Merge remote-tracking branch 'origin/master' into feat/paych-avail-reuse
This commit is contained in:
+112
@@ -1,7 +1,9 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
verifreg4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/verifreg"
|
||||
@@ -34,6 +36,7 @@ var filplusCmd = &cli.Command{
|
||||
filplusListClientsCmd,
|
||||
filplusCheckClientCmd,
|
||||
filplusCheckNotaryCmd,
|
||||
filplusSignRemoveDataCapProposal,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -274,3 +277,112 @@ func checkNotary(ctx context.Context, api v0api.FullNode, vaddr address.Address)
|
||||
|
||||
return st.VerifierDataCap(vid)
|
||||
}
|
||||
|
||||
var filplusSignRemoveDataCapProposal = &cli.Command{
|
||||
Name: "sign-remove-data-cap-proposal",
|
||||
Usage: "allows a notary to sign a Remove Data Cap Proposal",
|
||||
Flags: []cli.Flag{
|
||||
&cli.Int64Flag{
|
||||
Name: "id",
|
||||
Usage: "specify the RemoveDataCapProposal ID (will look up on chain if unspecified)",
|
||||
Required: false,
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.Args().Len() != 3 {
|
||||
return fmt.Errorf("must specify three arguments: notary address, client address, and allowance to remove")
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get full node api: %w", err)
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
act, err := api.StateGetActor(ctx, verifreg.Address, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get verifreg actor: %w", err)
|
||||
}
|
||||
|
||||
apibs := blockstore.NewAPIBlockstore(api)
|
||||
store := adt.WrapStore(ctx, cbor.NewCborStore(apibs))
|
||||
|
||||
st, err := verifreg.Load(store, act)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to load verified registry state: %w", err)
|
||||
}
|
||||
|
||||
verifier, err := address.NewFromString(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
verifierIdAddr, err := api.StateLookupID(ctx, verifier, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := address.NewFromString(cctx.Args().Get(1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clientIdAddr, err := api.StateLookupID(ctx, client, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
allowanceToRemove, err := types.BigFromString(cctx.Args().Get(2))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, dataCap, err := st.VerifiedClientDataCap(clientIdAddr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to find verified client data cap: %w", err)
|
||||
}
|
||||
if dataCap.LessThanEqual(big.Zero()) {
|
||||
return xerrors.Errorf("client data cap %s is less than amount requested to be removed %s", dataCap.String(), allowanceToRemove.String())
|
||||
}
|
||||
|
||||
found, _, err := checkNotary(ctx, api, verifier)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to check notary status: %w", err)
|
||||
}
|
||||
|
||||
if !found {
|
||||
return xerrors.New("verifier address must be a notary")
|
||||
}
|
||||
|
||||
id := cctx.Uint64("id")
|
||||
if id == 0 {
|
||||
_, id, err = st.RemoveDataCapProposalID(verifierIdAddr, clientIdAddr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed find remove data cap proposal id: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
params := verifreg.RemoveDataCapProposal{
|
||||
RemovalProposalID: verifreg.RmDcProposalID{ProposalID: id},
|
||||
DataCapAmount: allowanceToRemove,
|
||||
VerifiedClient: clientIdAddr,
|
||||
}
|
||||
|
||||
paramBuf := new(bytes.Buffer)
|
||||
paramBuf.WriteString(verifreg.SignatureDomainSeparation_RemoveDataCap)
|
||||
err = params.MarshalCBOR(paramBuf)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to marshall paramBuf: %w", err)
|
||||
}
|
||||
|
||||
sig, err := api.WalletSign(ctx, verifier, paramBuf.Bytes())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to sign message: %w", err)
|
||||
}
|
||||
|
||||
sigBytes := append([]byte{byte(sig.Type)}, sig.Data...)
|
||||
|
||||
fmt.Println(hex.EncodeToString(sigBytes))
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
+37
-24
@@ -60,6 +60,8 @@ var MpoolPending = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
afmt := NewAppFmt(cctx.App)
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -72,7 +74,7 @@ var MpoolPending = &cli.Command{
|
||||
if tos := cctx.String("to"); tos != "" {
|
||||
a, err := address.NewFromString(tos)
|
||||
if err != nil {
|
||||
return fmt.Errorf("given 'to' address %q was invalid: %w", tos, err)
|
||||
return xerrors.Errorf("given 'to' address %q was invalid: %w", tos, err)
|
||||
}
|
||||
toa = a
|
||||
}
|
||||
@@ -80,7 +82,7 @@ var MpoolPending = &cli.Command{
|
||||
if froms := cctx.String("from"); froms != "" {
|
||||
a, err := address.NewFromString(froms)
|
||||
if err != nil {
|
||||
return fmt.Errorf("given 'from' address %q was invalid: %w", froms, err)
|
||||
return xerrors.Errorf("given 'from' address %q was invalid: %w", froms, err)
|
||||
}
|
||||
froma = a
|
||||
}
|
||||
@@ -119,13 +121,13 @@ var MpoolPending = &cli.Command{
|
||||
}
|
||||
|
||||
if cctx.Bool("cids") {
|
||||
fmt.Println(msg.Cid())
|
||||
afmt.Println(msg.Cid())
|
||||
} else {
|
||||
out, err := json.MarshalIndent(msg, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
afmt.Println(string(out))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,6 +218,8 @@ var MpoolStat = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
afmt := NewAppFmt(cctx.App)
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -234,6 +238,7 @@ var MpoolStat = &cli.Command{
|
||||
currTs := ts
|
||||
for i := 0; i < cctx.Int("basefee-lookback"); i++ {
|
||||
currTs, err = api.ChainGetTipSet(ctx, currTs.Parents())
|
||||
|
||||
if err != nil {
|
||||
return xerrors.Errorf("walking chain: %w", err)
|
||||
}
|
||||
@@ -296,7 +301,7 @@ var MpoolStat = &cli.Command{
|
||||
for a, bkt := range buckets {
|
||||
act, err := api.StateGetActor(ctx, a, ts.Key())
|
||||
if err != nil {
|
||||
fmt.Printf("%s, err: %s\n", a, err)
|
||||
afmt.Printf("%s, err: %s\n", a, err)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -350,11 +355,11 @@ var MpoolStat = &cli.Command{
|
||||
total.belowPast += stat.belowPast
|
||||
total.gasLimit = big.Add(total.gasLimit, stat.gasLimit)
|
||||
|
||||
fmt.Printf("%s: Nonce past: %d, cur: %d, future: %d; FeeCap cur: %d, min-%d: %d, gasLimit: %s\n", stat.addr, stat.past, stat.cur, stat.future, stat.belowCurr, cctx.Int("basefee-lookback"), stat.belowPast, stat.gasLimit)
|
||||
afmt.Printf("%s: Nonce past: %d, cur: %d, future: %d; FeeCap cur: %d, min-%d: %d, gasLimit: %s\n", stat.addr, stat.past, stat.cur, stat.future, stat.belowCurr, cctx.Int("basefee-lookback"), stat.belowPast, stat.gasLimit)
|
||||
}
|
||||
|
||||
fmt.Println("-----")
|
||||
fmt.Printf("total: Nonce past: %d, cur: %d, future: %d; FeeCap cur: %d, min-%d: %d, gasLimit: %s\n", total.past, total.cur, total.future, total.belowCurr, cctx.Int("basefee-lookback"), total.belowPast, total.gasLimit)
|
||||
afmt.Println("-----")
|
||||
afmt.Printf("total: Nonce past: %d, cur: %d, future: %d; FeeCap cur: %d, min-%d: %d, gasLimit: %s\n", total.past, total.cur, total.future, total.belowCurr, cctx.Int("basefee-lookback"), total.belowPast, total.gasLimit)
|
||||
|
||||
return nil
|
||||
},
|
||||
@@ -385,8 +390,9 @@ var MpoolReplaceCmd = &cli.Command{
|
||||
Usage: "Spend up to X FIL for this message in units of FIL. Previously when flag was `max-fee` units were in attoFIL. Applicable for auto mode",
|
||||
},
|
||||
},
|
||||
ArgsUsage: "<from nonce> | <message-cid>",
|
||||
ArgsUsage: "<from> <nonce> | <message-cid>",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
afmt := NewAppFmt(cctx.App)
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
@@ -407,13 +413,14 @@ var MpoolReplaceCmd = &cli.Command{
|
||||
|
||||
msg, err := api.ChainGetMessage(ctx, mcid)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not find referenced message: %w", err)
|
||||
return xerrors.Errorf("could not find referenced message: %w", err)
|
||||
}
|
||||
|
||||
from = msg.From
|
||||
nonce = msg.Nonce
|
||||
case 2:
|
||||
f, err := address.NewFromString(cctx.Args().Get(0))
|
||||
arg0 := cctx.Args().Get(0)
|
||||
f, err := address.NewFromString(arg0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -448,7 +455,7 @@ var MpoolReplaceCmd = &cli.Command{
|
||||
}
|
||||
|
||||
if found == nil {
|
||||
return fmt.Errorf("no pending message found from %s with nonce %d", from, nonce)
|
||||
return xerrors.Errorf("no pending message found from %s with nonce %d", from, nonce)
|
||||
}
|
||||
|
||||
msg := found.Message
|
||||
@@ -460,7 +467,7 @@ var MpoolReplaceCmd = &cli.Command{
|
||||
if cctx.IsSet("fee-limit") {
|
||||
maxFee, err := types.ParseFIL(cctx.String("fee-limit"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing max-spend: %w", err)
|
||||
return xerrors.Errorf("parsing max-spend: %w", err)
|
||||
}
|
||||
mss = &lapi.MessageSendSpec{
|
||||
MaxFee: abi.TokenAmount(maxFee),
|
||||
@@ -472,7 +479,7 @@ var MpoolReplaceCmd = &cli.Command{
|
||||
msg.GasPremium = abi.NewTokenAmount(0)
|
||||
retm, err := api.GasEstimateMessageGas(ctx, &msg, mss, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to estimate gas values: %w", err)
|
||||
return xerrors.Errorf("failed to estimate gas values: %w", err)
|
||||
}
|
||||
|
||||
msg.GasPremium = big.Max(retm.GasPremium, minRBF)
|
||||
@@ -489,26 +496,26 @@ var MpoolReplaceCmd = &cli.Command{
|
||||
}
|
||||
msg.GasPremium, err = types.BigFromString(cctx.String("gas-premium"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing gas-premium: %w", err)
|
||||
return xerrors.Errorf("parsing gas-premium: %w", err)
|
||||
}
|
||||
// TODO: estimate fee cap here
|
||||
msg.GasFeeCap, err = types.BigFromString(cctx.String("gas-feecap"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing gas-feecap: %w", err)
|
||||
return xerrors.Errorf("parsing gas-feecap: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
smsg, err := api.WalletSignMessage(ctx, msg.From, &msg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to sign message: %w", err)
|
||||
return xerrors.Errorf("failed to sign message: %w", err)
|
||||
}
|
||||
|
||||
cid, err := api.MpoolPush(ctx, smsg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to push new message to mempool: %w", err)
|
||||
return xerrors.Errorf("failed to push new message to mempool: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println("new message cid: ", cid)
|
||||
afmt.Println("new message cid: ", cid)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -531,6 +538,8 @@ var MpoolFindCmd = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
afmt := NewAppFmt(cctx.App)
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -548,7 +557,7 @@ var MpoolFindCmd = &cli.Command{
|
||||
if cctx.IsSet("to") {
|
||||
a, err := address.NewFromString(cctx.String("to"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("'to' address was invalid: %w", err)
|
||||
return xerrors.Errorf("'to' address was invalid: %w", err)
|
||||
}
|
||||
|
||||
toFilter = a
|
||||
@@ -557,7 +566,7 @@ var MpoolFindCmd = &cli.Command{
|
||||
if cctx.IsSet("from") {
|
||||
a, err := address.NewFromString(cctx.String("from"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("'from' address was invalid: %w", err)
|
||||
return xerrors.Errorf("'from' address was invalid: %w", err)
|
||||
}
|
||||
|
||||
fromFilter = a
|
||||
@@ -591,7 +600,7 @@ var MpoolFindCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(string(b))
|
||||
afmt.Println(string(b))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -605,6 +614,8 @@ var MpoolConfig = &cli.Command{
|
||||
return cli.ShowCommandHelp(cctx, cctx.Command.Name)
|
||||
}
|
||||
|
||||
afmt := NewAppFmt(cctx.App)
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -624,7 +635,7 @@ var MpoolConfig = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(string(bytes))
|
||||
afmt.Println(string(bytes))
|
||||
} else {
|
||||
cfg := new(types.MpoolConfig)
|
||||
bytes := []byte(cctx.Args().Get(0))
|
||||
@@ -651,6 +662,8 @@ var MpoolGasPerfCmd = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
afmt := NewAppFmt(cctx.App)
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -717,7 +730,7 @@ var MpoolGasPerfCmd = &cli.Command{
|
||||
gasReward := getGasReward(m)
|
||||
gasPerf := getGasPerf(gasReward, m.Message.GasLimit)
|
||||
|
||||
fmt.Printf("%s\t%d\t%s\t%f\n", m.Message.From, m.Message.Nonce, gasReward, gasPerf)
|
||||
afmt.Printf("%s\t%d\t%s\t%f\n", m.Message.From, m.Message.Nonce, gasReward, gasPerf)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -0,0 +1,582 @@
|
||||
//stm: #cli
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"encoding/json"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStat(t *testing.T) {
|
||||
|
||||
t.Run("local", func(t *testing.T) {
|
||||
app, mockApi, buf, done := NewMockAppWithFullAPI(t, WithCategory("mpool", MpoolStat))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// add blocks to the chain
|
||||
first := mock.TipSet(mock.MkBlock(nil, 5, 4))
|
||||
head := mock.TipSet(mock.MkBlock(first, 15, 7))
|
||||
|
||||
// create a signed message to be returned as a pending message
|
||||
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
toAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sm := mock.MkMessage(senderAddr, toAddr, 1, w)
|
||||
|
||||
// mock actor to return for the sender
|
||||
actor := types.Actor{Nonce: 2, Balance: big.NewInt(200000)}
|
||||
|
||||
gomock.InOrder(
|
||||
mockApi.EXPECT().ChainHead(ctx).Return(head, nil),
|
||||
mockApi.EXPECT().ChainGetTipSet(ctx, head.Parents()).Return(first, nil),
|
||||
mockApi.EXPECT().WalletList(ctx).Return([]address.Address{senderAddr, toAddr}, nil),
|
||||
mockApi.EXPECT().MpoolPending(ctx, types.EmptyTSK).Return([]*types.SignedMessage{sm}, nil),
|
||||
mockApi.EXPECT().StateGetActor(ctx, senderAddr, head.Key()).Return(&actor, nil),
|
||||
)
|
||||
|
||||
//stm: @CLI_MEMPOOL_STAT_002
|
||||
err = app.Run([]string{"mpool", "stat", "--basefee-lookback", "1", "--local"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Contains(t, buf.String(), "Nonce past: 1")
|
||||
})
|
||||
|
||||
t.Run("all", func(t *testing.T) {
|
||||
app, mockApi, buf, done := NewMockAppWithFullAPI(t, WithCategory("mpool", MpoolStat))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// add blocks to the chain
|
||||
first := mock.TipSet(mock.MkBlock(nil, 5, 4))
|
||||
head := mock.TipSet(mock.MkBlock(first, 15, 7))
|
||||
|
||||
// create a signed message to be returned as a pending message
|
||||
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
toAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sm := mock.MkMessage(senderAddr, toAddr, 1, w)
|
||||
|
||||
// mock actor to return for the sender
|
||||
actor := types.Actor{Nonce: 2, Balance: big.NewInt(200000)}
|
||||
|
||||
gomock.InOrder(
|
||||
mockApi.EXPECT().ChainHead(ctx).Return(head, nil),
|
||||
mockApi.EXPECT().ChainGetTipSet(ctx, head.Parents()).Return(first, nil),
|
||||
mockApi.EXPECT().MpoolPending(ctx, types.EmptyTSK).Return([]*types.SignedMessage{sm}, nil),
|
||||
mockApi.EXPECT().StateGetActor(ctx, senderAddr, head.Key()).Return(&actor, nil),
|
||||
)
|
||||
|
||||
//stm: @CLI_MEMPOOL_STAT_001
|
||||
err = app.Run([]string{"mpool", "stat", "--basefee-lookback", "1"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Contains(t, buf.String(), "Nonce past: 1")
|
||||
})
|
||||
}
|
||||
|
||||
func TestPending(t *testing.T) {
|
||||
t.Run("all", func(t *testing.T) {
|
||||
|
||||
app, mockApi, buf, done := NewMockAppWithFullAPI(t, WithCategory("mpool", MpoolPending))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// create a signed message to be returned as a pending message
|
||||
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
toAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sm := mock.MkMessage(senderAddr, toAddr, 1, w)
|
||||
|
||||
gomock.InOrder(
|
||||
mockApi.EXPECT().MpoolPending(ctx, types.EmptyTSK).Return([]*types.SignedMessage{sm}, nil),
|
||||
)
|
||||
|
||||
//stm: @CLI_MEMPOOL_PENDING_001
|
||||
err = app.Run([]string{"mpool", "pending", "--cids"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Contains(t, buf.String(), sm.Cid().String())
|
||||
})
|
||||
|
||||
t.Run("local", func(t *testing.T) {
|
||||
|
||||
app, mockApi, buf, done := NewMockAppWithFullAPI(t, WithCategory("mpool", MpoolPending))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// create a signed message to be returned as a pending message
|
||||
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
toAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sm := mock.MkMessage(senderAddr, toAddr, 1, w)
|
||||
|
||||
gomock.InOrder(
|
||||
mockApi.EXPECT().WalletList(ctx).Return([]address.Address{senderAddr}, nil),
|
||||
mockApi.EXPECT().MpoolPending(ctx, types.EmptyTSK).Return([]*types.SignedMessage{sm}, nil),
|
||||
)
|
||||
|
||||
//stm: @CLI_MEMPOOL_PENDING_002
|
||||
err = app.Run([]string{"mpool", "pending", "--local"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Contains(t, buf.String(), sm.Cid().String())
|
||||
})
|
||||
|
||||
t.Run("to", func(t *testing.T) {
|
||||
|
||||
app, mockApi, buf, done := NewMockAppWithFullAPI(t, WithCategory("mpool", MpoolPending))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// create a signed message to be returned as a pending message
|
||||
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
toAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sm := mock.MkMessage(senderAddr, toAddr, 1, w)
|
||||
|
||||
gomock.InOrder(
|
||||
mockApi.EXPECT().MpoolPending(ctx, types.EmptyTSK).Return([]*types.SignedMessage{sm}, nil),
|
||||
)
|
||||
|
||||
//stm: @CLI_MEMPOOL_PENDING_003
|
||||
err = app.Run([]string{"mpool", "pending", "--to", sm.Message.To.String()})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Contains(t, buf.String(), sm.Cid().String())
|
||||
})
|
||||
|
||||
t.Run("from", func(t *testing.T) {
|
||||
|
||||
app, mockApi, buf, done := NewMockAppWithFullAPI(t, WithCategory("mpool", MpoolPending))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// create a signed message to be returned as a pending message
|
||||
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
toAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sm := mock.MkMessage(senderAddr, toAddr, 1, w)
|
||||
|
||||
gomock.InOrder(
|
||||
mockApi.EXPECT().MpoolPending(ctx, types.EmptyTSK).Return([]*types.SignedMessage{sm}, nil),
|
||||
)
|
||||
|
||||
//stm: @CLI_MEMPOOL_PENDING_004
|
||||
err = app.Run([]string{"mpool", "pending", "--from", sm.Message.From.String()})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Contains(t, buf.String(), sm.Cid().String())
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestReplace(t *testing.T) {
|
||||
t.Run("manual", func(t *testing.T) {
|
||||
app, mockApi, buf, done := NewMockAppWithFullAPI(t, WithCategory("mpool", MpoolReplaceCmd))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// create a signed message to be returned as a pending message
|
||||
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
toAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sm := mock.MkMessage(senderAddr, toAddr, 1, w)
|
||||
|
||||
gomock.InOrder(
|
||||
mockApi.EXPECT().ChainGetMessage(ctx, sm.Cid()).Return(&sm.Message, nil),
|
||||
mockApi.EXPECT().ChainHead(ctx).Return(nil, nil),
|
||||
mockApi.EXPECT().MpoolPending(ctx, types.EmptyTSK).Return([]*types.SignedMessage{sm}, nil),
|
||||
mockApi.EXPECT().WalletSignMessage(ctx, sm.Message.From, &sm.Message).Return(sm, nil),
|
||||
mockApi.EXPECT().MpoolPush(ctx, sm).Return(sm.Cid(), nil),
|
||||
)
|
||||
|
||||
//stm: @CLI_MEMPOOL_REPLACE_002
|
||||
err = app.Run([]string{"mpool", "replace", "--gas-premium", "1", "--gas-feecap", "100", sm.Cid().String()})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, buf.String(), sm.Cid().String())
|
||||
})
|
||||
|
||||
t.Run("auto", func(t *testing.T) {
|
||||
app, mockApi, buf, done := NewMockAppWithFullAPI(t, WithCategory("mpool", MpoolReplaceCmd))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// create a signed message to be returned as a pending message
|
||||
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
toAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sm := mock.MkMessage(senderAddr, toAddr, 1, w)
|
||||
|
||||
// gas fee param should be equal to the one passed in the cli invocation (used below)
|
||||
maxFee := "1000000"
|
||||
parsedFee, err := types.ParseFIL(maxFee)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mss := api.MessageSendSpec{MaxFee: abi.TokenAmount(parsedFee)}
|
||||
|
||||
gomock.InOrder(
|
||||
mockApi.EXPECT().ChainGetMessage(ctx, sm.Cid()).Return(&sm.Message, nil),
|
||||
mockApi.EXPECT().ChainHead(ctx).Return(nil, nil),
|
||||
mockApi.EXPECT().MpoolPending(ctx, types.EmptyTSK).Return([]*types.SignedMessage{sm}, nil),
|
||||
// use gomock.any to match the message in expected api calls
|
||||
// since the replace function modifies the message between calls, it would be pointless to try to match the exact argument
|
||||
mockApi.EXPECT().GasEstimateMessageGas(ctx, gomock.Any(), &mss, types.EmptyTSK).Return(&sm.Message, nil),
|
||||
mockApi.EXPECT().WalletSignMessage(ctx, sm.Message.From, gomock.Any()).Return(sm, nil),
|
||||
mockApi.EXPECT().MpoolPush(ctx, sm).Return(sm.Cid(), nil),
|
||||
)
|
||||
|
||||
//stm: @CLI_MEMPOOL_REPLACE_002
|
||||
err = app.Run([]string{"mpool", "replace", "--auto", "--fee-limit", maxFee, sm.Cid().String()})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, buf.String(), sm.Cid().String())
|
||||
})
|
||||
|
||||
t.Run("sender / nonce", func(t *testing.T) {
|
||||
app, mockApi, buf, done := NewMockAppWithFullAPI(t, WithCategory("mpool", MpoolReplaceCmd))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// create a signed message to be returned as a pending message
|
||||
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
toAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sm := mock.MkMessage(senderAddr, toAddr, 1, w)
|
||||
|
||||
// gas fee param should be equal to the one passed in the cli invocation (used below)
|
||||
maxFee := "1000000"
|
||||
parsedFee, err := types.ParseFIL(maxFee)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mss := api.MessageSendSpec{MaxFee: abi.TokenAmount(parsedFee)}
|
||||
|
||||
gomock.InOrder(
|
||||
mockApi.EXPECT().ChainHead(ctx).Return(nil, nil),
|
||||
mockApi.EXPECT().MpoolPending(ctx, types.EmptyTSK).Return([]*types.SignedMessage{sm}, nil),
|
||||
// use gomock.any to match the message in expected api calls
|
||||
// since the replace function modifies the message between calls, it would be pointless to try to match the exact argument
|
||||
mockApi.EXPECT().GasEstimateMessageGas(ctx, gomock.Any(), &mss, types.EmptyTSK).Return(&sm.Message, nil),
|
||||
mockApi.EXPECT().WalletSignMessage(ctx, sm.Message.From, gomock.Any()).Return(sm, nil),
|
||||
mockApi.EXPECT().MpoolPush(ctx, sm).Return(sm.Cid(), nil),
|
||||
)
|
||||
|
||||
//stm: @CLI_MEMPOOL_REPLACE_001
|
||||
err = app.Run([]string{"mpool", "replace", "--auto", "--fee-limit", maxFee, sm.Message.From.String(), fmt.Sprint(sm.Message.Nonce)})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, buf.String(), sm.Cid().String())
|
||||
})
|
||||
}
|
||||
|
||||
func TestFindMsg(t *testing.T) {
|
||||
t.Run("from", func(t *testing.T) {
|
||||
app, mockApi, buf, done := NewMockAppWithFullAPI(t, WithCategory("mpool", MpoolFindCmd))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// create a signed message to be returned as a pending message
|
||||
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
toAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sm := mock.MkMessage(senderAddr, toAddr, 1, w)
|
||||
|
||||
gomock.InOrder(
|
||||
mockApi.EXPECT().MpoolPending(ctx, types.EmptyTSK).Return([]*types.SignedMessage{sm}, nil),
|
||||
)
|
||||
|
||||
//stm: @CLI_MEMPOOL_FIND_001
|
||||
err = app.Run([]string{"mpool", "find", "--from", sm.Message.From.String()})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, buf.String(), sm.Cid().String())
|
||||
})
|
||||
|
||||
t.Run("to", func(t *testing.T) {
|
||||
app, mockApi, buf, done := NewMockAppWithFullAPI(t, WithCategory("mpool", MpoolFindCmd))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// create a signed message to be returned as a pending message
|
||||
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
toAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sm := mock.MkMessage(senderAddr, toAddr, 1, w)
|
||||
|
||||
gomock.InOrder(
|
||||
mockApi.EXPECT().MpoolPending(ctx, types.EmptyTSK).Return([]*types.SignedMessage{sm}, nil),
|
||||
)
|
||||
|
||||
//stm: @CLI_MEMPOOL_FIND_002
|
||||
err = app.Run([]string{"mpool", "find", "--to", sm.Message.To.String()})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, buf.String(), sm.Cid().String())
|
||||
})
|
||||
|
||||
t.Run("method", func(t *testing.T) {
|
||||
app, mockApi, buf, done := NewMockAppWithFullAPI(t, WithCategory("mpool", MpoolFindCmd))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// create a signed message to be returned as a pending message
|
||||
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
toAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sm := mock.MkMessage(senderAddr, toAddr, 1, w)
|
||||
|
||||
gomock.InOrder(
|
||||
mockApi.EXPECT().MpoolPending(ctx, types.EmptyTSK).Return([]*types.SignedMessage{sm}, nil),
|
||||
)
|
||||
|
||||
//stm: @CLI_MEMPOOL_FIND_003
|
||||
err = app.Run([]string{"mpool", "find", "--method", sm.Message.Method.String()})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, buf.String(), sm.Cid().String())
|
||||
})
|
||||
}
|
||||
|
||||
func TestGasPerf(t *testing.T) {
|
||||
t.Run("all", func(t *testing.T) {
|
||||
app, mockApi, buf, done := NewMockAppWithFullAPI(t, WithCategory("mpool", MpoolGasPerfCmd))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// add blocks to the chain
|
||||
first := mock.TipSet(mock.MkBlock(nil, 5, 4))
|
||||
head := mock.TipSet(mock.MkBlock(first, 15, 7))
|
||||
|
||||
// create a signed message to be returned as a pending message
|
||||
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
toAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sm := mock.MkMessage(senderAddr, toAddr, 13, w)
|
||||
|
||||
gomock.InOrder(
|
||||
mockApi.EXPECT().MpoolPending(ctx, types.EmptyTSK).Return([]*types.SignedMessage{sm}, nil),
|
||||
mockApi.EXPECT().ChainHead(ctx).Return(head, nil),
|
||||
)
|
||||
|
||||
//stm: @CLI_MEMPOOL_GAS_PERF_002
|
||||
err = app.Run([]string{"mpool", "gas-perf", "--all", "true"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Contains(t, buf.String(), sm.Message.From.String())
|
||||
assert.Contains(t, buf.String(), fmt.Sprint(sm.Message.Nonce))
|
||||
})
|
||||
|
||||
t.Run("local", func(t *testing.T) {
|
||||
app, mockApi, buf, done := NewMockAppWithFullAPI(t, WithCategory("mpool", MpoolGasPerfCmd))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// add blocks to the chain
|
||||
first := mock.TipSet(mock.MkBlock(nil, 5, 4))
|
||||
head := mock.TipSet(mock.MkBlock(first, 15, 7))
|
||||
|
||||
// create a signed message to be returned as a pending message
|
||||
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
toAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sm := mock.MkMessage(senderAddr, toAddr, 13, w)
|
||||
|
||||
gomock.InOrder(
|
||||
mockApi.EXPECT().MpoolPending(ctx, types.EmptyTSK).Return([]*types.SignedMessage{sm}, nil),
|
||||
mockApi.EXPECT().WalletList(ctx).Return([]address.Address{senderAddr}, nil),
|
||||
mockApi.EXPECT().ChainHead(ctx).Return(head, nil),
|
||||
)
|
||||
|
||||
//stm: @CLI_MEMPOOL_GAS_PERF_001
|
||||
err = app.Run([]string{"mpool", "gas-perf"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Contains(t, buf.String(), sm.Message.From.String())
|
||||
assert.Contains(t, buf.String(), fmt.Sprint(sm.Message.Nonce))
|
||||
})
|
||||
}
|
||||
|
||||
func TestConfig(t *testing.T) {
|
||||
t.Run("get", func(t *testing.T) {
|
||||
app, mockApi, buf, done := NewMockAppWithFullAPI(t, WithCategory("mpool", MpoolConfig))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mpoolCfg := &types.MpoolConfig{PriorityAddrs: []address.Address{senderAddr}, SizeLimitHigh: 1234567, SizeLimitLow: 6, ReplaceByFeeRatio: 0.25}
|
||||
gomock.InOrder(
|
||||
mockApi.EXPECT().MpoolGetConfig(ctx).Return(mpoolCfg, nil),
|
||||
)
|
||||
|
||||
//stm: @CLI_MEMPOOL_CONFIG_001
|
||||
err = app.Run([]string{"mpool", "config"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Contains(t, buf.String(), mpoolCfg.PriorityAddrs[0].String())
|
||||
assert.Contains(t, buf.String(), fmt.Sprint(mpoolCfg.SizeLimitHigh))
|
||||
assert.Contains(t, buf.String(), fmt.Sprint(mpoolCfg.SizeLimitLow))
|
||||
assert.Contains(t, buf.String(), fmt.Sprint(mpoolCfg.ReplaceByFeeRatio))
|
||||
})
|
||||
|
||||
t.Run("set", func(t *testing.T) {
|
||||
app, mockApi, _, done := NewMockAppWithFullAPI(t, WithCategory("mpool", MpoolConfig))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mpoolCfg := &types.MpoolConfig{PriorityAddrs: []address.Address{senderAddr}, SizeLimitHigh: 234567, SizeLimitLow: 3, ReplaceByFeeRatio: 0.33}
|
||||
gomock.InOrder(
|
||||
mockApi.EXPECT().MpoolSetConfig(ctx, mpoolCfg).Return(nil),
|
||||
)
|
||||
|
||||
bytes, err := json.Marshal(mpoolCfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
//stm: @CLI_MEMPOOL_CONFIG_002
|
||||
err = app.Run([]string{"mpool", "config", string(bytes)})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
+16
-12
@@ -33,6 +33,8 @@ var SyncStatusCmd = &cli.Command{
|
||||
Name: "status",
|
||||
Usage: "check sync status",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
afmt := NewAppFmt(cctx.App)
|
||||
|
||||
apic, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -45,9 +47,9 @@ var SyncStatusCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("sync status:")
|
||||
afmt.Println("sync status:")
|
||||
for _, ss := range state.ActiveSyncs {
|
||||
fmt.Printf("worker %d:\n", ss.WorkerID)
|
||||
afmt.Printf("worker %d:\n", ss.WorkerID)
|
||||
var base, target []cid.Cid
|
||||
var heightDiff int64
|
||||
var theight abi.ChainEpoch
|
||||
@@ -62,20 +64,20 @@ var SyncStatusCmd = &cli.Command{
|
||||
} else {
|
||||
heightDiff = 0
|
||||
}
|
||||
fmt.Printf("\tBase:\t%s\n", base)
|
||||
fmt.Printf("\tTarget:\t%s (%d)\n", target, theight)
|
||||
fmt.Printf("\tHeight diff:\t%d\n", heightDiff)
|
||||
fmt.Printf("\tStage: %s\n", ss.Stage)
|
||||
fmt.Printf("\tHeight: %d\n", ss.Height)
|
||||
afmt.Printf("\tBase:\t%s\n", base)
|
||||
afmt.Printf("\tTarget:\t%s (%d)\n", target, theight)
|
||||
afmt.Printf("\tHeight diff:\t%d\n", heightDiff)
|
||||
afmt.Printf("\tStage: %s\n", ss.Stage)
|
||||
afmt.Printf("\tHeight: %d\n", ss.Height)
|
||||
if ss.End.IsZero() {
|
||||
if !ss.Start.IsZero() {
|
||||
fmt.Printf("\tElapsed: %s\n", time.Since(ss.Start))
|
||||
afmt.Printf("\tElapsed: %s\n", time.Since(ss.Start))
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("\tElapsed: %s\n", ss.End.Sub(ss.Start))
|
||||
afmt.Printf("\tElapsed: %s\n", ss.End.Sub(ss.Start))
|
||||
}
|
||||
if ss.Stage == api.StageSyncErrored {
|
||||
fmt.Printf("\tError: %s\n", ss.Message)
|
||||
afmt.Printf("\tError: %s\n", ss.Message)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -168,6 +170,8 @@ var SyncCheckBadCmd = &cli.Command{
|
||||
Usage: "check if the given block was marked bad, and for what reason",
|
||||
ArgsUsage: "[blockCid]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
afmt := NewAppFmt(cctx.App)
|
||||
|
||||
napi, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -190,11 +194,11 @@ var SyncCheckBadCmd = &cli.Command{
|
||||
}
|
||||
|
||||
if reason == "" {
|
||||
fmt.Println("block was not marked as bad")
|
||||
afmt.Println("block was not marked as bad")
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Println(reason)
|
||||
afmt.Println(reason)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSyncStatus(t *testing.T) {
|
||||
app, mockApi, buf, done := NewMockAppWithFullAPI(t, WithCategory("sync", SyncStatusCmd))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
ts1 := mock.TipSet(mock.MkBlock(nil, 0, 0))
|
||||
ts2 := mock.TipSet(mock.MkBlock(ts1, 0, 0))
|
||||
|
||||
start := time.Now()
|
||||
end := start.Add(time.Minute)
|
||||
|
||||
state := &api.SyncState{
|
||||
ActiveSyncs: []api.ActiveSync{{
|
||||
WorkerID: 1,
|
||||
Base: ts1,
|
||||
Target: ts2,
|
||||
Stage: api.StageMessages,
|
||||
Height: abi.ChainEpoch(0),
|
||||
Start: start,
|
||||
End: end,
|
||||
Message: "whatever",
|
||||
}},
|
||||
VMApplied: 0,
|
||||
}
|
||||
|
||||
mockApi.EXPECT().SyncState(ctx).Return(state, nil)
|
||||
|
||||
//stm: @CLI_SYNC_STATUS_001
|
||||
err := app.Run([]string{"sync", "status"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
out := buf.String()
|
||||
|
||||
// output is plaintext, had to do string matching
|
||||
assert.Contains(t, out, fmt.Sprintf("Base:\t[%s]", ts1.Blocks()[0].Cid().String()))
|
||||
assert.Contains(t, out, fmt.Sprintf("Target:\t[%s]", ts2.Blocks()[0].Cid().String()))
|
||||
assert.Contains(t, out, "Height diff:\t1")
|
||||
assert.Contains(t, out, "Stage: message sync")
|
||||
assert.Contains(t, out, "Height: 0")
|
||||
assert.Contains(t, out, "Elapsed: 1m0s")
|
||||
}
|
||||
|
||||
func TestSyncMarkBad(t *testing.T) {
|
||||
app, mockApi, _, done := NewMockAppWithFullAPI(t, WithCategory("sync", SyncMarkBadCmd))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
blk := mock.MkBlock(nil, 0, 0)
|
||||
|
||||
mockApi.EXPECT().SyncMarkBad(ctx, blk.Cid()).Return(nil)
|
||||
|
||||
//stm: @CLI_SYNC_MARK_BAD_001
|
||||
err := app.Run([]string{"sync", "mark-bad", blk.Cid().String()})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSyncUnmarkBad(t *testing.T) {
|
||||
t.Run("one-block", func(t *testing.T) {
|
||||
app, mockApi, _, done := NewMockAppWithFullAPI(t, WithCategory("sync", SyncUnmarkBadCmd))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
blk := mock.MkBlock(nil, 0, 0)
|
||||
|
||||
mockApi.EXPECT().SyncUnmarkBad(ctx, blk.Cid()).Return(nil)
|
||||
|
||||
//stm: @CLI_SYNC_UNMARK_BAD_001
|
||||
err := app.Run([]string{"sync", "unmark-bad", blk.Cid().String()})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("all", func(t *testing.T) {
|
||||
app, mockApi, _, done := NewMockAppWithFullAPI(t, WithCategory("sync", SyncUnmarkBadCmd))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
mockApi.EXPECT().SyncUnmarkAllBad(ctx).Return(nil)
|
||||
|
||||
//stm: @CLI_SYNC_UNMARK_BAD_002
|
||||
err := app.Run([]string{"sync", "unmark-bad", "-all"})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSyncCheckBad(t *testing.T) {
|
||||
t.Run("not-bad", func(t *testing.T) {
|
||||
app, mockApi, buf, done := NewMockAppWithFullAPI(t, WithCategory("sync", SyncCheckBadCmd))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
blk := mock.MkBlock(nil, 0, 0)
|
||||
|
||||
mockApi.EXPECT().SyncCheckBad(ctx, blk.Cid()).Return("", nil)
|
||||
|
||||
//stm: @CLI_SYNC_CHECK_BAD_002
|
||||
err := app.Run([]string{"sync", "check-bad", blk.Cid().String()})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Contains(t, buf.String(), "block was not marked as bad")
|
||||
})
|
||||
|
||||
t.Run("bad", func(t *testing.T) {
|
||||
app, mockApi, buf, done := NewMockAppWithFullAPI(t, WithCategory("sync", SyncCheckBadCmd))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
blk := mock.MkBlock(nil, 0, 0)
|
||||
reason := "whatever"
|
||||
|
||||
mockApi.EXPECT().SyncCheckBad(ctx, blk.Cid()).Return(reason, nil)
|
||||
|
||||
//stm: @CLI_SYNC_CHECK_BAD_001
|
||||
err := app.Run([]string{"sync", "check-bad", blk.Cid().String()})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Contains(t, buf.String(), reason)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSyncCheckpoint(t *testing.T) {
|
||||
t.Run("tipset", func(t *testing.T) {
|
||||
app, mockApi, _, done := NewMockAppWithFullAPI(t, WithCategory("sync", SyncCheckpointCmd))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
blk := mock.MkBlock(nil, 0, 0)
|
||||
ts := mock.TipSet(blk)
|
||||
|
||||
gomock.InOrder(
|
||||
mockApi.EXPECT().ChainGetBlock(ctx, blk.Cid()).Return(blk, nil),
|
||||
mockApi.EXPECT().SyncCheckpoint(ctx, ts.Key()).Return(nil),
|
||||
)
|
||||
|
||||
//stm: @CLI_SYNC_CHECKPOINT_001
|
||||
err := app.Run([]string{"sync", "checkpoint", blk.Cid().String()})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("epoch", func(t *testing.T) {
|
||||
app, mockApi, _, done := NewMockAppWithFullAPI(t, WithCategory("sync", SyncCheckpointCmd))
|
||||
defer done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
epoch := abi.ChainEpoch(0)
|
||||
blk := mock.MkBlock(nil, 0, 0)
|
||||
ts := mock.TipSet(blk)
|
||||
|
||||
gomock.InOrder(
|
||||
mockApi.EXPECT().ChainGetTipSetByHeight(ctx, epoch, types.EmptyTSK).Return(ts, nil),
|
||||
mockApi.EXPECT().SyncCheckpoint(ctx, ts.Key()).Return(nil),
|
||||
)
|
||||
|
||||
//stm: @CLI_SYNC_CHECKPOINT_002
|
||||
err := app.Run([]string{"sync", "checkpoint", fmt.Sprintf("-epoch=%d", epoch)})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user