From 492fb9d054ace961e565d7ec9c2494753702cf9c Mon Sep 17 00:00:00 2001 From: TheMenko Date: Tue, 11 Jan 2022 02:16:53 +0100 Subject: [PATCH 01/57] wallet basic tests with annotations for system test matrix --- chain/wallet/multi_test.go | 74 +++++++++++++++++++++++++ chain/wallet/wallet_test.go | 105 ++++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 chain/wallet/multi_test.go create mode 100644 chain/wallet/wallet_test.go diff --git a/chain/wallet/multi_test.go b/chain/wallet/multi_test.go new file mode 100644 index 000000000..54ff240c5 --- /dev/null +++ b/chain/wallet/multi_test.go @@ -0,0 +1,74 @@ +//stm: #unit +package wallet + +import ( + "context" + "testing" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" +) + +func TestMultiWallet(t *testing.T) { + + ctx := context.Background() + + local, err := NewWallet(NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + var wallet api.Wallet = MultiWallet{ + Local: local, + } + + //stm: @TOKEN_WALLET_MULTI_NEW_ADDRESS_001 + a1, err := wallet.WalletNew(ctx, types.KTSecp256k1) + if err != nil { + t.Fatal(err) + } + + //stm: @TOKEN_WALLET_MULTI_HAS_001 + exists, err := wallet.WalletHas(ctx, a1) + if err != nil { + t.Fatal(err) + } + + if !exists { + t.Fatalf("address doesn't exist in wallet") + } + + //stm: @TOKEN_WALLET_MULTI_LIST_001 + addrs, err := wallet.WalletList(ctx) + if err != nil { + t.Fatal(err) + } + + // one default address and one newly created + if len(addrs) == 2 { + t.Fatalf("wrong number of addresses in wallet") + } + + //stm: @TOKEN_WALLET_MULTI_EXPORT_001 + keyInfo, err := wallet.WalletExport(ctx, a1) + if err != nil { + t.Fatal(err) + } + + //stm: @TOKEN_WALLET_MULTI_IMPORT_001 + addr, err := wallet.WalletImport(ctx, keyInfo) + if err != nil { + t.Fatal(err) + } + + //stm: @TOKEN_WALLET_DELETE_001 + err = wallet.WalletDelete(ctx, a1) + if err != nil { + t.Fatal(err) + } + + if addr != a1 { + t.Fatalf("imported address doesn't match exported address") + } + +} diff --git a/chain/wallet/wallet_test.go b/chain/wallet/wallet_test.go new file mode 100644 index 000000000..f07a6278c --- /dev/null +++ b/chain/wallet/wallet_test.go @@ -0,0 +1,105 @@ +//stm: #unit +package wallet + +import ( + "context" + "testing" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/stretchr/testify/assert" +) + +func TestWallet(t *testing.T) { + + ctx := context.Background() + + w1, err := NewWallet(NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + //stm: @TOKEN_WALLET_NEW_001 + a1, err := w1.WalletNew(ctx, types.KTSecp256k1) + if err != nil { + t.Fatal(err) + } + + //stm: @TOKEN_WALLET_HAS_001 + exists, err := w1.WalletHas(ctx, a1) + if err != nil { + t.Fatal(err) + } + + if !exists { + t.Fatalf("address doesn't exist in wallet") + } + + w2, err := NewWallet(NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + a2, err := w2.WalletNew(ctx, types.KTSecp256k1) + if err != nil { + t.Fatal(err) + } + + a3, err := w2.WalletNew(ctx, types.KTSecp256k1) + if err != nil { + t.Fatal(err) + } + + //stm: @TOKEN_WALLET_LIST_001 + addrs, err := w2.WalletList(ctx) + if err != nil { + t.Fatal(err) + } + + if len(addrs) != 2 { + t.Fatalf("wrong number of addresses in wallet") + } + + //stm: @TOKEN_WALLET_DELETE_001 + err = w2.WalletDelete(ctx, a2) + if err != nil { + t.Fatal(err) + } + + //stm: @TOKEN_WALLET_HAS_001 + exists, err = w2.WalletHas(ctx, a2) + if err != nil { + t.Fatal(err) + } + if exists { + t.Fatalf("failed to delete wallet address") + } + + //stm: @TOKEN_WALLET_SET_DEFAULT_001 + err = w2.SetDefault(a3) + if err != nil { + t.Fatal(err) + } + + //stm: @TOKEN_WALLET_DEFAULT_ADDRESS_001 + def, err := w2.GetDefault() + if !assert.Equal(t, a3, def) { + t.Fatal(err) + } + + //stm: @TOKEN_WALLET_EXPORT_001 + keyInfo, err := w2.WalletExport(ctx, a3) + if err != nil { + t.Fatal(err) + } + + //stm: @TOKEN_WALLET_IMPORT_001 + addr, err := w2.WalletImport(ctx, keyInfo) + if err != nil { + t.Fatal(err) + } + + if addr != a3 { + t.Fatalf("imported address doesn't match exported address") + } + +} From d9562e2aeef55eee06d439241b84ce59c4f4fbc4 Mon Sep 17 00:00:00 2001 From: Cory Schwartz Date: Fri, 14 Jan 2022 03:01:12 -0800 Subject: [PATCH 02/57] restore appiamge --- .circleci/config.yml | 21 ++++++++++++++++++++- .circleci/template.yml | 9 +++++++++ AppImageBuilder.yml | 10 +++++----- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 53611d565..f60cbdc6c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -390,7 +390,7 @@ jobs: build-appimage: machine: - image: ubuntu-2004:202104-01 + image: ubuntu-2004:202111-02 steps: - checkout - attach_workspace: @@ -398,6 +398,16 @@ jobs: - run: name: install appimage-builder command: | + # appimage-builder requires /dev/snd to exist. It creates containers during the testing phase + # that pass sound devices from the host to the testing container. (hard coded!) + # https://github.com/AppImageCrafters/appimage-builder/blob/master/appimagebuilder/modules/test/execution_test.py#L54 + # Circleci doesn't provide a working sound device; this is enough to fake it. + if [ ! -e /dev/snd ] + then + sudo mkdir /dev/snd + sudo mknod /dev/snd/ControlC0 c 1 2 + fi + # docs: https://appimage-builder.readthedocs.io/en/latest/intro/install.html sudo apt update sudo apt install -y python3-pip python3-setuptools patchelf desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace @@ -981,10 +991,19 @@ workflows: tags: only: - /^v\d+\.\d+\.\d+(-rc\d+)?$/ + - build-appimage: + filters: + branches: + ignore: + - /.*/ + tags: + only: + - /^v\d+\.\d+\.\d+(-rc\d+)?$/ - publish: requires: - build-all - build-macos + - build-appimage filters: branches: ignore: diff --git a/.circleci/template.yml b/.circleci/template.yml index ef6818c6d..72133b1cd 100644 --- a/.circleci/template.yml +++ b/.circleci/template.yml @@ -816,10 +816,19 @@ workflows: tags: only: - /^v\d+\.\d+\.\d+(-rc\d+)?$/ + - build-appimage: + filters: + branches: + ignore: + - /.*/ + tags: + only: + - /^v\d+\.\d+\.\d+(-rc\d+)?$/ - publish: requires: - build-all - build-macos + - build-appimage filters: branches: ignore: diff --git a/AppImageBuilder.yml b/AppImageBuilder.yml index 19c74e4a2..ff01b2112 100644 --- a/AppImageBuilder.yml +++ b/AppImageBuilder.yml @@ -49,23 +49,23 @@ AppDir: fedora: image: appimagecrafters/tests-env:fedora-30 command: ./AppRun - use_host_x: true + use_host_x: false debian: image: appimagecrafters/tests-env:debian-stable command: ./AppRun - use_host_x: true + use_host_x: false arch: image: appimagecrafters/tests-env:archlinux-latest command: ./AppRun - use_host_x: true + use_host_x: false centos: image: appimagecrafters/tests-env:centos-7 command: ./AppRun - use_host_x: true + use_host_x: false ubuntu: image: appimagecrafters/tests-env:ubuntu-xenial command: ./AppRun - use_host_x: true + use_host_x: false AppImage: arch: x86_64 update-information: guess From 899db1f7c3b8497f4948ce52f871453295edabce Mon Sep 17 00:00:00 2001 From: Cory Schwartz Date: Fri, 14 Jan 2022 03:07:20 -0800 Subject: [PATCH 03/57] fix template --- .circleci/template.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.circleci/template.yml b/.circleci/template.yml index 72133b1cd..c091c7b42 100644 --- a/.circleci/template.yml +++ b/.circleci/template.yml @@ -390,7 +390,7 @@ jobs: build-appimage: machine: - image: ubuntu-2004:202104-01 + image: ubuntu-2004:202111-02 steps: - checkout - attach_workspace: @@ -398,6 +398,16 @@ jobs: - run: name: install appimage-builder command: | + # appimage-builder requires /dev/snd to exist. It creates containers during the testing phase + # that pass sound devices from the host to the testing container. (hard coded!) + # https://github.com/AppImageCrafters/appimage-builder/blob/master/appimagebuilder/modules/test/execution_test.py#L54 + # Circleci doesn't provide a working sound device; this is enough to fake it. + if [ ! -e /dev/snd ] + then + sudo mkdir /dev/snd + sudo mknod /dev/snd/ControlC0 c 1 2 + fi + # docs: https://appimage-builder.readthedocs.io/en/latest/intro/install.html sudo apt update sudo apt install -y python3-pip python3-setuptools patchelf desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace From ae66f57fa08ba044eeee6db6a6f27a09f4011ec9 Mon Sep 17 00:00:00 2001 From: Nikola Divic Date: Fri, 11 Feb 2022 00:46:59 +0100 Subject: [PATCH 04/57] test: chain syncer & sync manager Added a few tests for some uncovered methods of the syncer and sync manager. Deleted some dead code (sync.go:getLatestBeaconEntry). --- chain/sync.go | 22 ------ chain/sync_manager_test.go | 33 ++++++++ chain/sync_test.go | 150 +++++++++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+), 22 deletions(-) diff --git a/chain/sync.go b/chain/sync.go index 0293ae25e..a34a83d76 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -1244,25 +1244,3 @@ func (syncer *Syncer) CheckBadBlockCache(blk cid.Cid) (string, bool) { bbr, ok := syncer.bad.Has(blk) return bbr.String(), ok } - -func (syncer *Syncer) getLatestBeaconEntry(ctx context.Context, ts *types.TipSet) (*types.BeaconEntry, error) { - cur := ts - for i := 0; i < 20; i++ { - cbe := cur.Blocks()[0].BeaconEntries - if len(cbe) > 0 { - return &cbe[len(cbe)-1], nil - } - - if cur.Height() == 0 { - return nil, xerrors.Errorf("made it back to genesis block without finding beacon entry") - } - - next, err := syncer.store.LoadTipSet(ctx, cur.Parents()) - if err != nil { - return nil, xerrors.Errorf("failed to load parents when searching back for latest beacon entry: %w", err) - } - cur = next - } - - return nil, xerrors.Errorf("found NO beacon entries in the 20 latest tipsets") -} diff --git a/chain/sync_manager_test.go b/chain/sync_manager_test.go index 5f23e67c0..bb0bbe1f5 100644 --- a/chain/sync_manager_test.go +++ b/chain/sync_manager_test.go @@ -8,6 +8,7 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types/mock" + "github.com/stretchr/testify/require" ) func init() { @@ -240,3 +241,35 @@ func TestSyncManager(t *testing.T) { op3.done() }) } + +func TestSyncManagerBucketSet(t *testing.T) { + ts1 := mock.TipSet(mock.MkBlock(nil, 0, 0)) + ts2 := mock.TipSet(mock.MkBlock(ts1, 1, 0)) + bucket1 := newSyncTargetBucket(ts1, ts2) + bucketSet := syncBucketSet{buckets: []*syncTargetBucket{bucket1}} + fmt.Println("bucketSet: ", bucketSet.String()) + + // inserting a tipset from an existing chain, should add to an existing bucket + ts3 := mock.TipSet(mock.MkBlock(ts2, 2, 0)) + bucketSet.Insert(ts3) + require.Equal(t, 1, len(bucketSet.buckets)) + require.Equal(t, 3, len(bucketSet.buckets[0].tips)) + fmt.Println("bucketSet: ", bucketSet.String()) + + // inserting a tipset from new chain, should create a new bucket + ts4fork := mock.TipSet(mock.MkBlock(nil, 1, 1)) + bucketSet.Insert(ts4fork) + require.Equal(t, 2, len(bucketSet.buckets)) + require.Equal(t, 3, len(bucketSet.buckets[0].tips)) + require.Equal(t, 1, len(bucketSet.buckets[1].tips)) + fmt.Println("bucketSet: ", bucketSet.String()) + + // Pop removes the best bucket, e.g. bucket1 + popped := bucketSet.Pop() + require.Equal(t, popped, bucket1) + require.Equal(t, 1, len(bucketSet.buckets)) + + // PopRelated removes the bucket containing the given tipset, leaving the set empty + bucketSet.PopRelated(ts4fork) + require.Equal(t, 0, len(bucketSet.buckets)) +} diff --git a/chain/sync_test.go b/chain/sync_test.go index 35566169f..2bc49dbec 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -1098,3 +1098,153 @@ func TestInvalidHeight(t *testing.T) { tu.mineOnBlock(base, 0, nil, false, true, nil, -1, true) } + +// TestIncomingBlocks mines new blocks and checks if the incoming channel streams new block headers properly +func TestIncomingBlocks(t *testing.T) { + H := 50 + tu := prepSyncTest(t, H) + + client := tu.addClientNode() + require.NoError(t, tu.mn.LinkAll()) + + clientNode := tu.nds[client] + incoming, err := clientNode.SyncIncomingBlocks(tu.ctx) + require.NoError(tu.t, err) + + tu.connect(client, 0) + tu.waitUntilSync(0, client) + tu.compareSourceState(client) + + timeout := time.After(10 * time.Second) + + for i := 0; i < 5; i++ { + tu.mineNewBlock(0, nil) + tu.waitUntilSync(0, client) + tu.compareSourceState(client) + + // just in case, so we don't get deadlocked + select { + case <-incoming: + case <-timeout: + tu.t.Fatal("TestIncomingBlocks timeout") + } + } +} + +// TestSyncManualBadTS tests manually marking and unmarking blocks in the bad TS cache +func TestSyncManualBadTS(t *testing.T) { + // Test setup: + // - source node is fully synced, + // - client node is unsynced + // - client manually marked source's head and it's parent as bad + H := 50 + tu := prepSyncTest(t, H) + + client := tu.addClientNode() + require.NoError(t, tu.mn.LinkAll()) + + sourceHead, err := tu.nds[source].ChainHead(tu.ctx) + require.NoError(tu.t, err) + + clientHead, err := tu.nds[client].ChainHead(tu.ctx) + require.NoError(tu.t, err) + + require.True(tu.t, !sourceHead.Equals(clientHead), "source and client should be out of sync in test setup") + + err = tu.nds[client].SyncMarkBad(tu.ctx, sourceHead.Cids()[0]) + require.NoError(tu.t, err) + + sourceHeadParent := sourceHead.Parents().Cids()[0] + err = tu.nds[client].SyncMarkBad(tu.ctx, sourceHeadParent) + require.NoError(tu.t, err) + + reason, err := tu.nds[client].SyncCheckBad(tu.ctx, sourceHead.Cids()[0]) + require.NoError(tu.t, err) + require.NotEqual(tu.t, "", reason, "block is not bad after manually marking") + + reason, err = tu.nds[client].SyncCheckBad(tu.ctx, sourceHeadParent) + require.NoError(tu.t, err) + require.NotEqual(tu.t, "", reason, "block is not bad after manually marking") + + // Assertion 1: + // - client shouldn't be synced after timeout, because the source TS is marked bad. + // - bad block is the first block that should be synced, 1sec should be enough + tu.connect(1, 0) + timeout := time.After(1 * time.Second) + <-timeout + + clientHead, err = tu.nds[client].ChainHead(tu.ctx) + require.NoError(tu.t, err) + require.True(tu.t, !sourceHead.Equals(clientHead), "source and client should be out of sync if source head is bad") + + // Assertion 2: + // - after unmarking blocks as bad and reconnecting, source & client should be in sync + err = tu.nds[client].SyncUnmarkBad(tu.ctx, sourceHead.Cids()[0]) + require.NoError(tu.t, err) + + reason, err = tu.nds[client].SyncCheckBad(tu.ctx, sourceHead.Cids()[0]) + require.NoError(tu.t, err) + require.Equal(tu.t, "", reason, "block is still bad after manually unmarking") + + err = tu.nds[client].SyncUnmarkAllBad(tu.ctx) + require.NoError(tu.t, err) + + reason, err = tu.nds[client].SyncCheckBad(tu.ctx, sourceHeadParent) + require.NoError(tu.t, err) + require.Equal(tu.t, "", reason, "block is still bad after manually unmarking") + + tu.disconnect(1, 0) + tu.connect(1, 0) + + tu.waitUntilSync(0, client) + tu.compareSourceState(client) +} + +// TestState tests fetching the sync worker state before, during & after the sync +func TestSyncState(t *testing.T) { + H := 50 + tu := prepSyncTest(t, H) + + client := tu.addClientNode() + require.NoError(t, tu.mn.LinkAll()) + clientNode := tu.nds[client] + sourceHead, err := tu.nds[source].ChainHead(tu.ctx) + require.NoError(tu.t, err) + + // sync state should be empty before the sync + state, err := clientNode.SyncState(tu.ctx) + require.NoError(tu.t, err) + require.Equal(tu.t, len(state.ActiveSyncs), 0) + + tu.connect(client, 0) + + // wait until sync starts, or at most `timeout` seconds + timeout := time.After(5 * time.Second) + activeSyncs := []api.ActiveSync{} + + for len(activeSyncs) == 0 { + state, err = clientNode.SyncState(tu.ctx) + require.NoError(tu.t, err) + activeSyncs = state.ActiveSyncs + + sleep := time.After(100 * time.Millisecond) + select { + case <-sleep: + case <-timeout: + tu.t.Fatal("TestSyncState timeout") + } + } + + // check state during sync + require.Equal(tu.t, len(activeSyncs), 1) + require.True(tu.t, activeSyncs[0].Target.Equals(sourceHead)) + + tu.waitUntilSync(0, client) + tu.compareSourceState(client) + + // check state after sync + state, err = clientNode.SyncState(tu.ctx) + require.NoError(tu.t, err) + require.Equal(tu.t, len(state.ActiveSyncs), 1) + require.Equal(tu.t, state.ActiveSyncs[0].Stage, api.StageSyncComplete) +} From 34bfd13548f84ed90900518ac12792dd048f44c2 Mon Sep 17 00:00:00 2001 From: Nikola Divic Date: Fri, 11 Feb 2022 15:06:06 +0100 Subject: [PATCH 05/57] doc: add stm annotations to the syncer tests Add annotations for the test crawler for the lotus.systemtestmatrix.com dashboard. --- chain/sync_manager_test.go | 6 ++++-- chain/sync_test.go | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/chain/sync_manager_test.go b/chain/sync_manager_test.go index bb0bbe1f5..d91ab1788 100644 --- a/chain/sync_manager_test.go +++ b/chain/sync_manager_test.go @@ -249,7 +249,8 @@ func TestSyncManagerBucketSet(t *testing.T) { bucketSet := syncBucketSet{buckets: []*syncTargetBucket{bucket1}} fmt.Println("bucketSet: ", bucketSet.String()) - // inserting a tipset from an existing chain, should add to an existing bucket + // inserting a tipset (potential sync target) from an existing chain, should add to an existing bucket + //stm: @CHAIN_SYNCER_ADD_SYNC_TARGET_001 ts3 := mock.TipSet(mock.MkBlock(ts2, 2, 0)) bucketSet.Insert(ts3) require.Equal(t, 1, len(bucketSet.buckets)) @@ -264,7 +265,8 @@ func TestSyncManagerBucketSet(t *testing.T) { require.Equal(t, 1, len(bucketSet.buckets[1].tips)) fmt.Println("bucketSet: ", bucketSet.String()) - // Pop removes the best bucket, e.g. bucket1 + // Pop removes the best bucket (best sync target), e.g. bucket1 + //stm: @CHAIN_SYNCER_SELECT_SYNC_TARGET_001 popped := bucketSet.Pop() require.Equal(t, popped, bucket1) require.Equal(t, 1, len(bucketSet.buckets)) diff --git a/chain/sync_test.go b/chain/sync_test.go index 2bc49dbec..96ed1440e 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -1108,6 +1108,7 @@ func TestIncomingBlocks(t *testing.T) { require.NoError(t, tu.mn.LinkAll()) clientNode := tu.nds[client] + //stm: @CHAIN_SYNCER_INCOMING_BLOCKS_001 incoming, err := clientNode.SyncIncomingBlocks(tu.ctx) require.NoError(tu.t, err) @@ -1151,6 +1152,7 @@ func TestSyncManualBadTS(t *testing.T) { require.True(tu.t, !sourceHead.Equals(clientHead), "source and client should be out of sync in test setup") + //stm: @CHAIN_SYNCER_MARK_BAD_001 err = tu.nds[client].SyncMarkBad(tu.ctx, sourceHead.Cids()[0]) require.NoError(tu.t, err) @@ -1158,6 +1160,7 @@ func TestSyncManualBadTS(t *testing.T) { err = tu.nds[client].SyncMarkBad(tu.ctx, sourceHeadParent) require.NoError(tu.t, err) + //stm: @CHAIN_SYNCER_CHECK_BAD_001 reason, err := tu.nds[client].SyncCheckBad(tu.ctx, sourceHead.Cids()[0]) require.NoError(tu.t, err) require.NotEqual(tu.t, "", reason, "block is not bad after manually marking") @@ -1179,6 +1182,7 @@ func TestSyncManualBadTS(t *testing.T) { // Assertion 2: // - after unmarking blocks as bad and reconnecting, source & client should be in sync + //stm: @CHAIN_SYNCER_UNMARK_BAD_001 err = tu.nds[client].SyncUnmarkBad(tu.ctx, sourceHead.Cids()[0]) require.NoError(tu.t, err) @@ -1223,6 +1227,7 @@ func TestSyncState(t *testing.T) { activeSyncs := []api.ActiveSync{} for len(activeSyncs) == 0 { + //stm: @CHAIN_SYNCER_STATE_001 state, err = clientNode.SyncState(tu.ctx) require.NoError(tu.t, err) activeSyncs = state.ActiveSyncs From ec0607900da136a481f64f72aabd4c2f5d17beee Mon Sep 17 00:00:00 2001 From: Nikola Divic Date: Fri, 11 Feb 2022 17:45:19 +0100 Subject: [PATCH 06/57] test: sync state cli command --- cli/sync.go | 22 ++++++++++--------- cli/sync_test.go | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 cli/sync_test.go diff --git a/cli/sync.go b/cli/sync.go index c7b010111..a486046bb 100644 --- a/cli/sync.go +++ b/cli/sync.go @@ -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 diff --git a/cli/sync_test.go b/cli/sync_test.go new file mode 100644 index 000000000..5c5961782 --- /dev/null +++ b/cli/sync_test.go @@ -0,0 +1,56 @@ +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/mock" + "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) + + 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") +} From 7fc2f9dc296083a02942b312349bb70a2964ced1 Mon Sep 17 00:00:00 2001 From: Nikola Divic Date: Fri, 11 Feb 2022 17:54:53 +0100 Subject: [PATCH 07/57] test: sync mark-bad cli command --- cli/sync_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/cli/sync_test.go b/cli/sync_test.go index 5c5961782..50be068f0 100644 --- a/cli/sync_test.go +++ b/cli/sync_test.go @@ -54,3 +54,18 @@ func TestSyncStatus(t *testing.T) { 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) + + err := app.Run([]string{"sync", "mark-bad", blk.Cid().String()}) + assert.NoError(t, err) +} From 0f79a0024c6f5f83dca4d1c7fa1e845a27c7d495 Mon Sep 17 00:00:00 2001 From: Nikola Divic Date: Fri, 11 Feb 2022 18:00:01 +0100 Subject: [PATCH 08/57] test: sync unmark-bad cli command --- cli/sync_test.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/cli/sync_test.go b/cli/sync_test.go index 50be068f0..7612d5da9 100644 --- a/cli/sync_test.go +++ b/cli/sync_test.go @@ -69,3 +69,33 @@ func TestSyncMarkBad(t *testing.T) { 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) + + 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) + + err := app.Run([]string{"sync", "unmark-bad", "-all"}) + assert.NoError(t, err) + }) +} From 05c8635749e53eb5591dce54cf895f9c2a4bcf51 Mon Sep 17 00:00:00 2001 From: Nikola Divic Date: Fri, 11 Feb 2022 18:08:36 +0100 Subject: [PATCH 09/57] test: sync check-bad cli command --- cli/sync.go | 6 ++++-- cli/sync_test.go | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/cli/sync.go b/cli/sync.go index a486046bb..0c4984379 100644 --- a/cli/sync.go +++ b/cli/sync.go @@ -170,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 @@ -192,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 }, } diff --git a/cli/sync_test.go b/cli/sync_test.go index 7612d5da9..85b05fa5c 100644 --- a/cli/sync_test.go +++ b/cli/sync_test.go @@ -99,3 +99,40 @@ func TestSyncUnmarkBad(t *testing.T) { 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) + + 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) + + err := app.Run([]string{"sync", "check-bad", blk.Cid().String()}) + assert.NoError(t, err) + + assert.Contains(t, buf.String(), reason) + }) +} From 94374aa93d4ef3fb6174e6d6422352599dccc894 Mon Sep 17 00:00:00 2001 From: Nikola Divic Date: Fri, 11 Feb 2022 18:30:07 +0100 Subject: [PATCH 10/57] test: sync checkpoint cli command --- cli/sync_test.go | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/cli/sync_test.go b/cli/sync_test.go index 85b05fa5c..174279d08 100644 --- a/cli/sync_test.go +++ b/cli/sync_test.go @@ -8,7 +8,9 @@ import ( "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" ) @@ -136,3 +138,44 @@ func TestSyncCheckBad(t *testing.T) { 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), + ) + + 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), + ) + + err := app.Run([]string{"sync", "checkpoint", fmt.Sprintf("-epoch=%d", epoch)}) + assert.NoError(t, err) + }) +} From baee4a157638c2f6ae804392e76297aae3a5d767 Mon Sep 17 00:00:00 2001 From: Nikola Divic Date: Fri, 11 Feb 2022 21:56:28 +0100 Subject: [PATCH 11/57] test: (kinda) fix flaky test deals_retry_deal_no_funds_test.go:TestDealsRetryLackOfFunds seems to be flaky, sometimes it passes and sometimes it doesn't. The first suspect for me was time.Sleep(), which I replaced with waiting until a deal state where you can restart is reached. --- itests/deals_retry_deal_no_funds_test.go | 3 +-- itests/kit/deals.go | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/itests/deals_retry_deal_no_funds_test.go b/itests/deals_retry_deal_no_funds_test.go index a14a0d085..ce8cd9729 100644 --- a/itests/deals_retry_deal_no_funds_test.go +++ b/itests/deals_retry_deal_no_funds_test.go @@ -95,12 +95,11 @@ func TestDealsRetryLackOfFunds(t *testing.T) { dp.FastRetrieval = true dp.EpochPrice = abi.NewTokenAmount(62500000) // minimum asking price. deal := dh.StartDeal(ctx, dp) + dh.WaitUntilDataTransfer(ctx, deal) propcid := *deal go func() { - time.Sleep(3 * time.Second) - kit.SendFunds(ctx, t, minerFullNode, publishStorageDealKey.Address, types.FromFil(1)) err := miner.MarketRetryPublishDeal(ctx, propcid) diff --git a/itests/kit/deals.go b/itests/kit/deals.go index f8de14d62..108c38c2d 100644 --- a/itests/kit/deals.go +++ b/itests/kit/deals.go @@ -134,6 +134,29 @@ func (dh *DealHarness) StartDeal(ctx context.Context, dealParams api.StartDealPa return dealProposalCid } +func (dh *DealHarness) WaitUntilDataTransfer(ctx context.Context, deal *cid.Cid) { +loop: + for { + di, err := dh.client.ClientGetDealInfo(ctx, *deal) + if err != nil { + dh.t.Fatal("can't fetch deal info") + } + + switch di.State { + case storagemarket.StorageDealProposalRejected: + dh.t.Fatal("deal rejected") + case storagemarket.StorageDealFailing: + dh.t.Fatal("deal failed") + case storagemarket.StorageDealError: + dh.t.Fatal("deal errored") + case storagemarket.StorageDealStartDataTransfer: + break loop + } + + time.Sleep(time.Millisecond * 100) + } +} + // WaitDealSealed waits until the deal is sealed. func (dh *DealHarness) WaitDealSealed(ctx context.Context, deal *cid.Cid, noseal, noSealStart bool, cb func()) { loop: From d50a26f4ae015dd6753f921c6342842179e4d038 Mon Sep 17 00:00:00 2001 From: Nikola Divic Date: Sat, 12 Feb 2022 17:10:00 +0100 Subject: [PATCH 12/57] Revert "test: (kinda) fix flaky test" This reverts commit baee4a157638c2f6ae804392e76297aae3a5d767. --- itests/deals_retry_deal_no_funds_test.go | 3 ++- itests/kit/deals.go | 23 ----------------------- 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/itests/deals_retry_deal_no_funds_test.go b/itests/deals_retry_deal_no_funds_test.go index ce8cd9729..a14a0d085 100644 --- a/itests/deals_retry_deal_no_funds_test.go +++ b/itests/deals_retry_deal_no_funds_test.go @@ -95,11 +95,12 @@ func TestDealsRetryLackOfFunds(t *testing.T) { dp.FastRetrieval = true dp.EpochPrice = abi.NewTokenAmount(62500000) // minimum asking price. deal := dh.StartDeal(ctx, dp) - dh.WaitUntilDataTransfer(ctx, deal) propcid := *deal go func() { + time.Sleep(3 * time.Second) + kit.SendFunds(ctx, t, minerFullNode, publishStorageDealKey.Address, types.FromFil(1)) err := miner.MarketRetryPublishDeal(ctx, propcid) diff --git a/itests/kit/deals.go b/itests/kit/deals.go index 108c38c2d..f8de14d62 100644 --- a/itests/kit/deals.go +++ b/itests/kit/deals.go @@ -134,29 +134,6 @@ func (dh *DealHarness) StartDeal(ctx context.Context, dealParams api.StartDealPa return dealProposalCid } -func (dh *DealHarness) WaitUntilDataTransfer(ctx context.Context, deal *cid.Cid) { -loop: - for { - di, err := dh.client.ClientGetDealInfo(ctx, *deal) - if err != nil { - dh.t.Fatal("can't fetch deal info") - } - - switch di.State { - case storagemarket.StorageDealProposalRejected: - dh.t.Fatal("deal rejected") - case storagemarket.StorageDealFailing: - dh.t.Fatal("deal failed") - case storagemarket.StorageDealError: - dh.t.Fatal("deal errored") - case storagemarket.StorageDealStartDataTransfer: - break loop - } - - time.Sleep(time.Millisecond * 100) - } -} - // WaitDealSealed waits until the deal is sealed. func (dh *DealHarness) WaitDealSealed(ctx context.Context, deal *cid.Cid, noseal, noSealStart bool, cb func()) { loop: From 93d9bfb682e0ef3a8bce5c769d7c9df75894ae82 Mon Sep 17 00:00:00 2001 From: Nikola Divic Date: Sun, 13 Feb 2022 18:39:37 +0100 Subject: [PATCH 13/57] doc: stm test annotations for cli/sync category --- cli/sync_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cli/sync_test.go b/cli/sync_test.go index 174279d08..90f20a029 100644 --- a/cli/sync_test.go +++ b/cli/sync_test.go @@ -43,6 +43,7 @@ func TestSyncStatus(t *testing.T) { mockApi.EXPECT().SyncState(ctx).Return(state, nil) + //stm: @CLI_SYNC_STATUS_001 err := app.Run([]string{"sync", "status"}) assert.NoError(t, err) @@ -68,6 +69,7 @@ func TestSyncMarkBad(t *testing.T) { 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) } @@ -84,6 +86,7 @@ func TestSyncUnmarkBad(t *testing.T) { 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) }) @@ -97,6 +100,7 @@ func TestSyncUnmarkBad(t *testing.T) { mockApi.EXPECT().SyncUnmarkAllBad(ctx).Return(nil) + //stm: @CLI_SYNC_UNMARK_BAD_002 err := app.Run([]string{"sync", "unmark-bad", "-all"}) assert.NoError(t, err) }) @@ -114,6 +118,7 @@ func TestSyncCheckBad(t *testing.T) { 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) @@ -132,6 +137,7 @@ func TestSyncCheckBad(t *testing.T) { 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) @@ -155,6 +161,7 @@ func TestSyncCheckpoint(t *testing.T) { 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) }) @@ -175,6 +182,7 @@ func TestSyncCheckpoint(t *testing.T) { 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) }) From c3817652dccfd964d9c731ea6201745e7f676973 Mon Sep 17 00:00:00 2001 From: Darko Brdareski Date: Mon, 21 Feb 2022 11:28:45 +0100 Subject: [PATCH 14/57] Add cli tests for mempool --- cli/mpool.go | 61 +++--- cli/mpool_test.go | 522 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 559 insertions(+), 24 deletions(-) create mode 100644 cli/mpool_test.go diff --git a/cli/mpool.go b/cli/mpool.go index adefd25a8..0224b15d2 100644 --- a/cli/mpool.go +++ b/cli/mpool.go @@ -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: " | ", + ArgsUsage: " | ", 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 diff --git a/cli/mpool_test.go b/cli/mpool_test.go new file mode 100644 index 000000000..1bb45fd62 --- /dev/null +++ b/cli/mpool_test.go @@ -0,0 +1,522 @@ +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, err := 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), + ) + + 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, err := 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), + ) + + 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, err := 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), + ) + + 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, err := 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), + ) + + 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, err := 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), + ) + + 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, err := 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), + ) + + 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, err := 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), + ) + + 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, err := 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), + ) + + 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()) + }) +} + +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, err := 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), + ) + + 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, err := 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), + ) + + 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, err := 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), + ) + + 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, err := 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), + ) + + 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, err := 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), + ) + + 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, err := 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), + ) + + 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, err := 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) + } + + err = app.Run([]string{"mpool", "config", string(bytes)}) + assert.NoError(t, err) + }) +} From c8cd8bb591c44a1d5dc5f2aa6355e9a0bcd19763 Mon Sep 17 00:00:00 2001 From: Darko Brdareski Date: Mon, 21 Feb 2022 12:32:53 +0100 Subject: [PATCH 15/57] Add stm annotations --- cli/mpool_test.go | 60 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/cli/mpool_test.go b/cli/mpool_test.go index 1bb45fd62..194233490 100644 --- a/cli/mpool_test.go +++ b/cli/mpool_test.go @@ -1,3 +1,4 @@ +//stm: #integration package cli import ( @@ -54,6 +55,7 @@ func TestStat(t *testing.T) { 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) @@ -93,6 +95,7 @@ func TestStat(t *testing.T) { 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) @@ -125,6 +128,7 @@ func TestPending(t *testing.T) { 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) @@ -156,6 +160,7 @@ func TestPending(t *testing.T) { 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) @@ -186,6 +191,7 @@ func TestPending(t *testing.T) { 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) @@ -216,6 +222,7 @@ func TestPending(t *testing.T) { 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) @@ -252,6 +259,7 @@ func TestReplace(t *testing.T) { 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) @@ -296,11 +304,56 @@ func TestReplace(t *testing.T) { 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, err := 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) { @@ -327,6 +380,7 @@ func TestFindMsg(t *testing.T) { 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) @@ -356,6 +410,7 @@ func TestFindMsg(t *testing.T) { 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) @@ -385,6 +440,7 @@ func TestFindMsg(t *testing.T) { 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) @@ -421,6 +477,7 @@ func TestGasPerf(t *testing.T) { 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) @@ -457,6 +514,7 @@ func TestGasPerf(t *testing.T) { mockApi.EXPECT().ChainHead(ctx).Return(head, nil), ) + //stm: @CLI_MEMPOOL_GAS_PERF_001 err = app.Run([]string{"mpool", "gas-perf"}) assert.NoError(t, err) @@ -484,6 +542,7 @@ func TestConfig(t *testing.T) { mockApi.EXPECT().MpoolGetConfig(ctx).Return(mpoolCfg, nil), ) + //stm: @CLI_MEMPOOL_CONFIG_001 err = app.Run([]string{"mpool", "config"}) assert.NoError(t, err) @@ -516,6 +575,7 @@ func TestConfig(t *testing.T) { t.Fatal(err) } + //stm: @CLI_MEMPOOL_CONFIG_002 err = app.Run([]string{"mpool", "config", string(bytes)}) assert.NoError(t, err) }) From ad4acf3baab003a142823e4be281ed579a6b3a83 Mon Sep 17 00:00:00 2001 From: Darko Brdareski Date: Mon, 21 Feb 2022 17:58:00 +0100 Subject: [PATCH 16/57] Fix lint issues --- cli/mpool_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/mpool_test.go b/cli/mpool_test.go index 194233490..47ded7f1d 100644 --- a/cli/mpool_test.go +++ b/cli/mpool_test.go @@ -1,4 +1,4 @@ -//stm: #integration +//stm: #cli package cli import ( @@ -33,7 +33,7 @@ func TestStat(t *testing.T) { head := mock.TipSet(mock.MkBlock(first, 15, 7)) // create a signed message to be returned as a pending message - w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + w, _ := wallet.NewWallet(wallet.NewMemKeyStore()) senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1) if err != nil { t.Fatal(err) @@ -74,7 +74,7 @@ func TestStat(t *testing.T) { head := mock.TipSet(mock.MkBlock(first, 15, 7)) // create a signed message to be returned as a pending message - w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + w, _ := wallet.NewWallet(wallet.NewMemKeyStore()) senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1) if err != nil { t.Fatal(err) @@ -113,7 +113,7 @@ func TestPending(t *testing.T) { defer cancel() // create a signed message to be returned as a pending message - w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + w, _ := wallet.NewWallet(wallet.NewMemKeyStore()) senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1) if err != nil { t.Fatal(err) From 7b203eae1bfc17dbe5fb38b7dd01725338c44864 Mon Sep 17 00:00:00 2001 From: Darko Brdareski Date: Mon, 21 Feb 2022 18:35:31 +0100 Subject: [PATCH 17/57] More lint issues fixed --- cli/mpool_test.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/cli/mpool_test.go b/cli/mpool_test.go index 47ded7f1d..d9eef452c 100644 --- a/cli/mpool_test.go +++ b/cli/mpool_test.go @@ -144,7 +144,7 @@ func TestPending(t *testing.T) { defer cancel() // create a signed message to be returned as a pending message - w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + w, _ := wallet.NewWallet(wallet.NewMemKeyStore()) senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1) if err != nil { t.Fatal(err) @@ -176,7 +176,7 @@ func TestPending(t *testing.T) { defer cancel() // create a signed message to be returned as a pending message - w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + w, _ := wallet.NewWallet(wallet.NewMemKeyStore()) senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1) if err != nil { t.Fatal(err) @@ -207,7 +207,7 @@ func TestPending(t *testing.T) { defer cancel() // create a signed message to be returned as a pending message - w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + w, _ := wallet.NewWallet(wallet.NewMemKeyStore()) senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1) if err != nil { t.Fatal(err) @@ -240,7 +240,7 @@ func TestReplace(t *testing.T) { defer cancel() // create a signed message to be returned as a pending message - w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + w, _ := wallet.NewWallet(wallet.NewMemKeyStore()) senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1) if err != nil { t.Fatal(err) @@ -274,7 +274,7 @@ func TestReplace(t *testing.T) { defer cancel() // create a signed message to be returned as a pending message - w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + w, _ := wallet.NewWallet(wallet.NewMemKeyStore()) senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1) if err != nil { t.Fatal(err) @@ -319,7 +319,7 @@ func TestReplace(t *testing.T) { defer cancel() // create a signed message to be returned as a pending message - w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + w, _ := wallet.NewWallet(wallet.NewMemKeyStore()) senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1) if err != nil { t.Fatal(err) @@ -365,7 +365,7 @@ func TestFindMsg(t *testing.T) { defer cancel() // create a signed message to be returned as a pending message - w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + w, _ := wallet.NewWallet(wallet.NewMemKeyStore()) senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1) if err != nil { t.Fatal(err) @@ -395,7 +395,7 @@ func TestFindMsg(t *testing.T) { defer cancel() // create a signed message to be returned as a pending message - w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + w, _ := wallet.NewWallet(wallet.NewMemKeyStore()) senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1) if err != nil { t.Fatal(err) @@ -425,7 +425,7 @@ func TestFindMsg(t *testing.T) { defer cancel() // create a signed message to be returned as a pending message - w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + w, _ := wallet.NewWallet(wallet.NewMemKeyStore()) senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1) if err != nil { t.Fatal(err) @@ -461,7 +461,7 @@ func TestGasPerf(t *testing.T) { head := mock.TipSet(mock.MkBlock(first, 15, 7)) // create a signed message to be returned as a pending message - w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + w, _ := wallet.NewWallet(wallet.NewMemKeyStore()) senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1) if err != nil { t.Fatal(err) @@ -497,7 +497,7 @@ func TestGasPerf(t *testing.T) { head := mock.TipSet(mock.MkBlock(first, 15, 7)) // create a signed message to be returned as a pending message - w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + w, _ := wallet.NewWallet(wallet.NewMemKeyStore()) senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1) if err != nil { t.Fatal(err) @@ -531,7 +531,7 @@ func TestConfig(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + w, _ := wallet.NewWallet(wallet.NewMemKeyStore()) senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1) if err != nil { t.Fatal(err) @@ -559,7 +559,7 @@ func TestConfig(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + w, _ := wallet.NewWallet(wallet.NewMemKeyStore()) senderAddr, err := w.WalletNew(context.Background(), types.KTSecp256k1) if err != nil { t.Fatal(err) From 04bc4405c782f390538d9c8e2c9dae6a471951c5 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 21 Feb 2022 14:29:17 +0000 Subject: [PATCH 18/57] fix: chain: check against the inclusion price at the correct height We need to use the height at which the messages will be executed, not the height of the previous tipset. This brings the gas checking for validation with the gas we actually _charge_ during message execution. This only matters for the Calico upgrade (the only upgrade where we changed the gas prices). This change could potentially cause a block at that height to be rejected if it includes a message with insufficient gas for inclusion. However, that _should_ have shown up as a miner penalty when we executed the blocks in the following tipset. Given that there were no miner penalties at 265199-265201, this change should be "safe". --- chain/consensus/filcns/filecoin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/consensus/filcns/filecoin.go b/chain/consensus/filcns/filecoin.go index 0adb79191..3aa85c7c5 100644 --- a/chain/consensus/filcns/filecoin.go +++ b/chain/consensus/filcns/filecoin.go @@ -467,7 +467,7 @@ func (filec *FilecoinEC) checkBlockMessages(ctx context.Context, b *types.FullBl } nv := filec.sm.GetNetworkVersion(ctx, b.Header.Height) - pl := vm.PricelistByEpoch(baseTs.Height()) + pl := vm.PricelistByEpoch(b.Header.Height) var sumGasLimit int64 checkMsg := func(msg types.ChainMsg) error { m := msg.VMMessage() From 1234fcfd4f9ea8bf057b02fba72a92d80e0afff8 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 21 Feb 2022 14:39:11 +0000 Subject: [PATCH 19/57] fix: mempool: check messages against the next block's height Previously, we checked message gas/validity with the previous block's height. This doesn't affect consensus, but will help us avoid adding messages to the message pool that shouldn't be there. --- chain/messagepool/check.go | 2 +- chain/messagepool/messagepool.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/chain/messagepool/check.go b/chain/messagepool/check.go index 283c0d119..92cfb458a 100644 --- a/chain/messagepool/check.go +++ b/chain/messagepool/check.go @@ -106,7 +106,7 @@ func (mp *MessagePool) checkMessages(ctx context.Context, msgs []*types.Message, curTs := mp.curTs mp.curTsLk.Unlock() - epoch := curTs.Height() + epoch := curTs.Height() + 1 var baseFee big.Int if len(curTs.Blocks()) > 0 { diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 76647e331..1520d45b4 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -628,7 +628,7 @@ func (mp *MessagePool) addLocal(ctx context.Context, m *types.SignedMessage) err // For non local messages, if the message cannot be included in the next 20 blocks it returns // a (soft) validation error. func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.TipSet, local bool) (bool, error) { - epoch := curTs.Height() + epoch := curTs.Height() + 1 minGas := vm.PricelistByEpoch(epoch).OnChainMessage(m.ChainLength()) if err := m.VMMessage().ValidForBlockInclusion(minGas.Total(), build.NewestNetworkVersion); err != nil { From a05a462c8c9110456c145a69ca202a57fd139940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 22 Feb 2022 10:48:47 +0100 Subject: [PATCH 20/57] market utils: Support unixfsnode in TraverseDag --- go.mod | 1 + markets/utils/selectors.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/go.mod b/go.mod index 293a17bc4..e8a97298e 100644 --- a/go.mod +++ b/go.mod @@ -100,6 +100,7 @@ require ( github.com/ipfs/go-metrics-prometheus v0.0.2 github.com/ipfs/go-path v0.0.7 github.com/ipfs/go-unixfs v0.3.1 + github.com/ipfs/go-unixfsnode v1.2.0 github.com/ipfs/interface-go-ipfs-core v0.4.0 github.com/ipld/go-car v0.3.3 github.com/ipld/go-car/v2 v2.1.1 diff --git a/markets/utils/selectors.go b/markets/utils/selectors.go index 7d40ba6dd..e1009d1ff 100644 --- a/markets/utils/selectors.go +++ b/markets/utils/selectors.go @@ -11,6 +11,7 @@ import ( "github.com/ipfs/go-cid" mdagipld "github.com/ipfs/go-ipld-format" + "github.com/ipfs/go-unixfsnode" dagpb "github.com/ipld/go-codec-dagpb" "github.com/ipld/go-ipld-prime" cidlink "github.com/ipld/go-ipld-prime/linking/cid" @@ -62,6 +63,7 @@ func TraverseDag( return bytes.NewBuffer(node.RawData()), nil } + unixfsnode.AddUnixFSReificationToLinkSystem(&linkSystem) // this is how we pull the start node out of the DS startLink := cidlink.Link{Cid: startFrom} From 012cf96d600c669fb90f87dec501b774a3069b12 Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 22 Feb 2022 12:19:26 +0200 Subject: [PATCH 21/57] update go-libp2p to v0.18.0-rc5 --- go.mod | 4 ++-- go.sum | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 293a17bc4..0fae1713c 100644 --- a/go.mod +++ b/go.mod @@ -110,7 +110,7 @@ require ( github.com/kelseyhightower/envconfig v1.4.0 github.com/libp2p/go-buffer-pool v0.0.2 github.com/libp2p/go-eventbus v0.2.1 - github.com/libp2p/go-libp2p v0.18.0-rc4 + github.com/libp2p/go-libp2p v0.18.0-rc5 github.com/libp2p/go-libp2p-connmgr v0.3.1 // indirect github.com/libp2p/go-libp2p-core v0.14.0 github.com/libp2p/go-libp2p-discovery v0.6.0 @@ -122,7 +122,7 @@ require ( github.com/libp2p/go-libp2p-record v0.1.3 github.com/libp2p/go-libp2p-resource-manager v0.1.4 github.com/libp2p/go-libp2p-routing-helpers v0.2.3 - github.com/libp2p/go-libp2p-swarm v0.10.1 + github.com/libp2p/go-libp2p-swarm v0.10.2 github.com/libp2p/go-libp2p-tls v0.3.1 github.com/libp2p/go-libp2p-yamux v0.8.2 github.com/libp2p/go-maddr-filter v0.1.0 diff --git a/go.sum b/go.sum index 292747fc8..417267e37 100644 --- a/go.sum +++ b/go.sum @@ -995,8 +995,8 @@ github.com/libp2p/go-libp2p v0.14.4/go.mod h1:EIRU0Of4J5S8rkockZM7eJp2S0UrCyi55m github.com/libp2p/go-libp2p v0.16.0/go.mod h1:ump42BsirwAWxKzsCiFnTtN1Yc+DuPu76fyMX364/O4= github.com/libp2p/go-libp2p v0.17.0/go.mod h1:Fkin50rsGdv5mm5BshBUtPRZknt9esfmYXBOYcwOTgw= github.com/libp2p/go-libp2p v0.18.0-rc1/go.mod h1:RgYlH7IIWHXREimC92bw5Lg1V2R5XmSzuLHb5fTnr+8= -github.com/libp2p/go-libp2p v0.18.0-rc4 h1:OUsSbeu7q+Ck/bV9wHDxFzb08ORqBupHhpCmRBhWrJ8= -github.com/libp2p/go-libp2p v0.18.0-rc4/go.mod h1:wzmsk1ioOq9FGQys2BN5BIw4nugP6+R+CyW3JbPEbbs= +github.com/libp2p/go-libp2p v0.18.0-rc5 h1:88wWDHb9nNo0vBNCupLde3OTnFAkugOCNkrDfl3ivK4= +github.com/libp2p/go-libp2p v0.18.0-rc5/go.mod h1:aZPS5l84bDvCvP4jkyEUT/J6YOpUq33Fgqrs3K59mpI= github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= github.com/libp2p/go-libp2p-asn-util v0.1.0 h1:rABPCO77SjdbJ/eJ/ynIo8vWICy1VEnL5JAxJbQLo1E= github.com/libp2p/go-libp2p-asn-util v0.1.0/go.mod h1:wu+AnM9Ii2KgO5jMmS1rz9dvzTdj8BXqsPR9HR0XB7I= @@ -1182,8 +1182,8 @@ github.com/libp2p/go-libp2p-swarm v0.5.3/go.mod h1:NBn7eNW2lu568L7Ns9wdFrOhgRlkR github.com/libp2p/go-libp2p-swarm v0.8.0/go.mod h1:sOMp6dPuqco0r0GHTzfVheVBh6UEL0L1lXUZ5ot2Fvc= github.com/libp2p/go-libp2p-swarm v0.9.0/go.mod h1:2f8d8uxTJmpeqHF/1ujjdXZp+98nNIbujVOMEZxCbZ8= github.com/libp2p/go-libp2p-swarm v0.10.0/go.mod h1:71ceMcV6Rg/0rIQ97rsZWMzto1l9LnNquef+efcRbmA= -github.com/libp2p/go-libp2p-swarm v0.10.1 h1:lXW3pgGt+BVmkzcFX61erX7l6Lt+WAamNhwa2Kf3eJM= -github.com/libp2p/go-libp2p-swarm v0.10.1/go.mod h1:Pdkq0QU5a+qu+oyqIV3bknMsnzk9lnNyKvB9acJ5aZs= +github.com/libp2p/go-libp2p-swarm v0.10.2 h1:UaXf+CTq6Ns1N2V1EgqJ9Q3xaRsiN7ImVlDMpirMAWw= +github.com/libp2p/go-libp2p-swarm v0.10.2/go.mod h1:Pdkq0QU5a+qu+oyqIV3bknMsnzk9lnNyKvB9acJ5aZs= github.com/libp2p/go-libp2p-testing v0.0.1/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= @@ -1299,8 +1299,9 @@ github.com/libp2p/go-tcp-transport v0.2.3/go.mod h1:9dvr03yqrPyYGIEN6Dy5UvdJZjyP github.com/libp2p/go-tcp-transport v0.2.4/go.mod h1:9dvr03yqrPyYGIEN6Dy5UvdJZjyPFvl1S/igQ5QD1SU= github.com/libp2p/go-tcp-transport v0.2.7/go.mod h1:lue9p1b3VmZj1MhhEGB/etmvF/nBQ0X9CW2DutBT3MM= github.com/libp2p/go-tcp-transport v0.4.0/go.mod h1:0y52Rwrn4076xdJYu/51/qJIdxz+EWDAOG2S45sV3VI= -github.com/libp2p/go-tcp-transport v0.5.0 h1:3ZPW8HAuyRAuFzyabE0hSrCXKKSWzROnZZX7DtcIatY= github.com/libp2p/go-tcp-transport v0.5.0/go.mod h1:UPPL0DIjQqiWRwVAb+CEQlaAG0rp/mCqJfIhFcLHc4Y= +github.com/libp2p/go-tcp-transport v0.5.1 h1:edOOs688VLZAozWC7Kj5/6HHXKNwi9M6wgRmmLa8M6Q= +github.com/libp2p/go-tcp-transport v0.5.1/go.mod h1:UPPL0DIjQqiWRwVAb+CEQlaAG0rp/mCqJfIhFcLHc4Y= github.com/libp2p/go-testutil v0.0.1/go.mod h1:iAcJc/DKJQanJ5ws2V+u5ywdL2n12X1WbbEG+Jjy69I= github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjVe/gLzZ2Ehc= github.com/libp2p/go-ws-transport v0.0.5/go.mod h1:Qbl4BxPfXXhhd/o0wcrgoaItHqA9tnZjoFZnxykuaXU= From 10c939bc36635cc5aea0970034e14e03b1f655e0 Mon Sep 17 00:00:00 2001 From: Darko Brdareski Date: Tue, 22 Feb 2022 14:54:56 +0100 Subject: [PATCH 22/57] Remove leftover logging from sync_manager_test --- chain/sync_manager_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/chain/sync_manager_test.go b/chain/sync_manager_test.go index d91ab1788..bbd690d23 100644 --- a/chain/sync_manager_test.go +++ b/chain/sync_manager_test.go @@ -247,7 +247,6 @@ func TestSyncManagerBucketSet(t *testing.T) { ts2 := mock.TipSet(mock.MkBlock(ts1, 1, 0)) bucket1 := newSyncTargetBucket(ts1, ts2) bucketSet := syncBucketSet{buckets: []*syncTargetBucket{bucket1}} - fmt.Println("bucketSet: ", bucketSet.String()) // inserting a tipset (potential sync target) from an existing chain, should add to an existing bucket //stm: @CHAIN_SYNCER_ADD_SYNC_TARGET_001 @@ -255,7 +254,6 @@ func TestSyncManagerBucketSet(t *testing.T) { bucketSet.Insert(ts3) require.Equal(t, 1, len(bucketSet.buckets)) require.Equal(t, 3, len(bucketSet.buckets[0].tips)) - fmt.Println("bucketSet: ", bucketSet.String()) // inserting a tipset from new chain, should create a new bucket ts4fork := mock.TipSet(mock.MkBlock(nil, 1, 1)) @@ -263,7 +261,6 @@ func TestSyncManagerBucketSet(t *testing.T) { require.Equal(t, 2, len(bucketSet.buckets)) require.Equal(t, 3, len(bucketSet.buckets[0].tips)) require.Equal(t, 1, len(bucketSet.buckets[1].tips)) - fmt.Println("bucketSet: ", bucketSet.String()) // Pop removes the best bucket (best sync target), e.g. bucket1 //stm: @CHAIN_SYNCER_SELECT_SYNC_TARGET_001 From a54d2fd19d58d0fc486477440a4d0bb518c45278 Mon Sep 17 00:00:00 2001 From: Darko Brdareski Date: Tue, 22 Feb 2022 17:08:04 +0100 Subject: [PATCH 23/57] Update cli docs --- documentation/en/cli-lotus.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/en/cli-lotus.md b/documentation/en/cli-lotus.md index e7ebf8af6..3be25a295 100644 --- a/documentation/en/cli-lotus.md +++ b/documentation/en/cli-lotus.md @@ -1643,7 +1643,7 @@ NAME: lotus mpool replace - replace a message in the mempool USAGE: - lotus mpool replace [command options] | + lotus mpool replace [command options] | OPTIONS: --gas-feecap value gas feecap for new message (burn and pay to miner, attoFIL/GasUnit) From e2cbad6ff4e248a44056aadf7a9813dfb298cbe5 Mon Sep 17 00:00:00 2001 From: "eben.xie" Date: Wed, 23 Feb 2022 10:49:53 +0800 Subject: [PATCH 24/57] [Describe]: when excute cmd "lotus-bench sealing" without "benchmark-existing-sectorbuilder", panic will occur [BugFix]: [FeatureAdd]: [CodeReview]: [ModifyDesc]: [Author]: [BugID]: --- cmd/lotus-bench/main.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cmd/lotus-bench/main.go b/cmd/lotus-bench/main.go index b0e71b90e..c6fdd5e32 100644 --- a/cmd/lotus-bench/main.go +++ b/cmd/lotus-bench/main.go @@ -276,6 +276,13 @@ var sealBenchCmd = &cli.Command{ if err != nil { return xerrors.Errorf("failed to run seals: %w", err) } + for _, s := range extendedSealedSectors { + sealedSectors = append(sealedSectors, proof.SectorInfo{ + SealedCID: s.SealedCID, + SectorNumber: s.SectorNumber, + SealProof: s.SealProof, + }) + } } else { // TODO: implement sbfs.List() and use that for all cases (preexisting sectorbuilder or not) From 375d9fdfc9e3278f6e751be093af12f2e237a68c Mon Sep 17 00:00:00 2001 From: Geoff Stuart Date: Tue, 22 Feb 2022 21:25:30 -0500 Subject: [PATCH 25/57] Added cli command for verifier to sing RemoveDataCapProposal --- .../actors/builtin/verifreg/actor.go.template | 5 + .../actors/builtin/verifreg/state.go.template | 9 ++ chain/actors/builtin/verifreg/util.go | 23 +++++ chain/actors/builtin/verifreg/v0.go | 9 ++ chain/actors/builtin/verifreg/v2.go | 9 ++ chain/actors/builtin/verifreg/v3.go | 9 ++ chain/actors/builtin/verifreg/v4.go | 9 ++ chain/actors/builtin/verifreg/v5.go | 9 ++ chain/actors/builtin/verifreg/v6.go | 9 ++ chain/actors/builtin/verifreg/v7.go | 8 ++ chain/actors/builtin/verifreg/verifreg.go | 7 ++ cli/filplus.go | 94 +++++++++++++++++++ 12 files changed, 200 insertions(+) diff --git a/chain/actors/builtin/verifreg/actor.go.template b/chain/actors/builtin/verifreg/actor.go.template index 9ea8e155a..7ca133af9 100644 --- a/chain/actors/builtin/verifreg/actor.go.template +++ b/chain/actors/builtin/verifreg/actor.go.template @@ -16,6 +16,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/types" + verifreg7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/verifreg" ) func init() { @@ -62,6 +63,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { return cid.Undef, xerrors.Errorf("unknown actor version %d", av) } +type RemoveDataCapProposal = verifreg7.RemoveDataCapProposal +type RmDcProposalID = verifreg7.RmDcProposalID +const SignatureDomainSeparation_RemoveDataCap = verifreg7.SignatureDomainSeparation_RemoveDataCap type State interface { cbor.Marshaler @@ -69,6 +73,7 @@ type State interface { RootKey() (address.Address, error) VerifiedClientDataCap(address.Address) (bool, abi.StoragePower, error) VerifierDataCap(address.Address) (bool, abi.StoragePower, error) + RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) ForEachVerifier(func(addr address.Address, dcap abi.StoragePower) error) error ForEachClient(func(addr address.Address, dcap abi.StoragePower) error) error GetState() interface{} diff --git a/chain/actors/builtin/verifreg/state.go.template b/chain/actors/builtin/verifreg/state.go.template index b59cfb628..4dfc11469 100644 --- a/chain/actors/builtin/verifreg/state.go.template +++ b/chain/actors/builtin/verifreg/state.go.template @@ -61,6 +61,10 @@ func (s *state{{.v}}) VerifierDataCap(addr address.Address) (bool, abi.StoragePo return getDataCap(s.store, actors.Version{{.v}}, s.verifiers, addr) } +func (s *state{{.v}}) RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) { + return getRemoveDataCapProposalID(s.store, actors.Version{{.v}}, s.removeDataCapProposalIDs, verifier, client) +} + func (s *state{{.v}}) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { return forEachCap(s.store, actors.Version{{.v}}, s.verifiers, cb) } @@ -77,6 +81,11 @@ func (s *state{{.v}}) verifiers() (adt.Map, error) { return adt{{.v}}.AsMap(s.store, s.Verifiers{{if (ge .v 3)}}, builtin{{.v}}.DefaultHamtBitwidth{{end}}) } +func (s *state{{.v}}) removeDataCapProposalIDs() (adt.Map, error) { + {{if le .v 6}}return nil, nil + {{else}}return adt{{.v}}.AsMap(s.store, s.RemoveDataCapProposalIDs, builtin{{.v}}.DefaultHamtBitwidth){{end}} +} + func (s *state{{.v}}) GetState() interface{} { return &s.State } \ No newline at end of file diff --git a/chain/actors/builtin/verifreg/util.go b/chain/actors/builtin/verifreg/util.go index 16e50c50a..8d63e28c9 100644 --- a/chain/actors/builtin/verifreg/util.go +++ b/chain/actors/builtin/verifreg/util.go @@ -6,6 +6,7 @@ import ( "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/specs-actors/v7/actors/builtin/verifreg" "golang.org/x/xerrors" ) @@ -50,3 +51,25 @@ func forEachCap(store adt.Store, ver actors.Version, root rootFunc, cb func(addr return cb(a, dcap) }) } + +func getRemoveDataCapProposalID(store adt.Store, ver actors.Version, root rootFunc, verifier address.Address, client address.Address) (bool, uint64, error) { + if verifier.Protocol() != address.ID { + return false, 0, xerrors.Errorf("can only look up ID addresses") + } + if client.Protocol() != address.ID { + return false, 0, xerrors.Errorf("can only look up ID addresses") + } + vh, err := root() + if err != nil { + return false, 0, xerrors.Errorf("loading verifreg: %w", err) + } + + var id verifreg.RmDcProposalID + if found, err := vh.Get(abi.NewAddrPairKey(verifier, client), &id); err != nil { + return false, 0, xerrors.Errorf("looking up addr pair: %w", err) + } else if !found { + return false, 0, nil + } + + return true, id.ProposalID, nil +} diff --git a/chain/actors/builtin/verifreg/v0.go b/chain/actors/builtin/verifreg/v0.go index e70b0e3c9..dcd34c72a 100644 --- a/chain/actors/builtin/verifreg/v0.go +++ b/chain/actors/builtin/verifreg/v0.go @@ -53,6 +53,10 @@ func (s *state0) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, return getDataCap(s.store, actors.Version0, s.verifiers, addr) } +func (s *state0) RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) { + return getRemoveDataCapProposalID(s.store, actors.Version0, s.removeDataCapProposalIDs, verifier, client) +} + func (s *state0) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { return forEachCap(s.store, actors.Version0, s.verifiers, cb) } @@ -69,6 +73,11 @@ func (s *state0) verifiers() (adt.Map, error) { return adt0.AsMap(s.store, s.Verifiers) } +func (s *state0) removeDataCapProposalIDs() (adt.Map, error) { + return nil, nil + +} + func (s *state0) GetState() interface{} { return &s.State } diff --git a/chain/actors/builtin/verifreg/v2.go b/chain/actors/builtin/verifreg/v2.go index 0bcbe0212..dfe25f054 100644 --- a/chain/actors/builtin/verifreg/v2.go +++ b/chain/actors/builtin/verifreg/v2.go @@ -53,6 +53,10 @@ func (s *state2) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, return getDataCap(s.store, actors.Version2, s.verifiers, addr) } +func (s *state2) RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) { + return getRemoveDataCapProposalID(s.store, actors.Version2, s.removeDataCapProposalIDs, verifier, client) +} + func (s *state2) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { return forEachCap(s.store, actors.Version2, s.verifiers, cb) } @@ -69,6 +73,11 @@ func (s *state2) verifiers() (adt.Map, error) { return adt2.AsMap(s.store, s.Verifiers) } +func (s *state2) removeDataCapProposalIDs() (adt.Map, error) { + return nil, nil + +} + func (s *state2) GetState() interface{} { return &s.State } diff --git a/chain/actors/builtin/verifreg/v3.go b/chain/actors/builtin/verifreg/v3.go index 32003ca3a..c71c69f92 100644 --- a/chain/actors/builtin/verifreg/v3.go +++ b/chain/actors/builtin/verifreg/v3.go @@ -54,6 +54,10 @@ func (s *state3) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, return getDataCap(s.store, actors.Version3, s.verifiers, addr) } +func (s *state3) RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) { + return getRemoveDataCapProposalID(s.store, actors.Version3, s.removeDataCapProposalIDs, verifier, client) +} + func (s *state3) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { return forEachCap(s.store, actors.Version3, s.verifiers, cb) } @@ -70,6 +74,11 @@ func (s *state3) verifiers() (adt.Map, error) { return adt3.AsMap(s.store, s.Verifiers, builtin3.DefaultHamtBitwidth) } +func (s *state3) removeDataCapProposalIDs() (adt.Map, error) { + return nil, nil + +} + func (s *state3) GetState() interface{} { return &s.State } diff --git a/chain/actors/builtin/verifreg/v4.go b/chain/actors/builtin/verifreg/v4.go index b752e747b..d3adc5169 100644 --- a/chain/actors/builtin/verifreg/v4.go +++ b/chain/actors/builtin/verifreg/v4.go @@ -54,6 +54,10 @@ func (s *state4) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, return getDataCap(s.store, actors.Version4, s.verifiers, addr) } +func (s *state4) RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) { + return getRemoveDataCapProposalID(s.store, actors.Version4, s.removeDataCapProposalIDs, verifier, client) +} + func (s *state4) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { return forEachCap(s.store, actors.Version4, s.verifiers, cb) } @@ -70,6 +74,11 @@ func (s *state4) verifiers() (adt.Map, error) { return adt4.AsMap(s.store, s.Verifiers, builtin4.DefaultHamtBitwidth) } +func (s *state4) removeDataCapProposalIDs() (adt.Map, error) { + return nil, nil + +} + func (s *state4) GetState() interface{} { return &s.State } diff --git a/chain/actors/builtin/verifreg/v5.go b/chain/actors/builtin/verifreg/v5.go index 6fefd7115..2af501af3 100644 --- a/chain/actors/builtin/verifreg/v5.go +++ b/chain/actors/builtin/verifreg/v5.go @@ -54,6 +54,10 @@ func (s *state5) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, return getDataCap(s.store, actors.Version5, s.verifiers, addr) } +func (s *state5) RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) { + return getRemoveDataCapProposalID(s.store, actors.Version5, s.removeDataCapProposalIDs, verifier, client) +} + func (s *state5) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { return forEachCap(s.store, actors.Version5, s.verifiers, cb) } @@ -70,6 +74,11 @@ func (s *state5) verifiers() (adt.Map, error) { return adt5.AsMap(s.store, s.Verifiers, builtin5.DefaultHamtBitwidth) } +func (s *state5) removeDataCapProposalIDs() (adt.Map, error) { + return nil, nil + +} + func (s *state5) GetState() interface{} { return &s.State } diff --git a/chain/actors/builtin/verifreg/v6.go b/chain/actors/builtin/verifreg/v6.go index b2c5078e7..454c9478f 100644 --- a/chain/actors/builtin/verifreg/v6.go +++ b/chain/actors/builtin/verifreg/v6.go @@ -54,6 +54,10 @@ func (s *state6) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, return getDataCap(s.store, actors.Version6, s.verifiers, addr) } +func (s *state6) RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) { + return getRemoveDataCapProposalID(s.store, actors.Version6, s.removeDataCapProposalIDs, verifier, client) +} + func (s *state6) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { return forEachCap(s.store, actors.Version6, s.verifiers, cb) } @@ -70,6 +74,11 @@ func (s *state6) verifiers() (adt.Map, error) { return adt6.AsMap(s.store, s.Verifiers, builtin6.DefaultHamtBitwidth) } +func (s *state6) removeDataCapProposalIDs() (adt.Map, error) { + return nil, nil + +} + func (s *state6) GetState() interface{} { return &s.State } diff --git a/chain/actors/builtin/verifreg/v7.go b/chain/actors/builtin/verifreg/v7.go index 9b2ca928a..3bcfa10bd 100644 --- a/chain/actors/builtin/verifreg/v7.go +++ b/chain/actors/builtin/verifreg/v7.go @@ -54,6 +54,10 @@ func (s *state7) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, return getDataCap(s.store, actors.Version7, s.verifiers, addr) } +func (s *state7) RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) { + return getRemoveDataCapProposalID(s.store, actors.Version7, s.removeDataCapProposalIDs, verifier, client) +} + func (s *state7) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { return forEachCap(s.store, actors.Version7, s.verifiers, cb) } @@ -70,6 +74,10 @@ func (s *state7) verifiers() (adt.Map, error) { return adt7.AsMap(s.store, s.Verifiers, builtin7.DefaultHamtBitwidth) } +func (s *state7) removeDataCapProposalIDs() (adt.Map, error) { + return adt7.AsMap(s.store, s.RemoveDataCapProposalIDs, builtin7.DefaultHamtBitwidth) +} + func (s *state7) GetState() interface{} { return &s.State } diff --git a/chain/actors/builtin/verifreg/verifreg.go b/chain/actors/builtin/verifreg/verifreg.go index f6281334d..b69a0f83e 100644 --- a/chain/actors/builtin/verifreg/verifreg.go +++ b/chain/actors/builtin/verifreg/verifreg.go @@ -27,6 +27,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" + verifreg7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/verifreg" ) func init() { @@ -151,12 +152,18 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { return cid.Undef, xerrors.Errorf("unknown actor version %d", av) } +type RemoveDataCapProposal = verifreg7.RemoveDataCapProposal +type RmDcProposalID = verifreg7.RmDcProposalID + +const SignatureDomainSeparation_RemoveDataCap = verifreg7.SignatureDomainSeparation_RemoveDataCap + type State interface { cbor.Marshaler RootKey() (address.Address, error) VerifiedClientDataCap(address.Address) (bool, abi.StoragePower, error) VerifierDataCap(address.Address) (bool, abi.StoragePower, error) + RemoveDataCapProposalID(verifier address.Address, client address.Address) (bool, uint64, error) ForEachVerifier(func(addr address.Address, dcap abi.StoragePower) error) error ForEachClient(func(addr address.Address, dcap abi.StoragePower) error) error GetState() interface{} diff --git a/cli/filplus.go b/cli/filplus.go index 02aac0b7b..ba2fc43a0 100644 --- a/cli/filplus.go +++ b/cli/filplus.go @@ -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,94 @@ 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: "TODO", + Flags: []cli.Flag{ + &cli.Int64Flag{ + Name: "id", + Usage: "specify the id of the Remove Data Cap Proposal", + Required: false, + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 3 { + return fmt.Errorf("must specify three arguments: verifier address, client address, and allowance to remove") + } + + verifier, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return err + } + + client, err := address.NewFromString(cctx.Args().Get(1)) + if err != nil { + return err + } + + allowanceToRemove, err := types.BigFromString(cctx.Args().Get(2)) + if err != nil { + return err + } + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + found, _, err := checkNotary(ctx, api, verifier) + if err != nil { + return err + } + + if !found { + return xerrors.New("verifier address must be a notary") + } + + id := cctx.Uint64("id") + if id == 0 { + act, err := api.StateGetActor(ctx, verifreg.Address, types.EmptyTSK) + if err != nil { + return err + } + + apibs := blockstore.NewAPIBlockstore(api) + store := adt.WrapStore(ctx, cbor.NewCborStore(apibs)) + + st, err := verifreg.Load(store, act) + if err != nil { + return err + } + _, id, err = st.RemoveDataCapProposalID(verifier, client) + if err != nil { + return err + } + } + + // TODO: This should be abstracted over actor versions + params := verifreg.RemoveDataCapProposal{ + RemovalProposalID: verifreg.RmDcProposalID{ProposalID: id}, + DataCapAmount: allowanceToRemove, + VerifiedClient: client, + } + + paramBuf := new(bytes.Buffer) + paramBuf.WriteString(verifreg.SignatureDomainSeparation_RemoveDataCap) + err = params.MarshalCBOR(paramBuf) + if err != nil { + return err + } + + msg, err := api.WalletSign(ctx, verifier, paramBuf.Bytes()) + if err != nil { + return err + } + + fmt.Println(hex.EncodeToString(msg.Data)) + + return nil + }, +} From 23147378a35a28ef2dc0a19a1b5de060d54e0332 Mon Sep 17 00:00:00 2001 From: Geoff Stuart Date: Tue, 22 Feb 2022 22:04:50 -0500 Subject: [PATCH 26/57] Added cli command for vrk to send RemoveVerifiedClientDataCap message --- .../actors/builtin/verifreg/actor.go.template | 8 +- chain/actors/builtin/verifreg/verifreg.go | 2 + cli/filplus.go | 6 +- cmd/lotus-shed/verifreg.go | 116 ++++++++++++++++++ 4 files changed, 127 insertions(+), 5 deletions(-) diff --git a/chain/actors/builtin/verifreg/actor.go.template b/chain/actors/builtin/verifreg/actor.go.template index 7ca133af9..adc156948 100644 --- a/chain/actors/builtin/verifreg/actor.go.template +++ b/chain/actors/builtin/verifreg/actor.go.template @@ -63,9 +63,11 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { return cid.Undef, xerrors.Errorf("unknown actor version %d", av) } -type RemoveDataCapProposal = verifreg7.RemoveDataCapProposal -type RmDcProposalID = verifreg7.RmDcProposalID -const SignatureDomainSeparation_RemoveDataCap = verifreg7.SignatureDomainSeparation_RemoveDataCap +type RemoveDataCapProposal = verifreg{{.latestVersion}}.RemoveDataCapProposal +type RemoveDataCapRequest = verifreg{{.latestVersion}}.RemoveDataCapRequest +type RemoveDataCapParams = verifreg{{.latestVersion}}.RemoveDataCapParams +type RmDcProposalID = verifreg{{.latestVersion}}.RmDcProposalID +const SignatureDomainSeparation_RemoveDataCap = verifreg{{.latestVersion}}.SignatureDomainSeparation_RemoveDataCap type State interface { cbor.Marshaler diff --git a/chain/actors/builtin/verifreg/verifreg.go b/chain/actors/builtin/verifreg/verifreg.go index b69a0f83e..cb26e324b 100644 --- a/chain/actors/builtin/verifreg/verifreg.go +++ b/chain/actors/builtin/verifreg/verifreg.go @@ -153,6 +153,8 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { } type RemoveDataCapProposal = verifreg7.RemoveDataCapProposal +type RemoveDataCapRequest = verifreg7.RemoveDataCapRequest +type RemoveDataCapParams = verifreg7.RemoveDataCapParams type RmDcProposalID = verifreg7.RmDcProposalID const SignatureDomainSeparation_RemoveDataCap = verifreg7.SignatureDomainSeparation_RemoveDataCap diff --git a/cli/filplus.go b/cli/filplus.go index ba2fc43a0..12584b2b8 100644 --- a/cli/filplus.go +++ b/cli/filplus.go @@ -358,12 +358,14 @@ var filplusSignRemoveDataCapProposal = &cli.Command{ return err } - msg, err := api.WalletSign(ctx, verifier, paramBuf.Bytes()) + sig, err := api.WalletSign(ctx, verifier, paramBuf.Bytes()) if err != nil { return err } - fmt.Println(hex.EncodeToString(msg.Data)) + sigBytes := append([]byte{byte(sig.Type)}, sig.Data...) + + fmt.Println(hex.EncodeToString(sigBytes)) return nil }, diff --git a/cmd/lotus-shed/verifreg.go b/cmd/lotus-shed/verifreg.go index 03be5f916..4220d2302 100644 --- a/cmd/lotus-shed/verifreg.go +++ b/cmd/lotus-shed/verifreg.go @@ -1,8 +1,11 @@ package main import ( + "encoding/hex" "fmt" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/go-state-types/big" "github.com/urfave/cli/v2" @@ -35,6 +38,7 @@ var verifRegCmd = &cli.Command{ verifRegListClientsCmd, verifRegCheckClientCmd, verifRegCheckVerifierCmd, + verifRegRemoveVerifiedClientDataCapCmd, }, } @@ -409,3 +413,115 @@ var verifRegCheckVerifierCmd = &cli.Command{ return nil }, } + +var verifRegRemoveVerifiedClientDataCapCmd = &cli.Command{ + Name: "remove-verified-client-data-cap", + Usage: "Remove data cap from verified client", + ArgsUsage: " ", + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 7 { + return fmt.Errorf("must specify seven arguments: sender, client, allowance to remove, verifier 1 ID, verifier 1 signature, verifier 2 ID, verifier 2 signature") + } + + srv, err := lcli.GetFullNodeServices(cctx) + if err != nil { + return err + } + defer srv.Close() //nolint:errcheck + + api := srv.FullNodeAPI() + ctx := lcli.ReqContext(cctx) + + sender, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return err + } + + client, err := address.NewFromString(cctx.Args().Get(1)) + if err != nil { + return err + } + + allowanceToRemove, err := types.BigFromString(cctx.Args().Get(2)) + if err != nil { + return err + } + + verifier1Addr, err := address.NewFromString(cctx.Args().Get(3)) + if err != nil { + return err + } + + verifier1Sig, err := hex.DecodeString(cctx.Args().Get(4)) + if err != nil { + return err + } + + verifier2Addr, err := address.NewFromString(cctx.Args().Get(5)) + if err != nil { + return err + } + + verifier2Sig, err := hex.DecodeString(cctx.Args().Get(6)) + if err != nil { + return err + } + + var sig1 crypto.Signature + if err := sig1.UnmarshalBinary(verifier1Sig); err != nil { + return xerrors.Errorf("couldn't unmarshal sig: %w", err) + } + + var sig2 crypto.Signature + if err := sig2.UnmarshalBinary(verifier2Sig); err != nil { + return xerrors.Errorf("couldn't unmarshal sig: %w", err) + } + + params, err := actors.SerializeParams(&verifreg.RemoveDataCapParams{ + VerifiedClientToRemove: client, + DataCapAmountToRemove: allowanceToRemove, + VerifierRequest1: verifreg.RemoveDataCapRequest{ + Verifier: verifier1Addr, + VerifierSignature: sig1, + }, + VerifierRequest2: verifreg.RemoveDataCapRequest{ + Verifier: verifier2Addr, + VerifierSignature: sig2, + }, + }) + if err != nil { + return err + } + + vrk, err := api.StateVerifiedRegistryRootKey(ctx, types.EmptyTSK) + if err != nil { + return err + } + + proto, err := api.MsigPropose(ctx, vrk, verifreg.Address, big.Zero(), sender, uint64(verifreg.Methods.RemoveVerifiedClientDataCap), params) + if err != nil { + return err + } + + sm, _, err := srv.PublishMessage(ctx, proto, false) + if err != nil { + return err + } + + msgCid := sm.Cid() + + fmt.Printf("message sent, now waiting on cid: %s\n", msgCid) + + mwait, err := api.StateWaitMsg(ctx, msgCid, uint64(cctx.Int("confidence")), build.Finality, true) + if err != nil { + return err + } + + if mwait.Receipt.ExitCode != 0 { + return fmt.Errorf("failed to removed verified data cap: %d", mwait.Receipt.ExitCode) + } + + //TODO: Internal msg might still have failed + return nil + }, +} From 5a5d1bf9aab0c8809518e7773889bb655362c380 Mon Sep 17 00:00:00 2001 From: Geoff Stuart Date: Tue, 22 Feb 2022 22:06:02 -0500 Subject: [PATCH 27/57] Updated cli docs --- documentation/en/cli-lotus.md | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/documentation/en/cli-lotus.md b/documentation/en/cli-lotus.md index e7ebf8af6..eca4e5a81 100644 --- a/documentation/en/cli-lotus.md +++ b/documentation/en/cli-lotus.md @@ -1234,12 +1234,13 @@ USAGE: lotus filplus command [command options] [arguments...] COMMANDS: - grant-datacap give allowance to the specified verified client address - list-notaries list all notaries - list-clients list all verified clients - check-client-datacap check verified client remaining bytes - check-notary-datacap check a notary's remaining bytes - help, h Shows a list of commands or help for one command + grant-datacap give allowance to the specified verified client address + list-notaries list all notaries + list-clients list all verified clients + check-client-datacap check verified client remaining bytes + check-notary-datacap check a notary's remaining bytes + sign-remove-data-cap-proposal TODO + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -1313,6 +1314,20 @@ OPTIONS: ``` +### lotus filplus sign-remove-data-cap-proposal +``` +NAME: + lotus filplus sign-remove-data-cap-proposal - TODO + +USAGE: + lotus filplus sign-remove-data-cap-proposal [command options] [arguments...] + +OPTIONS: + --id value specify the id of the Remove Data Cap Proposal (default: 0) + --help, -h show help (default: false) + +``` + ## lotus paych ``` NAME: From e9715cae3b0ca76a965640ed4a7ca18dce92922d Mon Sep 17 00:00:00 2001 From: Geoff Stuart Date: Tue, 22 Feb 2022 22:58:51 -0500 Subject: [PATCH 28/57] Small fixes --- cli/filplus.go | 59 +++++++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/cli/filplus.go b/cli/filplus.go index 12584b2b8..845b3948e 100644 --- a/cli/filplus.go +++ b/cli/filplus.go @@ -293,31 +293,52 @@ var filplusSignRemoveDataCapProposal = &cli.Command{ return fmt.Errorf("must specify three arguments: verifier 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 } - api, closer, err := GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer closer() - ctx := ReqContext(cctx) - found, _, err := checkNotary(ctx, api, verifier) if err != nil { - return err + return xerrors.Errorf("failed to check notary status: %w", err) } if !found { @@ -326,21 +347,9 @@ var filplusSignRemoveDataCapProposal = &cli.Command{ id := cctx.Uint64("id") if id == 0 { - act, err := api.StateGetActor(ctx, verifreg.Address, types.EmptyTSK) + _, id, err = st.RemoveDataCapProposalID(verifierIdAddr, clientIdAddr) if err != nil { - return err - } - - apibs := blockstore.NewAPIBlockstore(api) - store := adt.WrapStore(ctx, cbor.NewCborStore(apibs)) - - st, err := verifreg.Load(store, act) - if err != nil { - return err - } - _, id, err = st.RemoveDataCapProposalID(verifier, client) - if err != nil { - return err + return xerrors.Errorf("failed find remove data cap proposal id: %w", err) } } @@ -348,19 +357,19 @@ var filplusSignRemoveDataCapProposal = &cli.Command{ params := verifreg.RemoveDataCapProposal{ RemovalProposalID: verifreg.RmDcProposalID{ProposalID: id}, DataCapAmount: allowanceToRemove, - VerifiedClient: client, + VerifiedClient: clientIdAddr, } paramBuf := new(bytes.Buffer) paramBuf.WriteString(verifreg.SignatureDomainSeparation_RemoveDataCap) err = params.MarshalCBOR(paramBuf) if err != nil { - return err + return xerrors.Errorf("failed to marshall paramBuf: %w", err) } sig, err := api.WalletSign(ctx, verifier, paramBuf.Bytes()) if err != nil { - return err + return xerrors.Errorf("failed to sign message: %w", err) } sigBytes := append([]byte{byte(sig.Type)}, sig.Data...) From abe04c33c1183c7e94ac222183acaaf31dfd5c16 Mon Sep 17 00:00:00 2001 From: zenground0 Date: Wed, 23 Feb 2022 09:56:47 -0700 Subject: [PATCH 29/57] Fix fault tracker to handle snap deals --- api/api_storage.go | 2 +- api/proxy_gen.go | 8 +- api/version.go | 2 +- build/openrpc/miner.json.gz | Bin 12906 -> 12929 bytes cmd/lotus-miner/proving.go | 4 +- documentation/en/api-v0-methods-miner.md | 3 + extern/sector-storage/faults.go | 96 ++++++++++++----------- extern/sector-storage/mock/mock.go | 2 +- node/impl/storminer.go | 4 +- storage/wdpost_run.go | 4 +- storage/wdpost_run_test.go | 2 +- 11 files changed, 69 insertions(+), 58 deletions(-) diff --git a/api/api_storage.go b/api/api_storage.go index a66f22d04..da66a9a03 100644 --- a/api/api_storage.go +++ b/api/api_storage.go @@ -256,7 +256,7 @@ type StorageMiner interface { // the path specified when calling CreateBackup is within the base path CreateBackup(ctx context.Context, fpath string) error //perm:admin - CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, sectors []storage.SectorRef, expensive bool) (map[abi.SectorNumber]string, error) //perm:admin + CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, sectors []storage.SectorRef, update []bool, expensive bool) (map[abi.SectorNumber]string, error) //perm:admin ComputeProof(ctx context.Context, ssi []builtin.ExtendedSectorInfo, rand abi.PoStRandomness, poStEpoch abi.ChainEpoch, nv abinetwork.Version) ([]builtin.PoStProof, error) //perm:read } diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 73aa2c774..cd3e1ad35 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -627,7 +627,7 @@ type StorageMinerStruct struct { ActorSectorSize func(p0 context.Context, p1 address.Address) (abi.SectorSize, error) `perm:"read"` - CheckProvable func(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storage.SectorRef, p3 bool) (map[abi.SectorNumber]string, error) `perm:"admin"` + CheckProvable func(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storage.SectorRef, p3 []bool, p4 bool) (map[abi.SectorNumber]string, error) `perm:"admin"` ComputeProof func(p0 context.Context, p1 []builtin.ExtendedSectorInfo, p2 abi.PoStRandomness, p3 abi.ChainEpoch, p4 abinetwork.Version) ([]builtin.PoStProof, error) `perm:"read"` @@ -3760,14 +3760,14 @@ func (s *StorageMinerStub) ActorSectorSize(p0 context.Context, p1 address.Addres return *new(abi.SectorSize), ErrNotSupported } -func (s *StorageMinerStruct) CheckProvable(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storage.SectorRef, p3 bool) (map[abi.SectorNumber]string, error) { +func (s *StorageMinerStruct) CheckProvable(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storage.SectorRef, p3 []bool, p4 bool) (map[abi.SectorNumber]string, error) { if s.Internal.CheckProvable == nil { return *new(map[abi.SectorNumber]string), ErrNotSupported } - return s.Internal.CheckProvable(p0, p1, p2, p3) + return s.Internal.CheckProvable(p0, p1, p2, p3, p4) } -func (s *StorageMinerStub) CheckProvable(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storage.SectorRef, p3 bool) (map[abi.SectorNumber]string, error) { +func (s *StorageMinerStub) CheckProvable(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storage.SectorRef, p3 []bool, p4 bool) (map[abi.SectorNumber]string, error) { return *new(map[abi.SectorNumber]string), ErrNotSupported } diff --git a/api/version.go b/api/version.go index 228dcbd10..9f4f73513 100644 --- a/api/version.go +++ b/api/version.go @@ -57,7 +57,7 @@ var ( FullAPIVersion0 = newVer(1, 5, 0) FullAPIVersion1 = newVer(2, 2, 0) - MinerAPIVersion0 = newVer(1, 3, 0) + MinerAPIVersion0 = newVer(1, 4, 0) WorkerAPIVersion0 = newVer(1, 5, 0) ) diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index 4021b573d7df9e690f217a8548ac9c93933b2922..303444e99218463d0aa09b57899655163218db9a 100644 GIT binary patch delta 12156 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≀gT7 zurlaP29wcIZ!(Ip61}`FRtCxMG8}(TCjG&1(u;qZ$mMOZGJG!C96h^i9_^28j`v44 zC;K9sPn`fvy(vexSujmq+AWx>Hot8!RplcWOrMdJB$z%UE6ssvN!e@~Ov}sWcEGgK zS4e{CGqREd(`REP4W_*sV46bn-Fl`qnlBHgqpm*c_Kx}zlUsw2ur*zRru~0juiNVl z2S+_UgBe{{V&_24&nU%Dq!Ne(Qb&V9Z!pv+gMpru4!x^S2BYDqVSYyAqwZvIG&<^! zs^e;XF|CEGjfkl#uI@rilfe4iVwyzP=M~ck#Lf^EXCo)^wW|-t!=q6G{Jm=pBEK$y z*j=`r2G`xSopw!k*LK<$-Ccj%Ns!!S+ew_?kXR!E!1)e1t|z}&nsAx(Lr&nl!zfPGFOjUlXk zj~ukJumRWnNa=P>XU}+Q93+r15{XDW==?V1M|~Ynx)auPLT6=e0%DeUaK0QCmc95%q^e)HQLv z>i#X1KKI&dn-$Pz1rz{jn-#E6SpiQBN#7GVwZd)S-d@&E*lWc52_N~-kE^xVxvF=x z6aF_()ygljQ0BNmkEY7z`+#xj*)2Y!-_tMp8-W|E`H;L-@HHcs2^CWO95IcR2x3Ir6^k^+6u$gB y91)aWE7Mn%!X4GF#PO$u3~~6{W$E61t(DQ6XirbKPyasv0RR6yEy?v4c>(~l^V~52 delta 12122 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 Date: Wed, 23 Feb 2022 12:02:26 -0500 Subject: [PATCH 30/57] Handle pre-v7 case more gracefully --- chain/actors/builtin/verifreg/util.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/chain/actors/builtin/verifreg/util.go b/chain/actors/builtin/verifreg/util.go index 8d63e28c9..197a79215 100644 --- a/chain/actors/builtin/verifreg/util.go +++ b/chain/actors/builtin/verifreg/util.go @@ -63,6 +63,9 @@ func getRemoveDataCapProposalID(store adt.Store, ver actors.Version, root rootFu if err != nil { return false, 0, xerrors.Errorf("loading verifreg: %w", err) } + if vh == nil { + return false, 0, xerrors.Errorf("remove data cap proposal hamt not found. you are probably using an incompatible version of actors") + } var id verifreg.RmDcProposalID if found, err := vh.Get(abi.NewAddrPairKey(verifier, client), &id); err != nil { From 25912e72a14e5441b3b5d7c72348b4c7336c7bb7 Mon Sep 17 00:00:00 2001 From: Geoff Stuart Date: Wed, 23 Feb 2022 12:14:26 -0500 Subject: [PATCH 31/57] Update cli/filplus.go Co-authored-by: Aayush Rajasekaran --- cli/filplus.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/filplus.go b/cli/filplus.go index 845b3948e..881f5610b 100644 --- a/cli/filplus.go +++ b/cli/filplus.go @@ -284,7 +284,7 @@ var filplusSignRemoveDataCapProposal = &cli.Command{ Flags: []cli.Flag{ &cli.Int64Flag{ Name: "id", - Usage: "specify the id of the Remove Data Cap Proposal", + Usage: "specify the RemoveDataCapProposal ID (will look up on chain if unspecified)", Required: false, }, }, From ef68fdb261c4387017a10c88bb59df56eb2e816e Mon Sep 17 00:00:00 2001 From: Geoff Stuart Date: Wed, 23 Feb 2022 12:16:42 -0500 Subject: [PATCH 32/57] Update cmd/lotus-shed/verifreg.go Co-authored-by: Aayush Rajasekaran --- cmd/lotus-shed/verifreg.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/lotus-shed/verifreg.go b/cmd/lotus-shed/verifreg.go index 4220d2302..9777788cb 100644 --- a/cmd/lotus-shed/verifreg.go +++ b/cmd/lotus-shed/verifreg.go @@ -417,7 +417,7 @@ var verifRegCheckVerifierCmd = &cli.Command{ var verifRegRemoveVerifiedClientDataCapCmd = &cli.Command{ Name: "remove-verified-client-data-cap", Usage: "Remove data cap from verified client", - ArgsUsage: " ", + ArgsUsage: " ", Action: func(cctx *cli.Context) error { if cctx.Args().Len() != 7 { return fmt.Errorf("must specify seven arguments: sender, client, allowance to remove, verifier 1 ID, verifier 1 signature, verifier 2 ID, verifier 2 signature") From fd8cb44e675b08e033dc5f9b4e1ee67e3bbd5cd1 Mon Sep 17 00:00:00 2001 From: Aayush Date: Thu, 24 Feb 2022 10:27:37 -0500 Subject: [PATCH 33/57] fix: client: calculate commps for pieces bigger than 32GB --- node/impl/client/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/impl/client/client.go b/node/impl/client/client.go index 7848c84f9..1730b7a7a 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -1272,7 +1272,7 @@ func (a *API) ClientCalcCommP(ctx context.Context, inpath string) (*api.CommPRet // // IF/WHEN this changes in the future we will have to be able to calculate // "old style" commP, and thus will need to introduce a version switch or similar - arbitraryProofType := abi.RegisteredSealProof_StackedDrg32GiBV1_1 + arbitraryProofType := abi.RegisteredSealProof_StackedDrg64GiBV1_1 rdr, err := os.Open(inpath) if err != nil { From 83bf0c5a117dc5e65febbdf99ca40d5c2196a22a Mon Sep 17 00:00:00 2001 From: Geoff Stuart Date: Thu, 24 Feb 2022 12:40:13 -0500 Subject: [PATCH 34/57] Review fixes --- cli/filplus.go | 13 +++++++++--- cmd/lotus-shed/verifreg.go | 41 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/cli/filplus.go b/cli/filplus.go index 881f5610b..b3a98d487 100644 --- a/cli/filplus.go +++ b/cli/filplus.go @@ -280,7 +280,7 @@ func checkNotary(ctx context.Context, api v0api.FullNode, vaddr address.Address) var filplusSignRemoveDataCapProposal = &cli.Command{ Name: "sign-remove-data-cap-proposal", - Usage: "TODO", + Usage: "allows a notary to sign a Remove Data Cap Proposal", Flags: []cli.Flag{ &cli.Int64Flag{ Name: "id", @@ -290,7 +290,7 @@ var filplusSignRemoveDataCapProposal = &cli.Command{ }, Action: func(cctx *cli.Context) error { if cctx.Args().Len() != 3 { - return fmt.Errorf("must specify three arguments: verifier address, client address, and allowance to remove") + return fmt.Errorf("must specify three arguments: notary address, client address, and allowance to remove") } api, closer, err := GetFullNodeAPI(cctx) @@ -336,6 +336,14 @@ var filplusSignRemoveDataCapProposal = &cli.Command{ 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) @@ -353,7 +361,6 @@ var filplusSignRemoveDataCapProposal = &cli.Command{ } } - // TODO: This should be abstracted over actor versions params := verifreg.RemoveDataCapProposal{ RemovalProposalID: verifreg.RmDcProposalID{ProposalID: id}, DataCapAmount: allowanceToRemove, diff --git a/cmd/lotus-shed/verifreg.go b/cmd/lotus-shed/verifreg.go index 9777788cb..4a0664e90 100644 --- a/cmd/lotus-shed/verifreg.go +++ b/cmd/lotus-shed/verifreg.go @@ -4,6 +4,8 @@ import ( "encoding/hex" "fmt" + "github.com/filecoin-project/lotus/chain/actors/builtin/multisig" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/big" @@ -498,6 +500,45 @@ var verifRegRemoveVerifiedClientDataCapCmd = &cli.Command{ return err } + vrkState, err := api.StateGetActor(ctx, vrk, types.EmptyTSK) + if err != nil { + return err + } + + apibs := blockstore.NewAPIBlockstore(api) + store := adt.WrapStore(ctx, cbor.NewCborStore(apibs)) + + st, err := multisig.Load(store, vrkState) + if err != nil { + return err + } + + signers, err := st.Signers() + if err != nil { + return err + } + + senderIsSigner := false + senderIdAddr, err := address.IDFromAddress(sender) + if err != nil { + return err + } + + for _, signer := range signers { + signerIdAddr, err := address.IDFromAddress(signer) + if err != nil { + return err + } + + if signerIdAddr == senderIdAddr { + senderIsSigner = true + } + } + + if !senderIsSigner { + return fmt.Errorf("sender must be a vrk signer") + } + proto, err := api.MsigPropose(ctx, vrk, verifreg.Address, big.Zero(), sender, uint64(verifreg.Methods.RemoveVerifiedClientDataCap), params) if err != nil { return err From 4293023731e89148d9aaf6bddc7884b3fc548374 Mon Sep 17 00:00:00 2001 From: Geoff Stuart Date: Thu, 24 Feb 2022 12:43:02 -0500 Subject: [PATCH 35/57] Updated cli docs --- documentation/en/cli-lotus.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/en/cli-lotus.md b/documentation/en/cli-lotus.md index eca4e5a81..d136fe290 100644 --- a/documentation/en/cli-lotus.md +++ b/documentation/en/cli-lotus.md @@ -1239,7 +1239,7 @@ COMMANDS: list-clients list all verified clients check-client-datacap check verified client remaining bytes check-notary-datacap check a notary's remaining bytes - sign-remove-data-cap-proposal TODO + sign-remove-data-cap-proposal allows a notary to sign a Remove Data Cap Proposal help, h Shows a list of commands or help for one command OPTIONS: @@ -1317,13 +1317,13 @@ OPTIONS: ### lotus filplus sign-remove-data-cap-proposal ``` NAME: - lotus filplus sign-remove-data-cap-proposal - TODO + lotus filplus sign-remove-data-cap-proposal - allows a notary to sign a Remove Data Cap Proposal USAGE: lotus filplus sign-remove-data-cap-proposal [command options] [arguments...] OPTIONS: - --id value specify the id of the Remove Data Cap Proposal (default: 0) + --id value specify the RemoveDataCapProposal ID (will look up on chain if unspecified) (default: 0) --help, -h show help (default: false) ``` From e0382c546d06aaf667a9d2efd795c8462936ee24 Mon Sep 17 00:00:00 2001 From: Geoff Stuart Date: Thu, 24 Feb 2022 13:07:10 -0500 Subject: [PATCH 36/57] Update cmd/lotus-shed/verifreg.go Co-authored-by: Aayush Rajasekaran --- cmd/lotus-shed/verifreg.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/lotus-shed/verifreg.go b/cmd/lotus-shed/verifreg.go index 4a0664e90..fb2598fda 100644 --- a/cmd/lotus-shed/verifreg.go +++ b/cmd/lotus-shed/verifreg.go @@ -422,7 +422,7 @@ var verifRegRemoveVerifiedClientDataCapCmd = &cli.Command{ ArgsUsage: " ", Action: func(cctx *cli.Context) error { if cctx.Args().Len() != 7 { - return fmt.Errorf("must specify seven arguments: sender, client, allowance to remove, verifier 1 ID, verifier 1 signature, verifier 2 ID, verifier 2 signature") + return fmt.Errorf("must specify seven arguments: sender, client, allowance to remove, verifier 1 address, verifier 1 signature, verifier 2 address, verifier 2 signature") } srv, err := lcli.GetFullNodeServices(cctx) From f9641d70afd37ca4db9aca946f688e329da352c4 Mon Sep 17 00:00:00 2001 From: Jiaying Wang <42981373+jennijuju@users.noreply.github.com> Date: Thu, 24 Feb 2022 16:27:24 -0500 Subject: [PATCH 37/57] fix: sealing: missing file type --- extern/sector-storage/stores/http_handler.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/extern/sector-storage/stores/http_handler.go b/extern/sector-storage/stores/http_handler.go index 771a9a3a1..80fa87408 100644 --- a/extern/sector-storage/stores/http_handler.go +++ b/extern/sector-storage/stores/http_handler.go @@ -294,6 +294,10 @@ func ftFromString(t string) (storiface.SectorFileType, error) { return storiface.FTSealed, nil case storiface.FTCache.String(): return storiface.FTCache, nil + case storiface.FTUpdate.String(): + return storiface.FTUpdate, nil + case storiface.FTUpdateCache.String(): + return storiface.FTUpdateCache, nil default: return 0, xerrors.Errorf("unknown sector file type: '%s'", t) } From 367146f03207cff32bad2537cf295c5c6d6a4031 Mon Sep 17 00:00:00 2001 From: zenground0 Date: Thu, 24 Feb 2022 15:20:21 -0700 Subject: [PATCH 38/57] add rdi flag for abort upgrade --- cmd/lotus-miner/sectors.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmd/lotus-miner/sectors.go b/cmd/lotus-miner/sectors.go index d8c3e9c7c..89e282d00 100644 --- a/cmd/lotus-miner/sectors.go +++ b/cmd/lotus-miner/sectors.go @@ -1540,6 +1540,12 @@ var sectorsSnapAbortCmd = &cli.Command{ return lcli.ShowHelp(cctx, xerrors.Errorf("must pass sector number")) } + really := cctx.Bool("really-do-it") + if !really { + //nolint:golint + return fmt.Errorf("--really-do-it must be specified for this action to have an effect; you have been warned") + } + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) if err != nil { return err From 77bf46d018039d1709730f05ab0cb87920d63643 Mon Sep 17 00:00:00 2001 From: zenground0 Date: Thu, 24 Feb 2022 15:46:15 -0700 Subject: [PATCH 39/57] Tiny clean up --- chain/wallet/multi_test.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/chain/wallet/multi_test.go b/chain/wallet/multi_test.go index 54ff240c5..d6fdf6656 100644 --- a/chain/wallet/multi_test.go +++ b/chain/wallet/multi_test.go @@ -61,14 +61,13 @@ func TestMultiWallet(t *testing.T) { t.Fatal(err) } + if addr != a1 { + t.Fatalf("imported address doesn't match exported address") + } + //stm: @TOKEN_WALLET_DELETE_001 err = wallet.WalletDelete(ctx, a1) if err != nil { t.Fatal(err) } - - if addr != a1 { - t.Fatalf("imported address doesn't match exported address") - } - } From e5de2379903aa84865cb6ad4c080156adc3f27ef Mon Sep 17 00:00:00 2001 From: zenground0 Date: Wed, 23 Feb 2022 09:56:47 -0700 Subject: [PATCH 40/57] Fix fault tracker to handle snap deals --- api/api_storage.go | 2 +- api/proxy_gen.go | 8 +- api/version.go | 2 +- build/openrpc/miner.json.gz | Bin 11745 -> 11768 bytes cmd/lotus-miner/proving.go | 4 +- documentation/en/api-v0-methods-miner.md | 1 + extern/sector-storage/faults.go | 96 ++++++++++++----------- extern/sector-storage/mock/mock.go | 2 +- node/impl/storminer.go | 4 +- storage/wdpost_run.go | 4 +- storage/wdpost_run_test.go | 2 +- 11 files changed, 67 insertions(+), 58 deletions(-) diff --git a/api/api_storage.go b/api/api_storage.go index 398921e40..762b18b37 100644 --- a/api/api_storage.go +++ b/api/api_storage.go @@ -253,7 +253,7 @@ type StorageMiner interface { // the path specified when calling CreateBackup is within the base path CreateBackup(ctx context.Context, fpath string) error //perm:admin - CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, sectors []storage.SectorRef, expensive bool) (map[abi.SectorNumber]string, error) //perm:admin + CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, sectors []storage.SectorRef, update []bool, expensive bool) (map[abi.SectorNumber]string, error) //perm:admin ComputeProof(ctx context.Context, ssi []builtin.ExtendedSectorInfo, rand abi.PoStRandomness, poStEpoch abi.ChainEpoch, nv abinetwork.Version) ([]builtin.PoStProof, error) //perm:read } diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 0eecb27b9..4353da5fe 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -619,7 +619,7 @@ type StorageMinerStruct struct { ActorSectorSize func(p0 context.Context, p1 address.Address) (abi.SectorSize, error) `perm:"read"` - CheckProvable func(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storage.SectorRef, p3 bool) (map[abi.SectorNumber]string, error) `perm:"admin"` + CheckProvable func(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storage.SectorRef, p3 []bool, p4 bool) (map[abi.SectorNumber]string, error) `perm:"admin"` ComputeProof func(p0 context.Context, p1 []builtin.ExtendedSectorInfo, p2 abi.PoStRandomness, p3 abi.ChainEpoch, p4 abinetwork.Version) ([]builtin.PoStProof, error) `perm:"read"` @@ -3704,14 +3704,14 @@ func (s *StorageMinerStub) ActorSectorSize(p0 context.Context, p1 address.Addres return *new(abi.SectorSize), ErrNotSupported } -func (s *StorageMinerStruct) CheckProvable(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storage.SectorRef, p3 bool) (map[abi.SectorNumber]string, error) { +func (s *StorageMinerStruct) CheckProvable(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storage.SectorRef, p3 []bool, p4 bool) (map[abi.SectorNumber]string, error) { if s.Internal.CheckProvable == nil { return *new(map[abi.SectorNumber]string), ErrNotSupported } - return s.Internal.CheckProvable(p0, p1, p2, p3) + return s.Internal.CheckProvable(p0, p1, p2, p3, p4) } -func (s *StorageMinerStub) CheckProvable(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storage.SectorRef, p3 bool) (map[abi.SectorNumber]string, error) { +func (s *StorageMinerStub) CheckProvable(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storage.SectorRef, p3 []bool, p4 bool) (map[abi.SectorNumber]string, error) { return *new(map[abi.SectorNumber]string), ErrNotSupported } diff --git a/api/version.go b/api/version.go index 228dcbd10..9f4f73513 100644 --- a/api/version.go +++ b/api/version.go @@ -57,7 +57,7 @@ var ( FullAPIVersion0 = newVer(1, 5, 0) FullAPIVersion1 = newVer(2, 2, 0) - MinerAPIVersion0 = newVer(1, 3, 0) + MinerAPIVersion0 = newVer(1, 4, 0) WorkerAPIVersion0 = newVer(1, 5, 0) ) diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index e4cd5c9b827614c3e277177091a8fa58f50b23a2..2120341d7f19c16dc00be611c070fd72dc2d5ccc 100644 GIT binary patch delta 10025 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 delta 9985 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

PlB3d;NjA|f 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

(l=a00960 LUd>|=E=K|YSdc&B diff --git a/cmd/lotus-miner/proving.go b/cmd/lotus-miner/proving.go index ee15785fe..f8c23a1c9 100644 --- a/cmd/lotus-miner/proving.go +++ b/cmd/lotus-miner/proving.go @@ -437,6 +437,7 @@ var provingCheckProvableCmd = &cli.Command{ } var tocheck []storage.SectorRef + var update []bool for _, info := range sectorInfos { si := abi.SectorID{ Miner: abi.ActorID(mid), @@ -454,9 +455,10 @@ var provingCheckProvableCmd = &cli.Command{ ProofType: info.SealProof, ID: si, }) + update = append(update, info.SectorKeyCID != nil) } - bad, err := sapi.CheckProvable(ctx, info.WindowPoStProofType, tocheck, cctx.Bool("slow")) + bad, err := sapi.CheckProvable(ctx, info.WindowPoStProofType, tocheck, update, cctx.Bool("slow")) if err != nil { return err } diff --git a/documentation/en/api-v0-methods-miner.md b/documentation/en/api-v0-methods-miner.md index f9982d697..5837ab039 100644 --- a/documentation/en/api-v0-methods-miner.md +++ b/documentation/en/api-v0-methods-miner.md @@ -310,6 +310,7 @@ Inputs: [ 8, null, + null, true ] ``` diff --git a/extern/sector-storage/faults.go b/extern/sector-storage/faults.go index f7a764e50..5c542055b 100644 --- a/extern/sector-storage/faults.go +++ b/extern/sector-storage/faults.go @@ -19,11 +19,11 @@ import ( // FaultTracker TODO: Track things more actively type FaultTracker interface { - CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, sectors []storage.SectorRef, rg storiface.RGetter) (map[abi.SectorID]string, error) + CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, sectors []storage.SectorRef, update []bool, rg storiface.RGetter) (map[abi.SectorID]string, error) } // CheckProvable returns unprovable sectors -func (m *Manager) CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, sectors []storage.SectorRef, rg storiface.RGetter) (map[abi.SectorID]string, error) { +func (m *Manager) CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, sectors []storage.SectorRef, update []bool, rg storiface.RGetter) (map[abi.SectorID]string, error) { var bad = make(map[abi.SectorID]string) ssize, err := pp.SectorSize() @@ -32,72 +32,76 @@ func (m *Manager) CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, } // TODO: More better checks - for _, sector := range sectors { + for i, sector := range sectors { err := func() error { ctx, cancel := context.WithCancel(ctx) defer cancel() + var fReplica string + var fCache string - locked, err := m.index.StorageTryLock(ctx, sector.ID, storiface.FTSealed|storiface.FTCache, storiface.FTNone) - if err != nil { - return xerrors.Errorf("acquiring sector lock: %w", err) - } - - if !locked { - log.Warnw("CheckProvable Sector FAULT: can't acquire read lock", "sector", sector) - bad[sector.ID] = fmt.Sprint("can't acquire read lock") - return nil - } - - lp, _, err := m.localStore.AcquireSector(ctx, sector, storiface.FTSealed|storiface.FTCache, storiface.FTNone, storiface.PathStorage, storiface.AcquireMove) - if err != nil { - log.Warnw("CheckProvable Sector FAULT: acquire sector in checkProvable", "sector", sector, "error", err) - bad[sector.ID] = fmt.Sprintf("acquire sector failed: %s", err) - return nil - } - - // temporary hack to make the check work with snapdeals - // will go away in https://github.com/filecoin-project/lotus/pull/7971 - if lp.Sealed == "" || lp.Cache == "" { - // maybe it's update + if update[i] { lockedUpdate, err := m.index.StorageTryLock(ctx, sector.ID, storiface.FTUpdate|storiface.FTUpdateCache, storiface.FTNone) if err != nil { return xerrors.Errorf("acquiring sector lock: %w", err) } - if lockedUpdate { - lp, _, err = m.localStore.AcquireSector(ctx, sector, storiface.FTUpdate|storiface.FTUpdateCache, storiface.FTNone, storiface.PathStorage, storiface.AcquireMove) - if err != nil { - log.Warnw("CheckProvable Sector FAULT: acquire sector in checkProvable", "sector", sector, "error", err) - bad[sector.ID] = fmt.Sprintf("acquire sector failed: %s", err) - return nil - } - lp.Sealed, lp.Cache = lp.Update, lp.UpdateCache + if !lockedUpdate { + log.Warnw("CheckProvable Sector FAULT: can't acquire read lock on update replica", "sector", sector) + bad[sector.ID] = fmt.Sprint("can't acquire read lock") + return nil } + lp, _, err := m.localStore.AcquireSector(ctx, sector, storiface.FTUpdate|storiface.FTUpdateCache, storiface.FTNone, storiface.PathStorage, storiface.AcquireMove) + if err != nil { + log.Warnw("CheckProvable Sector FAULT: acquire sector update replica in checkProvable", "sector", sector, "error", err) + bad[sector.ID] = fmt.Sprintf("acquire sector failed: %s", err) + return nil + } + fReplica, fCache = lp.Update, lp.UpdateCache + } else { + locked, err := m.index.StorageTryLock(ctx, sector.ID, storiface.FTSealed|storiface.FTCache, storiface.FTNone) + if err != nil { + return xerrors.Errorf("acquiring sector lock: %w", err) + } + + if !locked { + log.Warnw("CheckProvable Sector FAULT: can't acquire read lock", "sector", sector) + bad[sector.ID] = fmt.Sprint("can't acquire read lock") + return nil + } + + lp, _, err := m.localStore.AcquireSector(ctx, sector, storiface.FTSealed|storiface.FTCache, storiface.FTNone, storiface.PathStorage, storiface.AcquireMove) + if err != nil { + log.Warnw("CheckProvable Sector FAULT: acquire sector in checkProvable", "sector", sector, "error", err) + bad[sector.ID] = fmt.Sprintf("acquire sector failed: %s", err) + return nil + } + fReplica, fCache = lp.Sealed, lp.Cache + } - if lp.Sealed == "" || lp.Cache == "" { - log.Warnw("CheckProvable Sector FAULT: cache and/or sealed paths not found", "sector", sector, "sealed", lp.Sealed, "cache", lp.Cache) - bad[sector.ID] = fmt.Sprintf("cache and/or sealed paths not found, cache %q, sealed %q", lp.Cache, lp.Sealed) + if fReplica == "" || fCache == "" { + log.Warnw("CheckProvable Sector FAULT: cache and/or sealed paths not found", "sector", sector, "sealed", fReplica, "cache", fCache) + bad[sector.ID] = fmt.Sprintf("cache and/or sealed paths not found, cache %q, sealed %q", fCache, fReplica) return nil } toCheck := map[string]int64{ - lp.Sealed: 1, - filepath.Join(lp.Cache, "p_aux"): 0, + fReplica: 1, + filepath.Join(fCache, "p_aux"): 0, } - addCachePathsForSectorSize(toCheck, lp.Cache, ssize) + addCachePathsForSectorSize(toCheck, fCache, ssize) for p, sz := range toCheck { st, err := os.Stat(p) if err != nil { - log.Warnw("CheckProvable Sector FAULT: sector file stat error", "sector", sector, "sealed", lp.Sealed, "cache", lp.Cache, "file", p, "err", err) + log.Warnw("CheckProvable Sector FAULT: sector file stat error", "sector", sector, "sealed", fReplica, "cache", fCache, "file", p, "err", err) bad[sector.ID] = fmt.Sprintf("%s", err) return nil } if sz != 0 { if st.Size() != int64(ssize)*sz { - log.Warnw("CheckProvable Sector FAULT: sector file is wrong size", "sector", sector, "sealed", lp.Sealed, "cache", lp.Cache, "file", p, "size", st.Size(), "expectSize", int64(ssize)*sz) + log.Warnw("CheckProvable Sector FAULT: sector file is wrong size", "sector", sector, "sealed", fReplica, "cache", fCache, "file", p, "size", st.Size(), "expectSize", int64(ssize)*sz) bad[sector.ID] = fmt.Sprintf("%s is wrong size (got %d, expect %d)", p, st.Size(), int64(ssize)*sz) return nil } @@ -118,14 +122,14 @@ func (m *Manager) CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, sector.ID.Number, }) if err != nil { - log.Warnw("CheckProvable Sector FAULT: generating challenges", "sector", sector, "sealed", lp.Sealed, "cache", lp.Cache, "err", err) + log.Warnw("CheckProvable Sector FAULT: generating challenges", "sector", sector, "sealed", fReplica, "cache", fCache, "err", err) bad[sector.ID] = fmt.Sprintf("generating fallback challenges: %s", err) return nil } commr, err := rg(ctx, sector.ID) if err != nil { - log.Warnw("CheckProvable Sector FAULT: getting commR", "sector", sector, "sealed", lp.Sealed, "cache", lp.Cache, "err", err) + log.Warnw("CheckProvable Sector FAULT: getting commR", "sector", sector, "sealed", fReplica, "cache", fCache, "err", err) bad[sector.ID] = fmt.Sprintf("getting commR: %s", err) return nil } @@ -136,12 +140,12 @@ func (m *Manager) CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, SectorNumber: sector.ID.Number, SealedCID: commr, }, - CacheDirPath: lp.Cache, + CacheDirPath: fCache, PoStProofType: wpp, - SealedSectorPath: lp.Sealed, + SealedSectorPath: fReplica, }, ch.Challenges[sector.ID.Number]) if err != nil { - log.Warnw("CheckProvable Sector FAULT: generating vanilla proof", "sector", sector, "sealed", lp.Sealed, "cache", lp.Cache, "err", err) + log.Warnw("CheckProvable Sector FAULT: generating vanilla proof", "sector", sector, "sealed", fReplica, "cache", fCache, "err", err) bad[sector.ID] = fmt.Sprintf("generating vanilla proof: %s", err) return nil } diff --git a/extern/sector-storage/mock/mock.go b/extern/sector-storage/mock/mock.go index 771265176..20abad309 100644 --- a/extern/sector-storage/mock/mock.go +++ b/extern/sector-storage/mock/mock.go @@ -505,7 +505,7 @@ func (mgr *SectorMgr) Remove(ctx context.Context, sector storage.SectorRef) erro return nil } -func (mgr *SectorMgr) CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, ids []storage.SectorRef, rg storiface.RGetter) (map[abi.SectorID]string, error) { +func (mgr *SectorMgr) CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, ids []storage.SectorRef, update []bool, rg storiface.RGetter) (map[abi.SectorID]string, error) { bad := map[abi.SectorID]string{} for _, sid := range ids { diff --git a/node/impl/storminer.go b/node/impl/storminer.go index e99003a18..3ea2f115f 100644 --- a/node/impl/storminer.go +++ b/node/impl/storminer.go @@ -960,7 +960,7 @@ func (sm *StorageMinerAPI) CreateBackup(ctx context.Context, fpath string) error return backup(sm.DS, fpath) } -func (sm *StorageMinerAPI) CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, sectors []sto.SectorRef, expensive bool) (map[abi.SectorNumber]string, error) { +func (sm *StorageMinerAPI) CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, sectors []sto.SectorRef, update []bool, expensive bool) (map[abi.SectorNumber]string, error) { var rg storiface.RGetter if expensive { rg = func(ctx context.Context, id abi.SectorID) (cid.Cid, error) { @@ -976,7 +976,7 @@ func (sm *StorageMinerAPI) CheckProvable(ctx context.Context, pp abi.RegisteredP } } - bad, err := sm.StorageMgr.CheckProvable(ctx, pp, sectors, rg) + bad, err := sm.StorageMgr.CheckProvable(ctx, pp, sectors, update, rg) if err != nil { return nil, err } diff --git a/storage/wdpost_run.go b/storage/wdpost_run.go index 0ba7b21e1..f0d557d12 100644 --- a/storage/wdpost_run.go +++ b/storage/wdpost_run.go @@ -205,6 +205,7 @@ func (s *WindowPoStScheduler) checkSectors(ctx context.Context, check bitfield.B sectors := make(map[abi.SectorNumber]struct{}) var tocheck []storage.SectorRef + var update []bool for _, info := range sectorInfos { sectors[info.SectorNumber] = struct{}{} tocheck = append(tocheck, storage.SectorRef{ @@ -214,9 +215,10 @@ func (s *WindowPoStScheduler) checkSectors(ctx context.Context, check bitfield.B Number: info.SectorNumber, }, }) + update = append(update, info.SectorKeyCID != nil) } - bad, err := s.faultTracker.CheckProvable(ctx, s.proofType, tocheck, nil) + bad, err := s.faultTracker.CheckProvable(ctx, s.proofType, tocheck, update, nil) if err != nil { return bitfield.BitField{}, xerrors.Errorf("checking provable sectors: %w", err) } diff --git a/storage/wdpost_run_test.go b/storage/wdpost_run_test.go index f3ea5836b..41ce5a2e9 100644 --- a/storage/wdpost_run_test.go +++ b/storage/wdpost_run_test.go @@ -168,7 +168,7 @@ func (m mockVerif) GenerateWinningPoStSectorChallenge(context.Context, abi.Regis type mockFaultTracker struct { } -func (m mockFaultTracker) CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, sectors []storage.SectorRef, rg storiface.RGetter) (map[abi.SectorID]string, error) { +func (m mockFaultTracker) CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, sectors []storage.SectorRef, update []bool, rg storiface.RGetter) (map[abi.SectorID]string, error) { // Returns "bad" sectors so just return empty map meaning all sectors are good return map[abi.SectorID]string{}, nil } From 6862015929fafd7b8be7fa6803fccd89731d5954 Mon Sep 17 00:00:00 2001 From: zenground0 Date: Thu, 24 Feb 2022 15:20:21 -0700 Subject: [PATCH 41/57] add rdi flag for abort upgrade --- cmd/lotus-miner/sectors.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmd/lotus-miner/sectors.go b/cmd/lotus-miner/sectors.go index 9c4a5d0d8..a5ab14c82 100644 --- a/cmd/lotus-miner/sectors.go +++ b/cmd/lotus-miner/sectors.go @@ -1530,6 +1530,12 @@ var sectorsSnapAbortCmd = &cli.Command{ return lcli.ShowHelp(cctx, xerrors.Errorf("must pass sector number")) } + really := cctx.Bool("really-do-it") + if !really { + //nolint:golint + return fmt.Errorf("--really-do-it must be specified for this action to have an effect; you have been warned") + } + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) if err != nil { return err From be3462eb761a22c4651182b1987287160de27890 Mon Sep 17 00:00:00 2001 From: "eben.xie" Date: Wed, 23 Feb 2022 10:49:53 +0800 Subject: [PATCH 42/57] [Describe]: when excute cmd "lotus-bench sealing" without "benchmark-existing-sectorbuilder", panic will occur [BugFix]: [FeatureAdd]: [CodeReview]: [ModifyDesc]: [Author]: [BugID]: --- cmd/lotus-bench/main.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cmd/lotus-bench/main.go b/cmd/lotus-bench/main.go index b0e71b90e..c6fdd5e32 100644 --- a/cmd/lotus-bench/main.go +++ b/cmd/lotus-bench/main.go @@ -276,6 +276,13 @@ var sealBenchCmd = &cli.Command{ if err != nil { return xerrors.Errorf("failed to run seals: %w", err) } + for _, s := range extendedSealedSectors { + sealedSectors = append(sealedSectors, proof.SectorInfo{ + SealedCID: s.SealedCID, + SectorNumber: s.SectorNumber, + SealProof: s.SealProof, + }) + } } else { // TODO: implement sbfs.List() and use that for all cases (preexisting sectorbuilder or not) From 3c366160bb60453443f262b45dee530128bbfc37 Mon Sep 17 00:00:00 2001 From: Peter Rabbitson Date: Sat, 19 Feb 2022 16:25:18 +0100 Subject: [PATCH 43/57] Retract force-pushed v1.14.0 to work around stale gomod caches --- go.mod | 2 ++ 1 file changed, 2 insertions(+) diff --git a/go.mod b/go.mod index 9edf85a52..25f0665ad 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,8 @@ module github.com/filecoin-project/lotus go 1.16 +retract v1.14.0 // Accidentally force-pushed tag, use v1.14.1+ instead. + require ( contrib.go.opencensus.io/exporter/jaeger v0.2.1 contrib.go.opencensus.io/exporter/prometheus v0.4.0 From 51fc965bebd7796a57b19901ea3113ec50c2eb60 Mon Sep 17 00:00:00 2001 From: Jennifer Wang Date: Thu, 24 Feb 2022 18:12:36 -0500 Subject: [PATCH 44/57] ayyush sucks at math with time --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6098a615..7a69ef900 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,8 @@ It is recommended that storage providers download the new params before updating - run `./lotus-shed fetch-params` with the appropriate `proving-params` flag - Upgrade the Lotus daemon and miner **when the previous step is complete** -All node operators, including storage providers, should be aware that a pre-migration will begin at 2022-03-01T13:30:00Z (150 minutes before the real upgrade). The pre-migration will take between 20 and 50 minutes, depending on hardware specs. During this time, expect slower block validation times, increased CPU and memory usage, and longer delays for API queries. +All node operators, including storage providers, should be aware that a pre-migration will begin at 2022-03-01T13:30:00Z (90 minutes before the real upgrade). The pre-migration will take between 20 and 50 minutes, +depending on hardware specs. During this time, expect slower block validation times, increased CPU and memory usage, and longer delays for API queries. ## New Features and Changes - Integrate actor v7-rc1: From a567a745b29f90b6a54c1a1911006ba1e19905a8 Mon Sep 17 00:00:00 2001 From: Jennifer Wang Date: Thu, 24 Feb 2022 18:30:31 -0500 Subject: [PATCH 45/57] bump the version to v1.14.2 --- build/openrpc/full.json.gz | Bin 25706 -> 25706 bytes build/openrpc/miner.json.gz | Bin 11768 -> 11768 bytes build/openrpc/worker.json.gz | Bin 3846 -> 3845 bytes build/version.go | 2 +- documentation/en/cli-lotus-miner.md | 2 +- documentation/en/cli-lotus-worker.md | 2 +- documentation/en/cli-lotus.md | 2 +- 7 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index af980b822822ac72d5957b3d032716c8f83d8b9b..d6f1437743b300f25103a5f74057caeaff6a4d93 100644 GIT binary patch delta 22 ecmaELg7MV}#tB`F-!^vNNMq>VVG1(< delta 22 ecmaELg7MV}#tB`FUp98%NM`?@ER@B~$^Za|T?yI% diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index 2120341d7f19c16dc00be611c070fd72dc2d5ccc..676bd4d72b0ab84c251f62902faa5fc1061b4748 100644 GIT binary patch delta 21 dcmewn{Udrp3**9#t=YO9S59gCx$n-z004V83LO9d delta 21 dcmewn{Udrp3uEKP)@)r4cFEb7?z=NF003|p2*>~c diff --git a/build/openrpc/worker.json.gz b/build/openrpc/worker.json.gz index 34d68c8b325a588c9bbf20ecbe934fefde29f04b..84c7626f7b0f83752db042c59e80910a3214a92e 100644 GIT binary patch delta 3753 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 delta 3754 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 UeYgI900030{|lEULIvai0GM@IcK`qY diff --git a/build/version.go b/build/version.go index fd790a795..0b7822e30 100644 --- a/build/version.go +++ b/build/version.go @@ -37,7 +37,7 @@ func BuildTypeString() string { } // BuildVersion is the local build version -const BuildVersion = "1.14.1" +const BuildVersion = "1.14.2" func UserVersion() string { if os.Getenv("LOTUS_VERSION_IGNORE_COMMIT") == "1" { diff --git a/documentation/en/cli-lotus-miner.md b/documentation/en/cli-lotus-miner.md index dc7ba1bea..bb9589401 100644 --- a/documentation/en/cli-lotus-miner.md +++ b/documentation/en/cli-lotus-miner.md @@ -7,7 +7,7 @@ USAGE: lotus-miner [global options] command [command options] [arguments...] VERSION: - 1.14.1 + 1.14.2 COMMANDS: init Initialize a lotus miner repo diff --git a/documentation/en/cli-lotus-worker.md b/documentation/en/cli-lotus-worker.md index 09cd157e9..6c5886d4c 100644 --- a/documentation/en/cli-lotus-worker.md +++ b/documentation/en/cli-lotus-worker.md @@ -7,7 +7,7 @@ USAGE: lotus-worker [global options] command [command options] [arguments...] VERSION: - 1.14.1 + 1.14.2 COMMANDS: run Start lotus worker diff --git a/documentation/en/cli-lotus.md b/documentation/en/cli-lotus.md index f2a0542d6..ed885bd6e 100644 --- a/documentation/en/cli-lotus.md +++ b/documentation/en/cli-lotus.md @@ -7,7 +7,7 @@ USAGE: lotus [global options] command [command options] [arguments...] VERSION: - 1.14.1 + 1.14.2 COMMANDS: daemon Start a lotus daemon process From 5cfe8f315f41e726984035ffdb49a9e183cf0dbe Mon Sep 17 00:00:00 2001 From: Jennifer Wang Date: Thu, 24 Feb 2022 18:30:52 -0500 Subject: [PATCH 46/57] add changelog --- CHANGELOG.md | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a69ef900..f0e90b7c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,32 @@ # Lotus changelog +# 1.14.2 / 2022-02-24 + +This is an **optional** release of lotus, that's had a couple more improvements w.r.t Snap experience for storage providers in preparation of the[upcoming OhSnap upgrade](https://github.com/filecoin-project/community/discussions/74?sort=new#discussioncomment-1922550). + +Wanna know how to Snap your deal? Check [this](https://github.com/filecoin-project/lotus/discussions/8141) out! + +## Bug Fixes +- fix lotus-bench for sealing jobs (#8173) +- fix:sealing:really-do-it flag for abort upgrade (#8181) +- fix:proving:post check sector handles snap deals replica faults (#8177) +- fix: sealing: missing file type (#8180) + +## Others +- Retract force-pushed v1.14.0 to work around stale gomod caches (#8159): We originally tagged v1.14.0 off the wrong + commit and fixed that by a force push, in which is a really bad practise since it messes up the go mod. Therefore, + we want to retract it and users may use v1.14.1&^. + +## Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| @zenground0 | 2 | +73/-58 | 12 | +| @eben.xie | 1 | +7/-0 | 1 | +| @jennijuju | 1 | +4/-0 | 1 | +| @jennijuju | 1 | +2/-1 | 1 | +| @ribasushi | 1 | +2/-0 | 1 | + # 1.14.1 / 2022-02-18 This is an **optional** release of lotus, that fixes the incorrect *comment* of network v15 OhSnap upgrade **date**. Note the actual upgrade epoch in [v1.14.0](https://github.com/filecoin-project/lotus/releases/tag/v1.14.0) was correct. @@ -22,8 +49,7 @@ It is recommended that storage providers download the new params before updating - run `./lotus-shed fetch-params` with the appropriate `proving-params` flag - Upgrade the Lotus daemon and miner **when the previous step is complete** -All node operators, including storage providers, should be aware that a pre-migration will begin at 2022-03-01T13:30:00Z (90 minutes before the real upgrade). The pre-migration will take between 20 and 50 minutes, -depending on hardware specs. During this time, expect slower block validation times, increased CPU and memory usage, and longer delays for API queries. +All node operators, including storage providers, should be aware that a pre-migration will begin at 2022-03-01T13:30:00Z (90 minutes before the real upgrade). The pre-migration will take between 20 and 50 minutes, depending on hardware specs. During this time, expect slower block validation times, increased CPU and memory usage, and longer delays for API queries. ## New Features and Changes - Integrate actor v7-rc1: From 37b857a0b261124f44fa5055f5258d4c6f5ed98c Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Thu, 24 Feb 2022 19:17:33 -0500 Subject: [PATCH 47/57] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0e90b7c8..629635c1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ This is an **optional** release of lotus, that's had a couple more improvements w.r.t Snap experience for storage providers in preparation of the[upcoming OhSnap upgrade](https://github.com/filecoin-project/community/discussions/74?sort=new#discussioncomment-1922550). +Note that the network is STILL scheduled to upgrade to v15 on March 1st at 2022-03-01T15:00:00Z. All node operators, including storage providers, must upgrade to at least Lotus v1.14.0 before that time. Storage providers must update their daemons, miners, and worker(s). + Wanna know how to Snap your deal? Check [this](https://github.com/filecoin-project/lotus/discussions/8141) out! ## Bug Fixes From 52756128da643dc3193738a354d97733eecb038c Mon Sep 17 00:00:00 2001 From: jennijuju Date: Fri, 25 Feb 2022 10:28:47 -0500 Subject: [PATCH 48/57] add flag usage --- cmd/lotus-miner/sectors.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmd/lotus-miner/sectors.go b/cmd/lotus-miner/sectors.go index 89e282d00..24098b558 100644 --- a/cmd/lotus-miner/sectors.go +++ b/cmd/lotus-miner/sectors.go @@ -1535,6 +1535,12 @@ var sectorsSnapAbortCmd = &cli.Command{ Name: "abort-upgrade", Usage: "Abort the attempted (SnapDeals) upgrade of a CC sector, reverting it to as before", ArgsUsage: "", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "really-do-it", + Usage: "pass this flag if you know what you are doing", + }, + }, Action: func(cctx *cli.Context) error { if cctx.Args().Len() != 1 { return lcli.ShowHelp(cctx, xerrors.Errorf("must pass sector number")) From 865c7e587cd6ec0ae8c6a51b7e32f072aae8ed18 Mon Sep 17 00:00:00 2001 From: jennijuju Date: Fri, 25 Feb 2022 10:48:08 -0500 Subject: [PATCH 49/57] make gen --- documentation/en/cli-lotus-miner.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/documentation/en/cli-lotus-miner.md b/documentation/en/cli-lotus-miner.md index 848a9c864..f455aeace 100644 --- a/documentation/en/cli-lotus-miner.md +++ b/documentation/en/cli-lotus-miner.md @@ -1826,7 +1826,8 @@ USAGE: lotus-miner sectors abort-upgrade [command options] OPTIONS: - --help, -h show help (default: false) + --really-do-it pass this flag if you know what you are doing (default: false) + --help, -h show help (default: false) ``` From 254f821564f439548512471dc347816bc517a7c3 Mon Sep 17 00:00:00 2001 From: jennijuju Date: Fri, 25 Feb 2022 21:03:46 -0500 Subject: [PATCH 50/57] get actor v7 (same commit as v7-rc1) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7b6e72575..344bcd7e2 100644 --- a/go.mod +++ b/go.mod @@ -52,7 +52,7 @@ require ( github.com/filecoin-project/specs-actors/v4 v4.0.1 github.com/filecoin-project/specs-actors/v5 v5.0.4 github.com/filecoin-project/specs-actors/v6 v6.0.1 - github.com/filecoin-project/specs-actors/v7 v7.0.0-rc1 + github.com/filecoin-project/specs-actors/v7 v7.0.0 github.com/filecoin-project/specs-storage v0.2.0 github.com/filecoin-project/test-vectors/schema v0.0.5 github.com/gbrlsnchs/jwt/v3 v3.0.1 diff --git a/go.sum b/go.sum index 417267e37..15fa2807b 100644 --- a/go.sum +++ b/go.sum @@ -380,8 +380,8 @@ github.com/filecoin-project/specs-actors/v6 v6.0.1 h1:laxvHNsvrq83Y9n+W7znVCePi3 github.com/filecoin-project/specs-actors/v6 v6.0.1/go.mod h1:V1AYfi5GkHXipx1mnVivoICZh3wtwPxDVuds+fbfQtk= github.com/filecoin-project/specs-actors/v7 v7.0.0-20211117170924-fd07a4c7dff9/go.mod h1:p6LIOFezA1rgRLMewbvdi3Pp6SAu+q9FtJ9CAleSjrE= github.com/filecoin-project/specs-actors/v7 v7.0.0-20211222192039-c83bea50c402/go.mod h1:p6LIOFezA1rgRLMewbvdi3Pp6SAu+q9FtJ9CAleSjrE= -github.com/filecoin-project/specs-actors/v7 v7.0.0-rc1 h1:FuDaXIbcw2hRsFI8SDTmsGGCE+NumpF6aiBoU/2X5W4= -github.com/filecoin-project/specs-actors/v7 v7.0.0-rc1/go.mod h1:TA5FwCna+Yi36POaT7SLKXsgEDvJwc0V/L6ZsO19B9M= +github.com/filecoin-project/specs-actors/v7 v7.0.0 h1:FQN7tjt3o68hfb3qLFSJBoLMuOFY0REkFVLO/zXj8RU= +github.com/filecoin-project/specs-actors/v7 v7.0.0/go.mod h1:TA5FwCna+Yi36POaT7SLKXsgEDvJwc0V/L6ZsO19B9M= github.com/filecoin-project/specs-storage v0.2.0 h1:Y4UDv0apRQ3zI2GiPPubi8JblpUZZphEdaJUxCutfyg= github.com/filecoin-project/specs-storage v0.2.0/go.mod h1:Tb88Zq+IBJbvAn3mS89GYj3jdRThBTE/771HCVZdRJU= github.com/filecoin-project/test-vectors/schema v0.0.5 h1:w3zHQhzM4pYxJDl21avXjOKBLF8egrvwUwjpT8TquDg= From 92c07f877bd97a18f082caf2cb84e7e1b7c1618e Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Sun, 27 Feb 2022 20:03:45 -0500 Subject: [PATCH 51/57] fix: shed: diff command --- cmd/lotus-shed/diff.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/lotus-shed/diff.go b/cmd/lotus-shed/diff.go index bcaa04122..d576f73b4 100644 --- a/cmd/lotus-shed/diff.go +++ b/cmd/lotus-shed/diff.go @@ -35,7 +35,7 @@ var diffStateTrees = &cli.Command{ return xerrors.Errorf("expected two state-tree roots") } - argA := cctx.Args().Get(1) + argA := cctx.Args().Get(0) rootA, err := cid.Parse(argA) if err != nil { return xerrors.Errorf("first state-tree root (%q) is not a CID: %w", argA, err) From 8a9ea66bdf002387c0fbe7f44c28b82d2fbe5fb0 Mon Sep 17 00:00:00 2001 From: Bhaskara Ram <39507881+bhaskarvilles@users.noreply.github.com> Date: Mon, 28 Feb 2022 12:40:43 +0530 Subject: [PATCH 52/57] node-fetch is vulnerable to Exposure of Sensitive Information to an Unauthorized Actor upgrade to node-fetch npm package --- lotuspond/front/package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lotuspond/front/package-lock.json b/lotuspond/front/package-lock.json index 252a42a6d..9bc04c8a3 100644 --- a/lotuspond/front/package-lock.json +++ b/lotuspond/front/package-lock.json @@ -6630,7 +6630,7 @@ "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", "requires": { - "node-fetch": "^1.0.1", + "node-fetch": "^2.6.7", "whatwg-fetch": ">=0.10.0" } }, From 296ae4305fa224c285d7ee8c1d8facbb7f28ecfc Mon Sep 17 00:00:00 2001 From: duzy555666 <965876239@qq.com> Date: Mon, 28 Feb 2022 16:51:15 +0800 Subject: [PATCH 53/57] avoid panic --- cmd/lotus-miner/sealing.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cmd/lotus-miner/sealing.go b/cmd/lotus-miner/sealing.go index 16b02f7bb..2f97c1e07 100644 --- a/cmd/lotus-miner/sealing.go +++ b/cmd/lotus-miner/sealing.go @@ -39,9 +39,12 @@ func barString(total, y, g float64) string { yBars := int(math.Round(y / total * barCols)) gBars := int(math.Round(g / total * barCols)) eBars := int(barCols) - yBars - gBars - return color.YellowString(strings.Repeat("|", yBars)) + - color.GreenString(strings.Repeat("|", gBars)) + - strings.Repeat(" ", eBars) + var barString = color.YellowString(strings.Repeat("|", yBars)) + + color.GreenString(strings.Repeat("|", gBars)) + if eBars >= 0 { + barString += strings.Repeat(" ", eBars) + } + return barString } var sealingWorkersCmd = &cli.Command{ From 686ada0582a30c19e9f185f9f97ade7bd6ad34aa Mon Sep 17 00:00:00 2001 From: Rjan Date: Mon, 28 Feb 2022 15:19:53 +0100 Subject: [PATCH 54/57] Make `--lite` option visibile in the cli --- cmd/lotus/daemon.go | 1 - documentation/en/cli-lotus.md | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/lotus/daemon.go b/cmd/lotus/daemon.go index 813a0a9bd..6c4ac2bcf 100644 --- a/cmd/lotus/daemon.go +++ b/cmd/lotus/daemon.go @@ -121,7 +121,6 @@ var DaemonCmd = &cli.Command{ &cli.BoolFlag{ Name: "lite", Usage: "start lotus in lite mode", - Hidden: true, }, &cli.StringFlag{ Name: "pprof", diff --git a/documentation/en/cli-lotus.md b/documentation/en/cli-lotus.md index 9a8ff028d..549945912 100644 --- a/documentation/en/cli-lotus.md +++ b/documentation/en/cli-lotus.md @@ -63,6 +63,7 @@ OPTIONS: --import-chain value on first run, load chain from given file or url and validate --import-snapshot value import chain state from a given chain export file or url --halt-after-import halt the process after importing chain from file (default: false) + --lite start lotus in lite mode (default: false) --pprof value specify name of file for writing cpu profile to --profile value specify type of node --manage-fdlimit manage open file limit (default: true) From c9e2c1b1d763a249b4b83ce89ac5aa35f36510d2 Mon Sep 17 00:00:00 2001 From: Rjan Date: Mon, 28 Feb 2022 17:14:05 +0100 Subject: [PATCH 55/57] Make --lite --- cmd/lotus/daemon.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/lotus/daemon.go b/cmd/lotus/daemon.go index 6c4ac2bcf..f285ba74e 100644 --- a/cmd/lotus/daemon.go +++ b/cmd/lotus/daemon.go @@ -119,8 +119,8 @@ var DaemonCmd = &cli.Command{ Usage: "halt the process after importing chain from file", }, &cli.BoolFlag{ - Name: "lite", - Usage: "start lotus in lite mode", + Name: "lite", + Usage: "start lotus in lite mode", }, &cli.StringFlag{ Name: "pprof", From f138ae8882bd0e18bb792166dfd9993abda61681 Mon Sep 17 00:00:00 2001 From: zenground0 Date: Tue, 1 Mar 2022 10:52:09 -0700 Subject: [PATCH 56/57] Less verbose sector manager logging --- extern/sector-storage/manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/sector-storage/manager.go b/extern/sector-storage/manager.go index 897ba4f06..28e071559 100644 --- a/extern/sector-storage/manager.go +++ b/extern/sector-storage/manager.go @@ -763,7 +763,7 @@ func (m *Manager) Remove(ctx context.Context, sector storage.SectorRef) error { func (m *Manager) ReplicaUpdate(ctx context.Context, sector storage.SectorRef, pieces []abi.PieceInfo) (out storage.ReplicaUpdateOut, err error) { ctx, cancel := context.WithCancel(ctx) defer cancel() - log.Errorf("manager is doing replica update") + log.Debugf("manager is doing replica update") wk, wait, cancel, err := m.getWork(ctx, sealtasks.TTReplicaUpdate, sector, pieces) if err != nil { return storage.ReplicaUpdateOut{}, xerrors.Errorf("getWork: %w", err) From e0922a7dd23dc93fd6549f447911c92c244a5cea Mon Sep 17 00:00:00 2001 From: Jiaying Wang <42981373+jennijuju@users.noreply.github.com> Date: Tue, 1 Mar 2022 21:56:12 -0500 Subject: [PATCH 57/57] pay for the collateral difference needed if the miner available balance is insufficient --- extern/storage-sealing/states_replica_update.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/storage-sealing/states_replica_update.go b/extern/storage-sealing/states_replica_update.go index 8683a11d8..bede7a5fa 100644 --- a/extern/storage-sealing/states_replica_update.go +++ b/extern/storage-sealing/states_replica_update.go @@ -168,7 +168,7 @@ func (m *Sealing) handleSubmitReplicaUpdate(ctx statemachine.Context, sector Sec log.Errorf("no good address to send replica update message from: %+v", err) return ctx.Send(SectorSubmitReplicaUpdateFailed{}) } - mcid, err := m.Api.SendMsg(ctx.Context(), from, m.maddr, miner.Methods.ProveReplicaUpdates, big.Zero(), big.Int(m.feeCfg.MaxCommitGasFee), enc.Bytes()) + mcid, err := m.Api.SendMsg(ctx.Context(), from, m.maddr, miner.Methods.ProveReplicaUpdates, collateral, big.Int(m.feeCfg.MaxCommitGasFee), enc.Bytes()) if err != nil { log.Errorf("handleSubmitReplicaUpdate: error sending message: %+v", err) return ctx.Send(SectorSubmitReplicaUpdateFailed{})