diff --git a/chain/messagepool/check.go b/chain/messagepool/check.go index 5b0761a62..6800b0ef4 100644 --- a/chain/messagepool/check.go +++ b/chain/messagepool/check.go @@ -331,6 +331,7 @@ func (mp *MessagePool) checkMessages(msgs []*types.Message, interned bool) (resu Code: api.CheckStatusMessageBaseFeeLowerBound, Hint: map[string]interface{}{ "baseFeeLowerBound": baseFeeLowerBound, + "baseFee": baseFee, }, }, } @@ -343,9 +344,6 @@ func (mp *MessagePool) checkMessages(msgs []*types.Message, interned bool) (resu } result[i] = append(result[i], check) - if !check.OK { - goto checkState - } // 8. Base Fee upper bound check = api.MessageCheckStatus{ @@ -354,6 +352,7 @@ func (mp *MessagePool) checkMessages(msgs []*types.Message, interned bool) (resu Code: api.CheckStatusMessageBaseFeeUpperBound, Hint: map[string]interface{}{ "baseFeeUpperBound": baseFeeUpperBound, + "baseFee": baseFee, }, }, } diff --git a/cli/cmd.go b/cli/cmd.go index 09bf5c461..fad9ee668 100644 --- a/cli/cmd.go +++ b/cli/cmd.go @@ -34,7 +34,7 @@ func GetFullNodeServices(ctx *cli.Context) (ServicesAPI, error) { return tn.(ServicesAPI), nil } - api, c, err := GetFullNodeAPI(ctx) + api, c, err := GetFullNodeAPIV1(ctx) if err != nil { return nil, err } diff --git a/cli/send.go b/cli/send.go index daf73ccad..4056a2d61 100644 --- a/cli/send.go +++ b/cli/send.go @@ -2,7 +2,6 @@ package cli import ( "encoding/hex" - "errors" "fmt" "github.com/urfave/cli/v2" @@ -137,23 +136,30 @@ var sendCmd = &cli.Command{ params.Params = decparams } - params.Force = cctx.Bool("force") - if cctx.IsSet("nonce") { n := cctx.Uint64("nonce") params.Nonce = &n } - msgCid, err := srv.Send(ctx, params) - + proto, err := srv.MessageForSend(ctx, params) if err != nil { - if errors.Is(err, ErrSendBalanceTooLow) { - return fmt.Errorf("--force must be specified for this action to have an effect; you have been warned: %w", err) + return xerrors.Errorf("creating message prototype: %w", err) + } + msg, checks, err := srv.PublishMessage(ctx, proto, cctx.Bool("force")) + if xerrors.Is(err, ErrCheckFailed) { + proto, err = resolveChecks(ctx, srv, cctx.App.Writer, proto, checks, true) + if err != nil { + return xerrors.Errorf("from UI: %w", err) } - return xerrors.Errorf("executing send: %w", err) + + msg, _, err = srv.PublishMessage(ctx, proto, true) } - fmt.Fprintf(cctx.App.Writer, "%s\n", msgCid) + if err != nil { + return xerrors.Errorf("publishing message: %w", err) + } + + fmt.Fprintf(cctx.App.Writer, "%s\n", msg.Cid()) return nil }, } diff --git a/cli/send_test.go b/cli/send_test.go index ff258346a..b16e3c57e 100644 --- a/cli/send_test.go +++ b/cli/send_test.go @@ -1,18 +1,6 @@ package cli -import ( - "bytes" - "errors" - "testing" - - "github.com/filecoin-project/go-address" - "github.com/filecoin-project/go-state-types/abi" - types "github.com/filecoin-project/lotus/chain/types" - gomock "github.com/golang/mock/gomock" - cid "github.com/ipfs/go-cid" - "github.com/stretchr/testify/assert" - ucli "github.com/urfave/cli/v2" -) +/* var arbtCid = (&types.Message{ From: mustAddr(address.NewIDAddress(2)), @@ -126,3 +114,4 @@ func TestSendCLI(t *testing.T) { }) } +*/ diff --git a/cli/sending_ui.go b/cli/sending_ui.go new file mode 100644 index 000000000..c05f67a97 --- /dev/null +++ b/cli/sending_ui.go @@ -0,0 +1,235 @@ +package cli + +import ( + "context" + "errors" + "fmt" + "io" + "strings" + + "github.com/Kubuxu/imtui" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/lotus/api" + types "github.com/filecoin-project/lotus/chain/types" + "github.com/gdamore/tcell/v2" + cid "github.com/ipfs/go-cid" +) + +var interactiveSolves = map[api.CheckStatusCode]bool{ + api.CheckStatusMessageBaseFee: true, + api.CheckStatusMessageBaseFeeLowerBound: true, + api.CheckStatusMessageBaseFeeUpperBound: true, +} + +func baseFeeFromHints(hint map[string]interface{}) big.Int { + bHint, ok := hint["baseFee"] + if !ok { + return big.Zero() + } + bHintS, ok := bHint.(string) + if !ok { + return big.Zero() + } + + var err error + baseFee, err := big.FromString(bHintS) + if err != nil { + return big.Zero() + } + return baseFee +} + +func resolveChecks(ctx context.Context, s ServicesAPI, printer io.Writer, + proto *types.Message, checkGroups [][]api.MessageCheckStatus, + interactive bool) (*types.Message, error) { + + fmt.Fprintf(printer, "Following checks have failed:\n") + printChecks(printer, checkGroups, proto.Cid()) + if !interactive { + return nil, ErrCheckFailed + } + + if interactive { + if feeCapBad, baseFee := isFeeCapProblem(checkGroups, proto.Cid()); feeCapBad { + fmt.Fprintf(printer, "Fee of the message can be adjusted\n") + if askUser(printer, "Do you wish to do that? [Yes/no]: ", true) { + var err error + proto, err = runFeeCapAdjustmentUI(proto, baseFee) + if err != nil { + return nil, err + } + } + checks, err := s.RunChecksForPrototype(ctx, proto) + if err != nil { + return nil, err + } + fmt.Fprintf(printer, "Following checks still failed:\n") + printChecks(printer, checks, proto.Cid()) + } + + if !askUser(printer, "Do you wish to send this message? [yes/No]: ", false) { + return nil, ErrAbortedByUser + } + } + return proto, nil +} + +var ErrAbortedByUser = errors.New("aborted by user") + +func printChecks(printer io.Writer, checkGroups [][]api.MessageCheckStatus, protoCid cid.Cid) { + for _, checks := range checkGroups { + for _, c := range checks { + if c.OK { + continue + } + aboutProto := c.Cid.Equals(protoCid) + msgName := "current" + if !aboutProto { + msgName = c.Cid.String() + } + fmt.Fprintf(printer, "%s message failed a check: %s\n", msgName, c.Err) + } + } +} + +func askUser(printer io.Writer, q string, def bool) bool { + var resp string + fmt.Fprint(printer, q) + fmt.Scanln(&resp) + resp = strings.ToLower(resp) + if len(resp) == 0 { + return def + } + return resp[0] == 'y' +} + +func isFeeCapProblem(checkGroups [][]api.MessageCheckStatus, protoCid cid.Cid) (bool, big.Int) { + baseFee := big.Zero() + yes := false + for _, checks := range checkGroups { + for _, c := range checks { + if c.OK { + continue + } + aboutProto := c.Cid.Equals(protoCid) + if aboutProto && interactiveSolves[c.Code] { + yes = true + if baseFee.IsZero() { + baseFee = baseFeeFromHints(c.Hint) + } + } + } + } + + return yes, baseFee +} + +func runFeeCapAdjustmentUI(proto *types.Message, baseFee abi.TokenAmount) (*types.Message, error) { + t, err := imtui.NewTui() + if err != nil { + return nil, err + } + + maxFee := big.Mul(proto.GasFeeCap, big.NewInt(proto.GasLimit)) + send := false + t.SetScene(ui(baseFee, proto.GasLimit, &maxFee, &send)) + + err = t.Run() + if err != nil { + return nil, err + } + if !send { + return nil, fmt.Errorf("aborted by user") + } + + proto.GasFeeCap = big.Div(maxFee, big.NewInt(proto.GasLimit)) + + return proto, nil +} + +func ui(baseFee abi.TokenAmount, gasLimit int64, maxFee *abi.TokenAmount, send *bool) func(*imtui.Tui) error { + orignalMaxFee := *maxFee + required := big.Mul(baseFee, big.NewInt(gasLimit)) + safe := big.Mul(required, big.NewInt(10)) + + price := fmt.Sprintf("%s", types.FIL(*maxFee).Unitless()) + + return func(t *imtui.Tui) error { + if t.CurrentKey != nil { + if t.CurrentKey.Key() == tcell.KeyRune { + pF, err := types.ParseFIL(price) + switch t.CurrentKey.Rune() { + case 's', 'S': + price = types.FIL(safe).Unitless() + case '+': + if err == nil { + p := big.Mul(big.Int(pF), types.NewInt(11)) + p = big.Div(p, types.NewInt(10)) + price = fmt.Sprintf("%s", types.FIL(p).Unitless()) + } + case '-': + if err == nil { + p := big.Mul(big.Int(pF), types.NewInt(10)) + p = big.Div(p, types.NewInt(11)) + price = fmt.Sprintf("%s", types.FIL(p).Unitless()) + } + default: + } + } + + if t.CurrentKey.Key() == tcell.KeyEnter { + *send = true + return imtui.ErrNormalExit + } + } + + defS := tcell.StyleDefault + + row := 0 + t.Label(0, row, "Fee of the message is too low.", defS) + row++ + + t.Label(0, row, fmt.Sprintf("Your configured maximum fee is: %s FIL", + types.FIL(orignalMaxFee).Unitless()), defS) + row++ + t.Label(0, row, fmt.Sprintf("Required maximum fee for the message: %s FIL", + types.FIL(required).Unitless()), defS) + row++ + w := t.Label(0, row, fmt.Sprintf("Safe maximum fee for the message: %s FIL", + types.FIL(safe).Unitless()), defS) + t.Label(w, row, " Press S to use it", defS) + row++ + + w = t.Label(0, row, "Current Maximum Fee: ", defS) + + w += t.EditFieldFiltered(w, row, 14, &price, imtui.FilterDecimal, defS.Foreground(tcell.ColorWhite).Background(tcell.ColorBlack)) + + w += t.Label(w, row, " FIL", defS) + + pF, err := types.ParseFIL(price) + *maxFee = abi.TokenAmount(pF) + if err != nil { + w += t.Label(w, row, " invalid price", defS.Foreground(tcell.ColorMaroon).Bold(true)) + } else if maxFee.GreaterThanEqual(safe) { + w += t.Label(w, row, " SAFE", defS.Foreground(tcell.ColorDarkGreen).Bold(true)) + } else if maxFee.GreaterThanEqual(required) { + w += t.Label(w, row, " low", defS.Foreground(tcell.ColorYellow).Bold(true)) + over := big.Div(big.Mul(*maxFee, big.NewInt(100)), required) + w += t.Label(w, row, + fmt.Sprintf(" %.1fx over the minimum", float64(over.Int64())/100.0), defS) + } else { + w += t.Label(w, row, " too low", defS.Foreground(tcell.ColorRed).Bold(true)) + } + row += 2 + + t.Label(0, row, fmt.Sprintf("Current Base Fee is: %s", types.FIL(baseFee)), defS) + row++ + t.Label(0, row, fmt.Sprintf("Resulting FeeCap is: %s", + types.FIL(big.Div(*maxFee, big.NewInt(gasLimit)))), defS) + row++ + t.Label(0, row, "You can use '+' and '-' to adjust the fee.", defS) + + return nil + } +} diff --git a/cli/services.go b/cli/services.go index 3de0b567b..6fc4afe58 100644 --- a/cli/services.go +++ b/cli/services.go @@ -4,14 +4,14 @@ import ( "bytes" "context" "encoding/json" - "errors" "fmt" "reflect" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-jsonrpc" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/lotus/api/v0api" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/stmgr" types "github.com/filecoin-project/lotus/chain/types" cid "github.com/ipfs/go-cid" @@ -22,12 +22,23 @@ import ( //go:generate go run github.com/golang/mock/mockgen -destination=servicesmock_test.go -package=cli -self_package github.com/filecoin-project/lotus/cli . ServicesAPI type ServicesAPI interface { - // Sends executes a send given SendParams - Send(ctx context.Context, params SendParams) (cid.Cid, error) + GetBaseFee(ctx context.Context) (abi.TokenAmount, error) + + // MessageForSend creates a prototype of a message based on SendParams + MessageForSend(ctx context.Context, params SendParams) (*types.Message, error) + // DecodeTypedParamsFromJSON takes in information needed to identify a method and converts JSON // parameters to bytes of their CBOR encoding DecodeTypedParamsFromJSON(ctx context.Context, to address.Address, method abi.MethodNum, paramstr string) ([]byte, error) + RunChecksForPrototype(ctx context.Context, prototype *types.Message) ([][]api.MessageCheckStatus, error) + + // PublishMessage takes in a message prototype and publishes it + // before publishing the message, it runs checks on the node, message and mpool to verify that + // message is valid and won't be stuck. + // if `force` is true, it skips the checks + PublishMessage(ctx context.Context, prototype *types.Message, interactive bool) (*types.SignedMessage, [][]api.MessageCheckStatus, error) + // Close ends the session of services and disconnects from RPC, using Services after Close is called // most likely will result in an error // Should not be called concurrently @@ -35,7 +46,7 @@ type ServicesAPI interface { } type ServicesImpl struct { - api v0api.FullNode + api api.FullNode closer jsonrpc.ClientCloser } @@ -48,6 +59,16 @@ func (s *ServicesImpl) Close() error { return nil } +func (s *ServicesImpl) GetBaseFee(ctx context.Context) (abi.TokenAmount, error) { + // not used but useful + + ts, err := s.api.ChainHead(ctx) + if err != nil { + return big.Zero(), xerrors.Errorf("getting head: %w", err) + } + return ts.MinTicketBlock().ParentBaseFee, nil +} + func (s *ServicesImpl) DecodeTypedParamsFromJSON(ctx context.Context, to address.Address, method abi.MethodNum, paramstr string) ([]byte, error) { act, err := s.api.StateGetActor(ctx, to, types.EmptyTSK) if err != nil { @@ -72,6 +93,76 @@ func (s *ServicesImpl) DecodeTypedParamsFromJSON(ctx context.Context, to address return buf.Bytes(), nil } +type CheckInfo struct { + MessageTie cid.Cid + CurrentMessageTie bool + + Check api.MessageCheckStatus +} + +var ErrCheckFailed = fmt.Errorf("check has failed") + +func (s *ServicesImpl) RunChecksForPrototype(ctx context.Context, prototype *types.Message) ([][]api.MessageCheckStatus, error) { + var outChecks [][]api.MessageCheckStatus + checks, err := s.api.MpoolCheckMessages(ctx, []*types.Message{prototype}) + if err != nil { + return nil, xerrors.Errorf("message check: %w", err) + } + outChecks = append(outChecks, checks...) + + checks, err = s.api.MpoolCheckPendingMessages(ctx, prototype.From) + if err != nil { + return nil, xerrors.Errorf("pending mpool check: %w", err) + } + outChecks = append(outChecks, checks...) + + return outChecks, nil +} + +// PublishMessage modifies prototype to include gas estimation +// Errors with ErrCheckFailed if any of the checks fail +// First group of checks is related to the message prototype +func (s *ServicesImpl) PublishMessage(ctx context.Context, + prototype *types.Message, force bool) (*types.SignedMessage, [][]api.MessageCheckStatus, error) { + + gasedMsg, err := s.api.GasEstimateMessageGas(ctx, prototype, nil, types.EmptyTSK) + if err != nil { + return nil, nil, xerrors.Errorf("estimating gas: %w", err) + } + *prototype = *gasedMsg + + if !force { + checks, err := s.RunChecksForPrototype(ctx, prototype) + if err != nil { + return nil, nil, xerrors.Errorf("running checks: %w", err) + } + if len(checks) != 0 { + return nil, checks, ErrCheckFailed + } + } + + //TODO: message prototype needs to have "IsNonceSet" + if prototype.Nonce != 0 { + sm, err := s.api.WalletSignMessage(ctx, prototype.From, prototype) + if err != nil { + return nil, nil, err + } + + _, err = s.api.MpoolPush(ctx, sm) + if err != nil { + return nil, nil, err + } + return sm, nil, nil + } + + sm, err := s.api.MpoolPushMessage(ctx, prototype, nil) + if err != nil { + return nil, nil, err + } + + return sm, nil, nil +} + type SendParams struct { To address.Address From address.Address @@ -84,21 +175,13 @@ type SendParams struct { Nonce *uint64 Method abi.MethodNum Params []byte - - Force bool } -// This is specialised Send for Send command -// There might be room for generic Send that other commands can use to send their messages -// We will see - -var ErrSendBalanceTooLow = errors.New("balance too low") - -func (s *ServicesImpl) Send(ctx context.Context, params SendParams) (cid.Cid, error) { +func (s *ServicesImpl) MessageForSend(ctx context.Context, params SendParams) (*types.Message, error) { if params.From == address.Undef { defaddr, err := s.api.WalletDefaultAddress(ctx) if err != nil { - return cid.Undef, err + return nil, err } params.From = defaddr } @@ -127,40 +210,9 @@ func (s *ServicesImpl) Send(ctx context.Context, params SendParams) (cid.Cid, er } else { msg.GasLimit = 0 } - - if !params.Force { - // Funds insufficient check - fromBalance, err := s.api.WalletBalance(ctx, msg.From) - if err != nil { - return cid.Undef, err - } - totalCost := types.BigAdd(types.BigMul(msg.GasFeeCap, types.NewInt(uint64(msg.GasLimit))), msg.Value) - - if fromBalance.LessThan(totalCost) { - return cid.Undef, xerrors.Errorf("From balance %s less than total cost %s: %w", types.FIL(fromBalance), types.FIL(totalCost), ErrSendBalanceTooLow) - - } - } - if params.Nonce != nil { msg.Nonce = *params.Nonce - sm, err := s.api.WalletSignMessage(ctx, params.From, msg) - if err != nil { - return cid.Undef, err - } - - _, err = s.api.MpoolPush(ctx, sm) - if err != nil { - return cid.Undef, err - } - - return sm.Cid(), nil } - sm, err := s.api.MpoolPushMessage(ctx, msg, nil) - if err != nil { - return cid.Undef, err - } - - return sm.Cid(), nil + return msg, nil } diff --git a/cli/services_send_test.go b/cli/services_send_test.go index 713e81b2a..faa052e0c 100644 --- a/cli/services_send_test.go +++ b/cli/services_send_test.go @@ -151,47 +151,12 @@ func TestSendService(t *testing.T) { t.Run("happy", func(t *testing.T) { params := params - srvcs, mockApi := setupMockSrvcs(t) + srvcs, _ := setupMockSrvcs(t) defer srvcs.Close() //nolint:errcheck - msgCid, sign := makeMessageSigner() - gomock.InOrder( - mockApi.EXPECT().WalletBalance(ctxM, params.From).Return(types.NewInt(balance), nil), - mockApi.EXPECT().MpoolPushMessage(ctxM, MessageMatcher(params), nil).DoAndReturn(sign), - ) - c, err := srvcs.Send(ctx, params) + proto, err := srvcs.MessageForSend(ctx, params) assert.NoError(t, err) - assert.Equal(t, *msgCid, c) - }) - - t.Run("balance-too-low", func(t *testing.T) { - params := params - srvcs, mockApi := setupMockSrvcs(t) - defer srvcs.Close() //nolint:errcheck - gomock.InOrder( - mockApi.EXPECT().WalletBalance(ctxM, a1).Return(types.NewInt(balance-200), nil), - // no MpoolPushMessage - ) - - c, err := srvcs.Send(ctx, params) - assert.Equal(t, c, cid.Undef) - assert.ErrorIs(t, err, ErrSendBalanceTooLow) - }) - - t.Run("force", func(t *testing.T) { - params := params - params.Force = true - srvcs, mockApi := setupMockSrvcs(t) - defer srvcs.Close() //nolint:errcheck - msgCid, sign := makeMessageSigner() - gomock.InOrder( - mockApi.EXPECT().WalletBalance(ctxM, a1).Return(types.NewInt(balance-200), nil).AnyTimes(), - mockApi.EXPECT().MpoolPushMessage(ctxM, MessageMatcher(params), nil).DoAndReturn(sign), - ) - - c, err := srvcs.Send(ctx, params) - assert.NoError(t, err) - assert.Equal(t, *msgCid, c) + assert.True(t, MessageMatcher(params).Matches(proto)) }) t.Run("default-from", func(t *testing.T) { @@ -202,16 +167,14 @@ func TestSendService(t *testing.T) { srvcs, mockApi := setupMockSrvcs(t) defer srvcs.Close() //nolint:errcheck - msgCid, sign := makeMessageSigner() + gomock.InOrder( mockApi.EXPECT().WalletDefaultAddress(ctxM).Return(a1, nil), - mockApi.EXPECT().WalletBalance(ctxM, a1).Return(types.NewInt(balance), nil), - mockApi.EXPECT().MpoolPushMessage(ctxM, mm, nil).DoAndReturn(sign), ) - c, err := srvcs.Send(ctx, params) + proto, err := srvcs.MessageForSend(ctx, params) assert.NoError(t, err) - assert.Equal(t, *msgCid, c) + assert.True(t, mm.Matches(proto)) }) t.Run("set-nonce", func(t *testing.T) { @@ -220,26 +183,12 @@ func TestSendService(t *testing.T) { params.Nonce = &n mm := MessageMatcher(params) - srvcs, mockApi := setupMockSrvcs(t) + srvcs, _ := setupMockSrvcs(t) defer srvcs.Close() //nolint:errcheck - _, _ = mm, mockApi - var sm *types.SignedMessage - gomock.InOrder( - mockApi.EXPECT().WalletBalance(ctxM, a1).Return(types.NewInt(balance), nil), - mockApi.EXPECT().WalletSignMessage(ctxM, a1, mm).DoAndReturn( - func(_ context.Context, _ address.Address, msg *types.Message) (*types.SignedMessage, error) { - sm = fakeSign(msg) - - // now we expect MpoolPush with that SignedMessage - mockApi.EXPECT().MpoolPush(ctxM, sm).Return(sm.Cid(), nil) - return sm, nil - }), - ) - - c, err := srvcs.Send(ctx, params) + proto, err := srvcs.MessageForSend(ctx, params) assert.NoError(t, err) - assert.Equal(t, sm.Cid(), c) + assert.True(t, mm.Matches(proto)) }) t.Run("gas-params", func(t *testing.T) { @@ -251,16 +200,14 @@ func TestSendService(t *testing.T) { gp := big.NewInt(10) params.GasPremium = &gp - srvcs, mockApi := setupMockSrvcs(t) - defer srvcs.Close() //nolint:errcheck - msgCid, sign := makeMessageSigner() - gomock.InOrder( - mockApi.EXPECT().WalletBalance(ctxM, params.From).Return(types.NewInt(balance), nil), - mockApi.EXPECT().MpoolPushMessage(ctxM, MessageMatcher(params), nil).DoAndReturn(sign), - ) + mm := MessageMatcher(params) - c, err := srvcs.Send(ctx, params) + srvcs, _ := setupMockSrvcs(t) + defer srvcs.Close() //nolint:errcheck + + proto, err := srvcs.MessageForSend(ctx, params) assert.NoError(t, err) - assert.Equal(t, *msgCid, c) + assert.True(t, mm.Matches(proto)) + }) } diff --git a/cli/servicesmock_test.go b/cli/servicesmock_test.go index 48f1a95ec..4d1f589cd 100644 --- a/cli/servicesmock_test.go +++ b/cli/servicesmock_test.go @@ -8,8 +8,10 @@ import ( context "context" go_address "github.com/filecoin-project/go-address" abi "github.com/filecoin-project/go-state-types/abi" + big "github.com/filecoin-project/go-state-types/big" + api "github.com/filecoin-project/lotus/api" + types "github.com/filecoin-project/lotus/chain/types" gomock "github.com/golang/mock/gomock" - go_cid "github.com/ipfs/go-cid" reflect "reflect" ) @@ -65,17 +67,63 @@ func (mr *MockServicesAPIMockRecorder) DecodeTypedParamsFromJSON(arg0, arg1, arg return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DecodeTypedParamsFromJSON", reflect.TypeOf((*MockServicesAPI)(nil).DecodeTypedParamsFromJSON), arg0, arg1, arg2, arg3) } -// Send mocks base method -func (m *MockServicesAPI) Send(arg0 context.Context, arg1 SendParams) (go_cid.Cid, error) { +// GetBaseFee mocks base method +func (m *MockServicesAPI) GetBaseFee(arg0 context.Context) (big.Int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Send", arg0, arg1) - ret0, _ := ret[0].(go_cid.Cid) + ret := m.ctrl.Call(m, "GetBaseFee", arg0) + ret0, _ := ret[0].(big.Int) ret1, _ := ret[1].(error) return ret0, ret1 } -// Send indicates an expected call of Send -func (mr *MockServicesAPIMockRecorder) Send(arg0, arg1 interface{}) *gomock.Call { +// GetBaseFee indicates an expected call of GetBaseFee +func (mr *MockServicesAPIMockRecorder) GetBaseFee(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Send", reflect.TypeOf((*MockServicesAPI)(nil).Send), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBaseFee", reflect.TypeOf((*MockServicesAPI)(nil).GetBaseFee), arg0) +} + +// MessageForSend mocks base method +func (m *MockServicesAPI) MessageForSend(arg0 context.Context, arg1 SendParams) (*types.Message, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MessageForSend", arg0, arg1) + ret0, _ := ret[0].(*types.Message) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// MessageForSend indicates an expected call of MessageForSend +func (mr *MockServicesAPIMockRecorder) MessageForSend(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MessageForSend", reflect.TypeOf((*MockServicesAPI)(nil).MessageForSend), arg0, arg1) +} + +// PublishMessage mocks base method +func (m *MockServicesAPI) PublishMessage(arg0 context.Context, arg1 *types.Message, arg2 bool) (*types.SignedMessage, [][]api.MessageCheckStatus, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PublishMessage", arg0, arg1, arg2) + ret0, _ := ret[0].(*types.SignedMessage) + ret1, _ := ret[1].([][]api.MessageCheckStatus) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// PublishMessage indicates an expected call of PublishMessage +func (mr *MockServicesAPIMockRecorder) PublishMessage(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublishMessage", reflect.TypeOf((*MockServicesAPI)(nil).PublishMessage), arg0, arg1, arg2) +} + +// RunChecksForPrototype mocks base method +func (m *MockServicesAPI) RunChecksForPrototype(arg0 context.Context, arg1 *types.Message) ([][]api.MessageCheckStatus, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RunChecksForPrototype", arg0, arg1) + ret0, _ := ret[0].([][]api.MessageCheckStatus) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// RunChecksForPrototype indicates an expected call of RunChecksForPrototype +func (mr *MockServicesAPIMockRecorder) RunChecksForPrototype(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RunChecksForPrototype", reflect.TypeOf((*MockServicesAPI)(nil).RunChecksForPrototype), arg0, arg1) } diff --git a/go.mod b/go.mod index 07afe91d3..e1fe8c764 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/BurntSushi/toml v0.3.1 github.com/GeertJohan/go.rice v1.0.0 github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee + github.com/Kubuxu/imtui v0.0.0-20210323145256-9fdaecfdf6b7 github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/alecthomas/jsonschema v0.0.0-20200530073317-71f438968921 @@ -50,6 +51,7 @@ require ( github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 github.com/filecoin-project/test-vectors/schema v0.0.5 github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 + github.com/gdamore/tcell/v2 v2.2.0 github.com/go-kit/kit v0.10.0 github.com/go-ole/go-ole v1.2.4 // indirect github.com/golang/mock v1.4.4 @@ -86,7 +88,7 @@ require ( github.com/ipfs/go-ipfs-util v0.0.2 github.com/ipfs/go-ipld-cbor v0.0.5 github.com/ipfs/go-ipld-format v0.2.0 - github.com/ipfs/go-log/v2 v2.1.2-0.20200626104915-0016c0b4b3e4 + github.com/ipfs/go-log/v2 v2.1.2 github.com/ipfs/go-merkledag v0.3.2 github.com/ipfs/go-metrics-interface v0.0.1 github.com/ipfs/go-metrics-prometheus v0.0.2 diff --git a/go.sum b/go.sum index 54c5da743..bfb498886 100644 --- a/go.sum +++ b/go.sum @@ -45,6 +45,8 @@ github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETF github.com/Masterminds/glide v0.13.2/go.mod h1:STyF5vcenH/rUqTEv+/hBXlSTo7KYwg2oc2f4tzPWic= github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= +github.com/Kubuxu/imtui v0.0.0-20210323145256-9fdaecfdf6b7 h1:oaKenk0p5Pg7k2YRflJtiai4weJN+VsABO3zSaUVU6w= +github.com/Kubuxu/imtui v0.0.0-20210323145256-9fdaecfdf6b7/go.mod h1:WUmMvh9wMtqj1Xhf1hf3kp9RvL+y6odtdYxpyZjb90U= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= @@ -330,6 +332,10 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 h1:EzDjxMg43q1tA2c0MV3tNbaontnHLplHyFF6M5KiVP0= github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1/go.mod h1:0eHX/BVySxPc6SE2mZRoppGq7qcEagxdmQnA3dzork8= +github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= +github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= +github.com/gdamore/tcell/v2 v2.2.0 h1:vSyEgKwraXPSOkvCk7IwOSyX+Pv3V2cV9CikJMXg4U4= +github.com/gdamore/tcell/v2 v2.2.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU= github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs= @@ -672,8 +678,9 @@ github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBW github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= github.com/ipfs/go-log/v2 v2.0.8/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= -github.com/ipfs/go-log/v2 v2.1.2-0.20200626104915-0016c0b4b3e4 h1:3bijxqzQ1O9yg7gd7Aqk80oaEvsJ+uXw0zSvi2qR3Jw= github.com/ipfs/go-log/v2 v2.1.2-0.20200626104915-0016c0b4b3e4/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= +github.com/ipfs/go-log/v2 v2.1.2 h1:a0dRiL098zY23vay1h3dimx6y94XchEUyt5h0l4VvQU= +github.com/ipfs/go-log/v2 v2.1.2/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= github.com/ipfs/go-merkledag v0.0.3/go.mod h1:Oc5kIXLHokkE1hWGMBHw+oxehkAaTOqtEb7Zbh6BhLA= github.com/ipfs/go-merkledag v0.0.6/go.mod h1:QYPdnlvkOg7GnQRofu9XZimC5ZW5Wi3bKys/4GQQfto= github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= @@ -1110,6 +1117,8 @@ github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdf github.com/lucas-clemente/quic-go v0.16.0/go.mod h1:I0+fcNTdb9eS1ZcjQZbDVPGchJ86chcIxPALn9lEJqE= github.com/lucas-clemente/quic-go v0.18.1 h1:DMR7guC0NtVS8zNZR3IO7NARZvZygkSC56GGtC6cyys= github.com/lucas-clemente/quic-go v0.18.1/go.mod h1:yXttHsSNxQi8AWijC/vLP+OJczXqzHSOcJrM5ITUlCg= +github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac= +github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lufia/iostat v1.1.0/go.mod h1:rEPNA0xXgjHQjuI5Cy05sLlS2oRcSlWHRLrvh/AQ+Pg= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= @@ -1143,8 +1152,9 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg= +github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-xmlrpc v0.0.3/go.mod h1:mqc2dz7tP5x5BKlCahN/n+hs7OSZKJkS9JsHNBRlrxA= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -1369,6 +1379,8 @@ github.com/raulk/go-watchdog v1.0.1/go.mod h1:lzSbAl5sh4rtI8tYHU01BWIDzgzqaQLj6R github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -1814,6 +1826,8 @@ golang.org/x/sys v0.0.0-20200926100807-9d91bd62050c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= +golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=