From 322b33197c812a59c6163627ea63ed9547c477c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Sat, 15 Aug 2020 23:57:27 +0100 Subject: [PATCH 001/247] introduce interoperable vector-based conformance testing. This commit introduces a new package `conformance` containing: 1. the test driver to exercise Lotus against interoperable test vectors, and 2. the test runner, which integrates go test with the test vector corpus hosted at https://github.com/filecoin-project/conformance-vectors. The corpus is mounted via a git submodule. Right now, only message-class test vectors are supported. In the next week, this support will be extended to tipset-class, chain-class, and block sequence-class vectors. --- .gitmodules | 4 + conformance/driver.go | 59 ++++++++++++ conformance/runner_test.go | 180 +++++++++++++++++++++++++++++++++++++ conformance/schema.go | 123 +++++++++++++++++++++++++ conformance/stubs.go | 54 +++++++++++ extern/conformance-vectors | 1 + 6 files changed, 421 insertions(+) create mode 100644 conformance/driver.go create mode 100644 conformance/runner_test.go create mode 100644 conformance/schema.go create mode 100644 conformance/stubs.go create mode 160000 extern/conformance-vectors diff --git a/.gitmodules b/.gitmodules index 709a28003..6cf1ccc72 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,3 +5,7 @@ [submodule "extern/serialization-vectors"] path = extern/serialization-vectors url = https://github.com/filecoin-project/serialization-vectors +[submodule "extern/conformance-vectors"] + path = extern/conformance-vectors + url = https://github.com/filecoin-project/conformance-vectors.git + branch = initial diff --git a/conformance/driver.go b/conformance/driver.go new file mode 100644 index 000000000..e25e5b9f2 --- /dev/null +++ b/conformance/driver.go @@ -0,0 +1,59 @@ +package conformance + +import ( + "context" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/puppet" + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" + "github.com/filecoin-project/lotus/lib/blockstore" + "github.com/filecoin-project/sector-storage/ffiwrapper" +) + +var ( + // BaseFee to use in the VM. + // TODO make parametrisable through vector. + BaseFee = abi.NewTokenAmount(100) +) + +type Driver struct { + ctx context.Context +} + +func NewDriver(ctx context.Context) *Driver { + return &Driver{ctx: ctx} +} + +// ExecuteMessage executes a conformance test vector message in a temporary VM. +func (d *Driver) ExecuteMessage(msg *types.Message, preroot cid.Cid, bs blockstore.Blockstore, epoch abi.ChainEpoch) (*vm.ApplyRet, cid.Cid, error) { + vmOpts := &vm.VMOpts{ + StateBase: preroot, + Epoch: epoch, + Rand: &testRand{}, // TODO always succeeds; need more flexibility. + Bstore: bs, + Syscalls: mkFakedSigSyscalls(vm.Syscalls(ffiwrapper.ProofVerifier)), // TODO always succeeds; need more flexibility. + CircSupplyCalc: nil, + BaseFee: BaseFee, + } + + lvm, err := vm.NewVM(vmOpts) + if err != nil { + return nil, cid.Undef, err + } + + // add support for the puppet actor. + invoker := vm.NewInvoker() + invoker.Register(puppet.PuppetActorCodeID, puppet.Actor{}, puppet.State{}) + lvm.SetInvoker(invoker) + + ret, err := lvm.ApplyMessage(d.ctx, msg) + if err != nil { + return nil, cid.Undef, err + } + + root, err := lvm.Flush(d.ctx) + return ret, root, err +} diff --git a/conformance/runner_test.go b/conformance/runner_test.go new file mode 100644 index 000000000..34d1a3c69 --- /dev/null +++ b/conformance/runner_test.go @@ -0,0 +1,180 @@ +package conformance + +import ( + "bytes" + "compress/gzip" + "context" + "encoding/json" + "flag" + "io/ioutil" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" + "github.com/filecoin-project/lotus/lib/blockstore" + + "github.com/ipld/go-car" +) + +const ( + // defaultRoot is default root at where the message vectors are hosted. + // + // You can run this test with the -vectors.root flag to execute + // a custom corpus. + defaultRoot = "../extern/conformance-vectors" +) + +var ( + // root is the effective root path, taken from the `-vectors.root` CLI flag, + // falling back to defaultRoot if not provided. + root string + // ignore is a set of paths relative to root to skip. + ignore = map[string]struct{}{ + ".git": {}, + "schema.json": {}, + } +) + +func init() { + // read the alternative root from the -vectors.root CLI flag. + flag.StringVar(&root, "vectors.root", defaultRoot, "root directory containing test vectors") +} + +// TestConformance is the entrypoint test that runs all test vectors found +// in the root directory. +// +// It locates all json files via a recursive walk, skipping over the ignore set, +// as well as files beginning with _. It parses each file as a test vector, and +// runs it via the Driver. +func TestConformance(t *testing.T) { + var vectors []string + err := filepath.Walk(root+"/", func(path string, info os.FileInfo, err error) error { + if err != nil { + t.Fatal(err) + } + + filename := filepath.Base(path) + rel, err := filepath.Rel(root, path) + if err != nil { + t.Fatal(err) + } + + if _, ok := ignore[rel]; ok { + // skip over using the right error. + if info.IsDir() { + return filepath.SkipDir + } + return nil + } + if info.IsDir() { + // dive into directories. + return nil + } + if filepath.Ext(path) != ".json" { + // skip if not .json. + return nil + } + if ignored := strings.HasPrefix(filename, "_"); ignored { + // ignore files starting with _. + t.Logf("ignoring: %s", rel) + return nil + } + vectors = append(vectors, rel) + return nil + }) + + if err != nil { + t.Fatal(err) + } + + if len(vectors) == 0 { + t.Fatalf("no test vectors found") + } + + // Run a test for each vector. + for _, v := range vectors { + v := v + t.Run(v, func(t *testing.T) { + path := filepath.Join(root, v) + raw, err := ioutil.ReadFile(path) + if err != nil { + t.Fatalf("failed to read test raw file: %s", path) + } + + var vector TestVector + err = json.Unmarshal(raw, &vector) + if err != nil { + t.Fatalf("failed to parse test raw: %s", err) + } + + // dispatch the execution depending on the vector class. + switch vector.Class { + case "message": + executeMessageVector(t, &vector) + default: + t.Fatalf("test vector class not supported: %s", vector.Class) + } + }) + } +} + +// executeMessageVector executes a message-class test vector. +func executeMessageVector(t *testing.T, vector *TestVector) { + var ( + ctx = context.Background() + epoch = vector.Pre.Epoch + root = vector.Pre.StateTree.RootCID + ) + + bs := blockstore.NewTemporary() + + // Read the base64-encoded CAR from the vector, and inflate the gzip. + buf := bytes.NewReader(vector.CAR) + r, err := gzip.NewReader(buf) + if err != nil { + t.Fatalf("failed to inflate gzipped CAR: %s", err) + } + defer r.Close() // nolint + + // Load the CAR embedded in the test vector into the Blockstore. + _, err = car.LoadCar(bs, r) + if err != nil { + t.Fatalf("failed to load state tree car from test vector: %s", err) + } + + // Create a new Driver. + driver := NewDriver(ctx) + + // Apply every message. + for i, m := range vector.ApplyMessages { + msg, err := types.DecodeMessage(m.Bytes) + if err != nil { + t.Fatalf("failed to deserialize message: %s", err) + } + + // add an epoch if one's set. + if m.Epoch != nil { + epoch = *m.Epoch + } + + var ret *vm.ApplyRet + ret, root, err = driver.ExecuteMessage(msg, root, bs, epoch) + if err != nil { + t.Fatalf("fatal failure when executing message: %s", err) + } + + receipt := vector.Post.Receipts[i] + if expected, actual := receipt.ExitCode, ret.ExitCode; expected != actual { + t.Errorf("exit code of msg %d did not match; expected: %s, got: %s", i, expected, actual) + } + if expected, actual := receipt.GasUsed, ret.GasUsed; expected != actual { + t.Errorf("gas used of msg %d did not match; expected: %d, got: %d", i, expected, actual) + } + } + if root != vector.Post.StateTree.RootCID { + t.Errorf("wrong post root cid; expected %vector , but got %vector", vector.Post.StateTree.RootCID, root) + } +} diff --git a/conformance/schema.go b/conformance/schema.go new file mode 100644 index 000000000..6c44f7ea1 --- /dev/null +++ b/conformance/schema.go @@ -0,0 +1,123 @@ +package conformance + +import ( + "encoding/base64" + "encoding/json" + "fmt" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + "github.com/ipfs/go-cid" +) + +// Class represents the type of test this instance is. +type Class string + +var ( + // ClassMessage tests the VM transition over a single message + ClassMessage Class = "message" + // ClassBlock tests the VM transition over a block of messages + ClassBlock Class = "block" + // ClassTipset tests the VM transition on a tipset update + ClassTipset Class = "tipset" + // ClassChain tests the VM transition across a chain segment + ClassChain Class = "chain" +) + +// Selector provides a filter to indicate what implementations this test is relevant for +type Selector string + +// Metadata provides information on the generation of this test case +type Metadata struct { + ID string `json:"id"` + Version string `json:"version,omitempty"` + Desc string `json:"description,omitempty"` + Comment string `json:"comment,omitempty"` + Gen GenerationData `json:"gen"` +} + +// GenerationData tags the source of this test case +type GenerationData struct { + Source string `json:"source,omitempty"` + Version string `json:"version,omitempty"` +} + +// StateTree represents a state tree within preconditions and postconditions. +type StateTree struct { + RootCID cid.Cid `json:"root_cid"` +} + +// Base64EncodedBytes is a base64-encoded binary value. +type Base64EncodedBytes []byte + +// Preconditions contain a representation of VM state at the beginning of the test +type Preconditions struct { + Epoch abi.ChainEpoch `json:"epoch"` + StateTree *StateTree `json:"state_tree"` +} + +// Receipt represents a receipt to match against. +type Receipt struct { + ExitCode exitcode.ExitCode `json:"exit_code"` + ReturnValue Base64EncodedBytes `json:"return"` + GasUsed int64 `json:"gas_used"` +} + +// Postconditions contain a representation of VM state at th end of the test +type Postconditions struct { + StateTree *StateTree `json:"state_tree"` + Receipts []*Receipt `json:"receipts"` +} + +// MarshalJSON implements json.Marshal for Base64EncodedBytes +func (beb Base64EncodedBytes) MarshalJSON() ([]byte, error) { + return json.Marshal(base64.StdEncoding.EncodeToString(beb)) +} + +// UnmarshalJSON implements json.Unmarshal for Base64EncodedBytes +func (beb *Base64EncodedBytes) UnmarshalJSON(v []byte) error { + var s string + if err := json.Unmarshal(v, &s); err != nil { + return err + } + + bytes, err := base64.StdEncoding.DecodeString(s) + if err != nil { + return err + } + *beb = bytes + return nil +} + +// TestVector is a single test case +type TestVector struct { + Class `json:"class"` + Selector `json:"selector,omitempty"` + Meta *Metadata `json:"_meta"` + + // CAR binary data to be loaded into the test environment, usually a CAR + // containing multiple state trees, addressed by root CID from the relevant + // objects. + CAR Base64EncodedBytes `json:"car"` + + Pre *Preconditions `json:"preconditions"` + ApplyMessages []Message `json:"apply_messages"` + Post *Postconditions `json:"postconditions"` +} + +type Message struct { + Bytes Base64EncodedBytes `json:"bytes"` + Epoch *abi.ChainEpoch `json:"epoch,omitempty"` +} + +// Validate validates this test vector against the JSON schema, and applies +// further validation rules that cannot be enforced through JSON Schema. +func (tv *TestVector) Validate() error { + // TODO validate against JSON Schema. + if tv.Class == ClassMessage { + if len(tv.Post.Receipts) != len(tv.ApplyMessages) { + return fmt.Errorf("length of postcondition receipts must match length of messages to apply") + } + } + return nil +} diff --git a/conformance/stubs.go b/conformance/stubs.go new file mode 100644 index 000000000..2fd1e7b64 --- /dev/null +++ b/conformance/stubs.go @@ -0,0 +1,54 @@ +package conformance + +import ( + "context" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/chain/state" + "github.com/filecoin-project/lotus/chain/vm" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/specs-actors/actors/runtime" + + cbor "github.com/ipfs/go-ipld-cbor" +) + +type testRand struct{} + +var _ vm.Rand = (*testRand)(nil) + +func (r *testRand) GetChainRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { + return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes. +} + +func (r *testRand) GetBeaconRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { + return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes. +} + +type testSyscalls struct { + runtime.Syscalls +} + +// TODO VerifySignature this will always succeed; but we want to be able to test failures too. +func (fss *testSyscalls) VerifySignature(_ crypto.Signature, _ address.Address, _ []byte) error { + return nil +} + +// TODO VerifySeal this will always succeed; but we want to be able to test failures too. +func (fss *testSyscalls) VerifySeal(_ abi.SealVerifyInfo) error { + return nil +} + +// TODO VerifyPoSt this will always succeed; but we want to be able to test failures too. +func (fss *testSyscalls) VerifyPoSt(_ abi.WindowPoStVerifyInfo) error { + return nil +} + +func mkFakedSigSyscalls(base vm.SyscallBuilder) vm.SyscallBuilder { + return func(ctx context.Context, cstate *state.StateTree, cst cbor.IpldStore) runtime.Syscalls { + return &testSyscalls{ + base(ctx, cstate, cst), + } + } +} diff --git a/extern/conformance-vectors b/extern/conformance-vectors new file mode 160000 index 000000000..6014f0705 --- /dev/null +++ b/extern/conformance-vectors @@ -0,0 +1 @@ +Subproject commit 6014f0705b91012b37ca5009b742b71a2423d529 From a0c0d9c98aaed52601e833194bb6ecd56445a81e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Sat, 15 Aug 2020 23:57:27 +0100 Subject: [PATCH 002/247] small fixes. --- conformance/runner_test.go | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/conformance/runner_test.go b/conformance/runner_test.go index 34d1a3c69..c2519a3f8 100644 --- a/conformance/runner_test.go +++ b/conformance/runner_test.go @@ -20,17 +20,18 @@ import ( ) const ( - // defaultRoot is default root at where the message vectors are hosted. + // defaultCorpusRoot is the directory where the test vector corpus is hosted. + // It is mounted on the Lotus repo as a git submodule. // - // You can run this test with the -vectors.root flag to execute - // a custom corpus. - defaultRoot = "../extern/conformance-vectors" + // When running this test, the corpus root can be overridden through the + // -corpus.root CLI flag to run an alternate corpus. + defaultCorpusRoot = "../extern/conformance-vectors" ) var ( - // root is the effective root path, taken from the `-vectors.root` CLI flag, - // falling back to defaultRoot if not provided. - root string + // corpusRoot is the effective corpus root path, taken from the `-corpus.root` CLI flag, + // falling back to defaultCorpusRoot if not provided. + corpusRoot string // ignore is a set of paths relative to root to skip. ignore = map[string]struct{}{ ".git": {}, @@ -39,25 +40,25 @@ var ( ) func init() { - // read the alternative root from the -vectors.root CLI flag. - flag.StringVar(&root, "vectors.root", defaultRoot, "root directory containing test vectors") + // read the alternative root from the -corpus.root CLI flag. + flag.StringVar(&corpusRoot, "corpus.root", defaultCorpusRoot, "test vector corpus directory") } // TestConformance is the entrypoint test that runs all test vectors found -// in the root directory. +// in the corpus root directory. // // It locates all json files via a recursive walk, skipping over the ignore set, // as well as files beginning with _. It parses each file as a test vector, and // runs it via the Driver. func TestConformance(t *testing.T) { var vectors []string - err := filepath.Walk(root+"/", func(path string, info os.FileInfo, err error) error { + err := filepath.Walk(corpusRoot+"/", func(path string, info os.FileInfo, err error) error { if err != nil { t.Fatal(err) } filename := filepath.Base(path) - rel, err := filepath.Rel(root, path) + rel, err := filepath.Rel(corpusRoot, path) if err != nil { t.Fatal(err) } @@ -98,7 +99,7 @@ func TestConformance(t *testing.T) { for _, v := range vectors { v := v t.Run(v, func(t *testing.T) { - path := filepath.Join(root, v) + path := filepath.Join(corpusRoot, v) raw, err := ioutil.ReadFile(path) if err != nil { t.Fatalf("failed to read test raw file: %s", path) @@ -160,12 +161,14 @@ func executeMessageVector(t *testing.T, vector *TestVector) { epoch = *m.Epoch } + // Execute the message. var ret *vm.ApplyRet ret, root, err = driver.ExecuteMessage(msg, root, bs, epoch) if err != nil { t.Fatalf("fatal failure when executing message: %s", err) } + // Assert that the receipt matches what the test vector expects. receipt := vector.Post.Receipts[i] if expected, actual := receipt.ExitCode, ret.ExitCode; expected != actual { t.Errorf("exit code of msg %d did not match; expected: %s, got: %s", i, expected, actual) @@ -174,6 +177,9 @@ func executeMessageVector(t *testing.T, vector *TestVector) { t.Errorf("gas used of msg %d did not match; expected: %d, got: %d", i, expected, actual) } } + + // Once all messages are applied, assert that the final state root matches + // the expected postcondition root. if root != vector.Post.StateTree.RootCID { t.Errorf("wrong post root cid; expected %vector , but got %vector", vector.Post.StateTree.RootCID, root) } From 483e82e14bd49a3ab4a324c2f66185755bf1e8c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Sun, 16 Aug 2020 22:05:43 +0100 Subject: [PATCH 003/247] point test-vectors to master. --- .gitmodules | 7 +++---- extern/conformance-vectors | 1 - extern/test-vectors | 1 + 3 files changed, 4 insertions(+), 5 deletions(-) delete mode 160000 extern/conformance-vectors create mode 160000 extern/test-vectors diff --git a/.gitmodules b/.gitmodules index 6cf1ccc72..ad09aba35 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,7 +5,6 @@ [submodule "extern/serialization-vectors"] path = extern/serialization-vectors url = https://github.com/filecoin-project/serialization-vectors -[submodule "extern/conformance-vectors"] - path = extern/conformance-vectors - url = https://github.com/filecoin-project/conformance-vectors.git - branch = initial +[submodule "extern/test-vectors"] + path = extern/test-vectors + url = https://github.com/filecoin-project/test-vectors.git diff --git a/extern/conformance-vectors b/extern/conformance-vectors deleted file mode 160000 index 6014f0705..000000000 --- a/extern/conformance-vectors +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6014f0705b91012b37ca5009b742b71a2423d529 diff --git a/extern/test-vectors b/extern/test-vectors new file mode 160000 index 000000000..6da40aea2 --- /dev/null +++ b/extern/test-vectors @@ -0,0 +1 @@ +Subproject commit 6da40aea2981f87efec5bde76de95b68c1c21bf6 From b9d67296ef775bbdcc9548476f25dd217d49254c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Sun, 16 Aug 2020 22:15:12 +0100 Subject: [PATCH 004/247] small adjustments to runner. --- conformance/runner_test.go | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/conformance/runner_test.go b/conformance/runner_test.go index c2519a3f8..edccc2a78 100644 --- a/conformance/runner_test.go +++ b/conformance/runner_test.go @@ -25,7 +25,7 @@ const ( // // When running this test, the corpus root can be overridden through the // -corpus.root CLI flag to run an alternate corpus. - defaultCorpusRoot = "../extern/conformance-vectors" + defaultCorpusRoot = "../extern/test-vectors/corpus" ) var ( @@ -97,20 +97,20 @@ func TestConformance(t *testing.T) { // Run a test for each vector. for _, v := range vectors { - v := v + path := filepath.Join(corpusRoot, v) + raw, err := ioutil.ReadFile(path) + if err != nil { + t.Fatalf("failed to read test raw file: %s", path) + } + + var vector TestVector + err = json.Unmarshal(raw, &vector) + if err != nil { + t.Errorf("failed to parse test vector %s: %s; skipping", path, err) + continue + } + t.Run(v, func(t *testing.T) { - path := filepath.Join(corpusRoot, v) - raw, err := ioutil.ReadFile(path) - if err != nil { - t.Fatalf("failed to read test raw file: %s", path) - } - - var vector TestVector - err = json.Unmarshal(raw, &vector) - if err != nil { - t.Fatalf("failed to parse test raw: %s", err) - } - // dispatch the execution depending on the vector class. switch vector.Class { case "message": @@ -181,6 +181,7 @@ func executeMessageVector(t *testing.T, vector *TestVector) { // Once all messages are applied, assert that the final state root matches // the expected postcondition root. if root != vector.Post.StateTree.RootCID { + // TODO trigger state diff on failure (@willscott) t.Errorf("wrong post root cid; expected %vector , but got %vector", vector.Post.StateTree.RootCID, root) } } From f1c452754f7fc639d149008c68a36b46af4b247a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Sun, 16 Aug 2020 22:22:12 +0100 Subject: [PATCH 005/247] separate conformance suite on CI. --- .circleci/config.yml | 14 ++++++++++++++ conformance/runner_test.go | 15 +++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8b304da90..c7ecb135a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -146,6 +146,10 @@ jobs: description: | Upload coverage report to https://codecov.io/. Requires the codecov API token to be set as an environment variable for private projects. + skip-conformance: + type: string + default: "0" + description: "Skip conformance tests (default: no)." executor: << parameters.executor >> steps: - install-deps @@ -161,6 +165,7 @@ jobs: name: go test environment: LOTUS_TEST_WINDOW_POST: << parameters.winpost-test >> + SKIP_CONFORMANCE: << parameters.skip-conformance >> command: | mkdir -p /tmp/test-reports/<< parameters.test-suite-name >> mkdir -p /tmp/test-artifacts @@ -191,6 +196,8 @@ jobs: <<: *test test-window-post: <<: *test + test-conformance: + <<: *test build-macos: description: build darwin lotus binary @@ -326,17 +333,24 @@ workflows: - test: codecov-upload: true test-suite-name: full + skip-conformance: "1" - test-window-post: go-test-flags: "-run=TestWindowedPost" + skip-conformance: "1" winpost-test: "1" test-suite-name: window-post - test-short: go-test-flags: "--timeout 10m --short" test-suite-name: short + skip-conformance: "1" filters: tags: only: - /^v\d+\.\d+\.\d+$/ + - test-conformance: + test-suite-name: conformance + packages: "./conformance" + skip-conformance: "0" - build-debug - build-all: requires: diff --git a/conformance/runner_test.go b/conformance/runner_test.go index edccc2a78..1fca08d45 100644 --- a/conformance/runner_test.go +++ b/conformance/runner_test.go @@ -24,12 +24,12 @@ const ( // It is mounted on the Lotus repo as a git submodule. // // When running this test, the corpus root can be overridden through the - // -corpus.root CLI flag to run an alternate corpus. + // -conformance.corpus CLI flag to run an alternate corpus. defaultCorpusRoot = "../extern/test-vectors/corpus" ) var ( - // corpusRoot is the effective corpus root path, taken from the `-corpus.root` CLI flag, + // corpusRoot is the effective corpus root path, taken from the `-conformance.corpus` CLI flag, // falling back to defaultCorpusRoot if not provided. corpusRoot string // ignore is a set of paths relative to root to skip. @@ -37,11 +37,15 @@ var ( ".git": {}, "schema.json": {}, } + skip bool ) func init() { - // read the alternative root from the -corpus.root CLI flag. - flag.StringVar(&corpusRoot, "corpus.root", defaultCorpusRoot, "test vector corpus directory") + // read the alternative root from the -conformance.corpus CLI flag. + flag.StringVar(&corpusRoot, "conformance.corpus", defaultCorpusRoot, "test vector corpus directory") + if strings.TrimSpace(os.Getenv("SKIP_CONFORMANCE")) == "1" { + skip = true + } } // TestConformance is the entrypoint test that runs all test vectors found @@ -51,6 +55,9 @@ func init() { // as well as files beginning with _. It parses each file as a test vector, and // runs it via the Driver. func TestConformance(t *testing.T) { + if skip { + t.SkipNow() + } var vectors []string err := filepath.Walk(corpusRoot+"/", func(path string, info os.FileInfo, err error) error { if err != nil { From b25215e31b84b37db97a7e6de89f145b1702de9c Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Mon, 17 Aug 2020 11:13:13 -0400 Subject: [PATCH 006/247] fix: paych add voucher - for inbound voucher check channel To address is owned by wallet --- node/impl/paych/paych.go | 6 +- paychmgr/manager.go | 85 +++++++++--- paychmgr/mock_test.go | 17 +++ paychmgr/paych.go | 6 +- paychmgr/paych_test.go | 271 +++++++++++++++++++++------------------ paychmgr/state.go | 4 +- paychmgr/store.go | 13 +- paychmgr/store_test.go | 6 +- 8 files changed, 248 insertions(+), 160 deletions(-) diff --git a/node/impl/paych/paych.go b/node/impl/paych/paych.go index 156a9837a..b9f8005d7 100644 --- a/node/impl/paych/paych.go +++ b/node/impl/paych/paych.go @@ -124,9 +124,7 @@ func (a *PaychAPI) PaychVoucherCheckSpendable(ctx context.Context, ch address.Ad } func (a *PaychAPI) PaychVoucherAdd(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { - _ = a.PaychMgr.TrackInboundChannel(ctx, ch) // TODO: expose those calls - - return a.PaychMgr.AddVoucher(ctx, ch, sv, proof, minDelta) + return a.PaychMgr.AddVoucherInbound(ctx, ch, sv, proof, minDelta) } // PaychVoucherCreate creates a new signed voucher on the given payment channel @@ -164,7 +162,7 @@ func (a *PaychAPI) paychVoucherCreate(ctx context.Context, pch address.Address, sv.Signature = sig - if _, err := a.PaychMgr.AddVoucher(ctx, pch, sv, nil, types.NewInt(0)); err != nil { + if _, err := a.PaychMgr.AddVoucherOutbound(ctx, pch, sv, nil, types.NewInt(0)); err != nil { return nil, xerrors.Errorf("failed to persist voucher: %w", err) } diff --git a/paychmgr/manager.go b/paychmgr/manager.go index 6244d9104..db685bbbf 100644 --- a/paychmgr/manager.go +++ b/paychmgr/manager.go @@ -47,6 +47,7 @@ type stateManagerAPI interface { type paychAPI interface { StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) MpoolPushMessage(ctx context.Context, msg *types.Message, maxFee *api.MessageSendSpec) (*types.SignedMessage, error) + WalletHas(ctx context.Context, addr address.Address) (bool, error) } // managerAPI defines all methods needed by the manager @@ -127,26 +128,6 @@ func (pm *Manager) Stop() error { return nil } -func (pm *Manager) TrackOutboundChannel(ctx context.Context, ch address.Address) error { - return pm.trackChannel(ctx, ch, DirOutbound) -} - -func (pm *Manager) TrackInboundChannel(ctx context.Context, ch address.Address) error { - return pm.trackChannel(ctx, ch, DirInbound) -} - -func (pm *Manager) trackChannel(ctx context.Context, ch address.Address, dir uint64) error { - pm.lk.Lock() - defer pm.lk.Unlock() - - ci, err := pm.sa.loadStateChannelInfo(ctx, ch, dir) - if err != nil { - return err - } - - return pm.store.TrackChannel(ci) -} - func (pm *Manager) GetPaych(ctx context.Context, from, to address.Address, amt types.BigInt) (address.Address, cid.Cid, error) { chanAccessor, err := pm.accessorByFromTo(from, to) if err != nil { @@ -218,7 +199,9 @@ func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address return ca.checkVoucherSpendable(ctx, ch, sv, secret, proof) } -func (pm *Manager) AddVoucher(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { +// AddVoucherOutbound adds a voucher for an outbound channel. +// Returns an error if the channel is not already in the store. +func (pm *Manager) AddVoucherOutbound(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { ca, err := pm.accessorByAddress(ch) if err != nil { return types.NewInt(0), err @@ -226,6 +209,66 @@ func (pm *Manager) AddVoucher(ctx context.Context, ch address.Address, sv *paych return ca.addVoucher(ctx, ch, sv, proof, minDelta) } +// AddVoucherInbound adds a voucher for an inbound channel. +// If the channel is not in the store, fetches the channel from state (and checks that +// the channel To address is owned by the wallet). +func (pm *Manager) AddVoucherInbound(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { + // Make sure channel is in store, or can be fetched from state, and that + // the channel To address is owned by the wallet + ci, err := pm.trackInboundChannel(ctx, ch) + if err != nil { + return types.BigInt{}, err + } + + // This is an inbound channel, so To is the Control address (this node) + from := ci.Target + to := ci.Control + ca, err := pm.accessorByFromTo(from, to) + if err != nil { + return types.BigInt{}, err + } + return ca.addVoucher(ctx, ch, sv, proof, minDelta) +} + +func (pm *Manager) trackInboundChannel(ctx context.Context, ch address.Address) (*ChannelInfo, error) { + // Need to take an exclusive lock here so that channel operations can't run + // in parallel (see channelLock) + pm.lk.Lock() + defer pm.lk.Unlock() + + // Check if channel is in store + ci, err := pm.store.ByAddress(ch) + if err == nil { + // Channel is in store, so it's already being tracked + return ci, nil + } + + // If there's an error (besides channel not in store) return err + if err != ErrChannelNotTracked { + return nil, err + } + + // Channel is not in store, so get channel from state + stateCi, err := pm.sa.loadStateChannelInfo(ctx, ch, DirInbound) + if err != nil { + return nil, err + } + + // Check that channel To address is in wallet + to := stateCi.Control // Inbound channel so To addr is Control (this node) + has, err := pm.pchapi.WalletHas(ctx, to) + if err != nil { + return nil, err + } + if !has { + msg := "cannot add voucher for channel %s: wallet does not have key for address %s" + return nil, xerrors.Errorf(msg, ch, to) + } + + // Save channel to store + return pm.store.TrackChannel(stateCi) +} + func (pm *Manager) AllocateLane(ch address.Address) (uint64, error) { ca, err := pm.accessorByAddress(ch) if err != nil { diff --git a/paychmgr/mock_test.go b/paychmgr/mock_test.go index 2ccb6e1d7..26b47976a 100644 --- a/paychmgr/mock_test.go +++ b/paychmgr/mock_test.go @@ -111,6 +111,7 @@ type mockPaychAPI struct { messages map[cid.Cid]*types.SignedMessage waitingCalls map[cid.Cid]*waitingCall waitingResponses map[cid.Cid]*waitingResponse + wallet map[address.Address]struct{} } func newMockPaychAPI() *mockPaychAPI { @@ -118,6 +119,7 @@ func newMockPaychAPI() *mockPaychAPI { messages: make(map[cid.Cid]*types.SignedMessage), waitingCalls: make(map[cid.Cid]*waitingCall), waitingResponses: make(map[cid.Cid]*waitingResponse), + wallet: make(map[address.Address]struct{}), } } @@ -199,3 +201,18 @@ func (pchapi *mockPaychAPI) pushedMessageCount() int { return len(pchapi.messages) } + +func (pchapi *mockPaychAPI) WalletHas(ctx context.Context, addr address.Address) (bool, error) { + pchapi.lk.Lock() + defer pchapi.lk.Unlock() + + _, ok := pchapi.wallet[addr] + return ok, nil +} + +func (pchapi *mockPaychAPI) addWalletAddress(addr address.Address) { + pchapi.lk.Lock() + defer pchapi.lk.Unlock() + + pchapi.wallet[addr] = struct{}{} +} diff --git a/paychmgr/paych.go b/paychmgr/paych.go index d4b02ec11..43e4c128b 100644 --- a/paychmgr/paych.go +++ b/paychmgr/paych.go @@ -64,11 +64,13 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add return nil, xerrors.Errorf("voucher ChannelAddr doesn't match channel address, got %s, expected %s", sv.ChannelAddr, ch) } - act, pchState, err := ca.sa.loadPaychState(ctx, ch) + // Load payment channel actor state + act, pchState, err := ca.sa.loadPaychActorState(ctx, ch) if err != nil { return nil, err } + // Load channel "From" account actor state var actState account.State _, err = ca.api.LoadActorState(ctx, pchState.From, &actState, nil) if err != nil { @@ -76,7 +78,7 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add } from := actState.Address - // verify signature + // verify voucher signature vb, err := sv.SigningBytes() if err != nil { return nil, err diff --git a/paychmgr/paych_test.go b/paychmgr/paych_test.go index 126e73702..0b8cd0f6f 100644 --- a/paychmgr/paych_test.go +++ b/paychmgr/paych_test.go @@ -29,95 +29,16 @@ import ( ds_sync "github.com/ipfs/go-datastore/sync" ) -func TestPaychOutbound(t *testing.T) { - ctx := context.Background() - store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore())) - - ch := tutils.NewIDAddr(t, 100) - from := tutils.NewIDAddr(t, 101) - to := tutils.NewIDAddr(t, 102) - fromAcct := tutils.NewIDAddr(t, 201) - toAcct := tutils.NewIDAddr(t, 202) - - mock := newMockManagerAPI() - arr, err := adt.MakeEmptyArray(mock.store).Root() - require.NoError(t, err) - mock.setAccountState(fromAcct, account.State{Address: from}) - mock.setAccountState(toAcct, account.State{Address: to}) - mock.setPaychState(ch, nil, paych.State{ - From: fromAcct, - To: toAcct, - ToSend: big.NewInt(0), - SettlingAt: abi.ChainEpoch(0), - MinSettleHeight: abi.ChainEpoch(0), - LaneStates: arr, - }) - - mgr, err := newManager(store, mock) - require.NoError(t, err) - - err = mgr.TrackOutboundChannel(ctx, ch) - require.NoError(t, err) - - ci, err := mgr.GetChannelInfo(ch) - require.NoError(t, err) - require.Equal(t, *ci.Channel, ch) - require.Equal(t, ci.Control, from) - require.Equal(t, ci.Target, to) - require.EqualValues(t, ci.Direction, DirOutbound) - require.EqualValues(t, ci.NextLane, 0) - require.Len(t, ci.Vouchers, 0) -} - -func TestPaychInbound(t *testing.T) { - ctx := context.Background() - store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore())) - - ch := tutils.NewIDAddr(t, 100) - from := tutils.NewIDAddr(t, 101) - to := tutils.NewIDAddr(t, 102) - fromAcct := tutils.NewIDAddr(t, 201) - toAcct := tutils.NewIDAddr(t, 202) - - mock := newMockManagerAPI() - arr, err := adt.MakeEmptyArray(mock.store).Root() - require.NoError(t, err) - mock.setAccountState(fromAcct, account.State{Address: from}) - mock.setAccountState(toAcct, account.State{Address: to}) - mock.setPaychState(ch, nil, paych.State{ - From: fromAcct, - To: toAcct, - ToSend: big.NewInt(0), - SettlingAt: abi.ChainEpoch(0), - MinSettleHeight: abi.ChainEpoch(0), - LaneStates: arr, - }) - - mgr, err := newManager(store, mock) - require.NoError(t, err) - - err = mgr.TrackInboundChannel(ctx, ch) - require.NoError(t, err) - - ci, err := mgr.GetChannelInfo(ch) - require.NoError(t, err) - require.Equal(t, *ci.Channel, ch) - require.Equal(t, ci.Control, to) - require.Equal(t, ci.Target, from) - require.EqualValues(t, ci.Direction, DirInbound) - require.EqualValues(t, ci.NextLane, 0) - require.Len(t, ci.Vouchers, 0) -} - func TestCheckVoucherValid(t *testing.T) { ctx := context.Background() fromKeyPrivate, fromKeyPublic := testGenerateKeyPair(t) + toKeyPrivate, toKeyPublic := testGenerateKeyPair(t) randKeyPrivate, _ := testGenerateKeyPair(t) ch := tutils.NewIDAddr(t, 100) from := tutils.NewSECP256K1Addr(t, string(fromKeyPublic)) - to := tutils.NewSECP256K1Addr(t, "secpTo") + to := tutils.NewSECP256K1Addr(t, string(toKeyPublic)) fromAcct := tutils.NewActorAddr(t, "fromAct") toAcct := tutils.NewActorAddr(t, "toAct") @@ -155,6 +76,13 @@ func TestCheckVoucherValid(t *testing.T) { actorBalance: big.NewInt(10), toSend: big.NewInt(0), voucherAmount: big.NewInt(5), + }, { + name: "fails when signed by channel To account (instead of From account)", + expectError: true, + key: toKeyPrivate, + actorBalance: big.NewInt(10), + toSend: big.NewInt(0), + voucherAmount: big.NewInt(5), }, { name: "fails when nonce too low", expectError: true, @@ -269,6 +197,7 @@ func TestCheckVoucherValid(t *testing.T) { t.Run(tcase.name, func(t *testing.T) { store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore())) + // Create an actor for the channel with the test case balance act := &types.Actor{ Code: builtin.AccountActorCodeID, Head: cid.Cid{}, @@ -276,6 +205,7 @@ func TestCheckVoucherValid(t *testing.T) { Balance: tcase.actorBalance, } + // Set the state of the channel's lanes laneStates, err := mock.storeLaneStates(tcase.laneStates) require.NoError(t, err) @@ -288,14 +218,24 @@ func TestCheckVoucherValid(t *testing.T) { LaneStates: laneStates, }) + // Create a manager mgr, err := newManager(store, mock) require.NoError(t, err) - err = mgr.TrackInboundChannel(ctx, ch) + // Create the channel in the manager's store + ci := &ChannelInfo{ + Channel: &ch, + Control: toAcct, + Target: fromAcct, + Direction: DirInbound, + } + err = mgr.store.putChannelInfo(ci) require.NoError(t, err) - sv := testCreateVoucher(t, ch, tcase.voucherLane, tcase.voucherNonce, tcase.voucherAmount, tcase.key) + // Create a signed voucher + sv := createTestVoucher(t, ch, tcase.voucherLane, tcase.voucherNonce, tcase.voucherAmount, tcase.key) + // Check the voucher's validity err = mgr.CheckVoucherValid(ctx, ch, sv) if tcase.expectError { require.Error(t, err) @@ -358,7 +298,14 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) { mgr, err := newManager(store, mock) require.NoError(t, err) - err = mgr.TrackInboundChannel(ctx, ch) + // Create the channel in the manager's store + ci := &ChannelInfo{ + Channel: &ch, + Control: toAcct, + Target: fromAcct, + Direction: DirInbound, + } + err = mgr.store.putChannelInfo(ci) require.NoError(t, err) // @@ -380,7 +327,7 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) { voucherLane := uint64(1) voucherNonce := uint64(2) voucherAmount := big.NewInt(6) - sv := testCreateVoucher(t, ch, voucherLane, voucherNonce, voucherAmount, fromKeyPrivate) + sv := createTestVoucher(t, ch, voucherLane, voucherNonce, voucherAmount, fromKeyPrivate) err = mgr.CheckVoucherValid(ctx, ch, sv) require.Error(t, err) @@ -398,13 +345,13 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) { // actor balance is 10 so total is ok. // voucherAmount = big.NewInt(4) - sv = testCreateVoucher(t, ch, voucherLane, voucherNonce, voucherAmount, fromKeyPrivate) + sv = createTestVoucher(t, ch, voucherLane, voucherNonce, voucherAmount, fromKeyPrivate) err = mgr.CheckVoucherValid(ctx, ch, sv) require.NoError(t, err) // Add voucher to lane 1, so Lane 1 effective redeemed // (with first voucher) is now 4 - _, err = mgr.AddVoucher(ctx, ch, sv, nil, minDelta) + _, err = mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta) require.NoError(t, err) // @@ -422,7 +369,7 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) { // voucherNonce++ voucherAmount = big.NewInt(6) - sv = testCreateVoucher(t, ch, voucherLane, voucherNonce, voucherAmount, fromKeyPrivate) + sv = createTestVoucher(t, ch, voucherLane, voucherNonce, voucherAmount, fromKeyPrivate) err = mgr.CheckVoucherValid(ctx, ch, sv) require.Error(t, err) @@ -440,7 +387,7 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) { // actor balance is 10 so total is ok. // voucherAmount = big.NewInt(5) - sv = testCreateVoucher(t, ch, voucherLane, voucherNonce, voucherAmount, fromKeyPrivate) + sv = createTestVoucher(t, ch, voucherLane, voucherNonce, voucherAmount, fromKeyPrivate) err = mgr.CheckVoucherValid(ctx, ch, sv) require.NoError(t, err) } @@ -457,23 +404,23 @@ func TestAddVoucherDelta(t *testing.T) { minDelta := big.NewInt(2) nonce := uint64(1) voucherAmount := big.NewInt(1) - sv := testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate) - _, err := mgr.AddVoucher(ctx, ch, sv, nil, minDelta) + sv := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate) + _, err := mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta) require.Error(t, err) // Expect success when adding a voucher whose amount is equal to minDelta nonce++ voucherAmount = big.NewInt(2) - sv = testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate) - delta, err := mgr.AddVoucher(ctx, ch, sv, nil, minDelta) + sv = createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate) + delta, err := mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta) require.NoError(t, err) require.EqualValues(t, delta.Int64(), 2) // Check that delta is correct when there's an existing voucher nonce++ voucherAmount = big.NewInt(5) - sv = testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate) - delta, err = mgr.AddVoucher(ctx, ch, sv, nil, minDelta) + sv = createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate) + delta, err = mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta) require.NoError(t, err) require.EqualValues(t, delta.Int64(), 3) @@ -481,8 +428,8 @@ func TestAddVoucherDelta(t *testing.T) { nonce = uint64(1) voucherAmount = big.NewInt(6) voucherLane = uint64(2) - sv = testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate) - delta, err = mgr.AddVoucher(ctx, ch, sv, nil, minDelta) + sv = createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate) + delta, err = mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta) require.NoError(t, err) require.EqualValues(t, delta.Int64(), 6) } @@ -499,8 +446,8 @@ func TestAddVoucherNextLane(t *testing.T) { // Add a voucher in lane 2 nonce := uint64(1) voucherLane := uint64(2) - sv := testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate) - _, err := mgr.AddVoucher(ctx, ch, sv, nil, minDelta) + sv := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate) + _, err := mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta) require.NoError(t, err) ci, err := mgr.GetChannelInfo(ch) @@ -518,8 +465,8 @@ func TestAddVoucherNextLane(t *testing.T) { // Add a voucher in lane 1 voucherLane = uint64(1) - sv = testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate) - _, err = mgr.AddVoucher(ctx, ch, sv, nil, minDelta) + sv = createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate) + _, err = mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta) require.NoError(t, err) ci, err = mgr.GetChannelInfo(ch) @@ -528,8 +475,8 @@ func TestAddVoucherNextLane(t *testing.T) { // Add a voucher in lane 7 voucherLane = uint64(7) - sv = testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate) - _, err = mgr.AddVoucher(ctx, ch, sv, nil, minDelta) + sv = createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate) + _, err = mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta) require.NoError(t, err) ci, err = mgr.GetChannelInfo(ch) @@ -557,7 +504,7 @@ func TestAllocateLane(t *testing.T) { func TestAllocateLaneWithExistingLaneState(t *testing.T) { ctx := context.Background() - _, fromKeyPublic := testGenerateKeyPair(t) + fromKeyPrivate, fromKeyPublic := testGenerateKeyPair(t) ch := tutils.NewIDAddr(t, 100) from := tutils.NewSECP256K1Addr(t, string(fromKeyPublic)) @@ -568,17 +515,13 @@ func TestAllocateLaneWithExistingLaneState(t *testing.T) { mock := newMockManagerAPI() mock.setAccountState(fromAcct, account.State{Address: from}) mock.setAccountState(toAcct, account.State{Address: to}) + mock.addWalletAddress(to) store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore())) + // Create a channel that will be retrieved from state actorBalance := big.NewInt(10) toSend := big.NewInt(1) - laneStates := map[uint64]paych.LaneState{ - 2: { - Nonce: 1, - Redeemed: big.NewInt(4), - }, - } act := &types.Actor{ Code: builtin.AccountActorCodeID, @@ -587,7 +530,7 @@ func TestAllocateLaneWithExistingLaneState(t *testing.T) { Balance: actorBalance, } - lsCid, err := mock.storeLaneStates(laneStates) + arr, err := adt.MakeEmptyArray(mock.store).Root() require.NoError(t, err) mock.setPaychState(ch, act, paych.State{ From: fromAcct, @@ -595,15 +538,23 @@ func TestAllocateLaneWithExistingLaneState(t *testing.T) { ToSend: toSend, SettlingAt: abi.ChainEpoch(0), MinSettleHeight: abi.ChainEpoch(0), - LaneStates: lsCid, + LaneStates: arr, }) mgr, err := newManager(store, mock) require.NoError(t, err) - err = mgr.TrackInboundChannel(ctx, ch) + // Create a voucher on lane 2 + // (also reads the channel from state and puts it in the store) + voucherLane := uint64(2) + minDelta := big.NewInt(0) + nonce := uint64(2) + voucherAmount := big.NewInt(5) + sv := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate) + _, err = mgr.AddVoucherInbound(ctx, ch, sv, nil, minDelta) require.NoError(t, err) + // Allocate lane should return the next lane (lane 3) lane, err := mgr.AllocateLane(ch) require.NoError(t, err) require.EqualValues(t, 3, lane) @@ -623,8 +574,8 @@ func TestAddVoucherProof(t *testing.T) { // Add a voucher with no proof var proof []byte - sv := testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate) - _, err := mgr.AddVoucher(ctx, ch, sv, nil, minDelta) + sv := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate) + _, err := mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta) require.NoError(t, err) // Expect one voucher with no proof @@ -635,7 +586,7 @@ func TestAddVoucherProof(t *testing.T) { // Add same voucher with no proof voucherLane = uint64(1) - _, err = mgr.AddVoucher(ctx, ch, sv, proof, minDelta) + _, err = mgr.AddVoucherOutbound(ctx, ch, sv, proof, minDelta) require.NoError(t, err) // Expect one voucher with no proof @@ -646,7 +597,7 @@ func TestAddVoucherProof(t *testing.T) { // Add same voucher with proof proof = []byte{1} - _, err = mgr.AddVoucher(ctx, ch, sv, proof, minDelta) + _, err = mgr.AddVoucherOutbound(ctx, ch, sv, proof, minDelta) require.NoError(t, err) // Should add proof to existing voucher @@ -656,6 +607,69 @@ func TestAddVoucherProof(t *testing.T) { require.Len(t, ci.Vouchers[0].Proof, 1) } +func TestAddVoucherInboundWalletKey(t *testing.T) { + ctx := context.Background() + + fromKeyPrivate, fromKeyPublic := testGenerateKeyPair(t) + + ch := tutils.NewIDAddr(t, 100) + from := tutils.NewSECP256K1Addr(t, string(fromKeyPublic)) + to := tutils.NewSECP256K1Addr(t, "secpTo") + fromAcct := tutils.NewActorAddr(t, "fromAct") + toAcct := tutils.NewActorAddr(t, "toAct") + + // Create an actor for the channel in state + act := &types.Actor{ + Code: builtin.AccountActorCodeID, + Head: cid.Cid{}, + Nonce: 0, + Balance: types.NewInt(20), + } + + mock := newMockManagerAPI() + arr, err := adt.MakeEmptyArray(mock.store).Root() + require.NoError(t, err) + mock.setAccountState(fromAcct, account.State{Address: from}) + mock.setAccountState(toAcct, account.State{Address: to}) + + mock.setPaychState(ch, act, paych.State{ + From: fromAcct, + To: toAcct, + ToSend: types.NewInt(0), + SettlingAt: abi.ChainEpoch(0), + MinSettleHeight: abi.ChainEpoch(0), + LaneStates: arr, + }) + + // Create a manager + store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore())) + mgr, err := newManager(store, mock) + require.NoError(t, err) + + // Add a voucher + nonce := uint64(1) + voucherLane := uint64(1) + minDelta := big.NewInt(0) + voucherAmount := big.NewInt(2) + sv := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate) + _, err = mgr.AddVoucherInbound(ctx, ch, sv, nil, minDelta) + + // Should fail because there is no wallet key matching the channel To + // address (ie, the channel is not "owned" by this node) + require.Error(t, err) + + // Add wallet key for To address + mock.addWalletAddress(to) + + // Add voucher again + sv = createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate) + _, err = mgr.AddVoucherInbound(ctx, ch, sv, nil, minDelta) + + // Should now pass because there is a wallet key matching the channel To + // address + require.NoError(t, err) +} + func TestNextNonceForLane(t *testing.T) { ctx := context.Background() @@ -674,19 +688,19 @@ func TestNextNonceForLane(t *testing.T) { // Add vouchers such that we have // lane 1: nonce 2 // lane 1: nonce 4 - // lane 2: nonce 7 voucherLane := uint64(1) for _, nonce := range []uint64{2, 4} { voucherAmount = big.Add(voucherAmount, big.NewInt(1)) - sv := testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, key) - _, err := mgr.AddVoucher(ctx, ch, sv, nil, minDelta) + sv := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, key) + _, err := mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta) require.NoError(t, err) } + // lane 2: nonce 7 voucherLane = uint64(2) nonce := uint64(7) - sv := testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, key) - _, err = mgr.AddVoucher(ctx, ch, sv, nil, minDelta) + sv := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, key) + _, err = mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta) require.NoError(t, err) // Expect next nonce for lane 1 to be 5 @@ -715,6 +729,7 @@ func testSetupMgrWithChannel(ctx context.Context, t *testing.T) (*Manager, addre mock.setAccountState(fromAcct, account.State{Address: from}) mock.setAccountState(toAcct, account.State{Address: to}) + // Create channel in state act := &types.Actor{ Code: builtin.AccountActorCodeID, Head: cid.Cid{}, @@ -734,8 +749,16 @@ func testSetupMgrWithChannel(ctx context.Context, t *testing.T) (*Manager, addre mgr, err := newManager(store, mock) require.NoError(t, err) - err = mgr.TrackInboundChannel(ctx, ch) + // Create the channel in the manager's store + ci := &ChannelInfo{ + Channel: &ch, + Control: fromAcct, + Target: toAcct, + Direction: DirOutbound, + } + err = mgr.store.putChannelInfo(ci) require.NoError(t, err) + return mgr, ch, fromKeyPrivate } @@ -747,7 +770,7 @@ func testGenerateKeyPair(t *testing.T) ([]byte, []byte) { return priv, pub } -func testCreateVoucher(t *testing.T, ch address.Address, voucherLane uint64, nonce uint64, voucherAmount big.Int, key []byte) *paych.SignedVoucher { +func createTestVoucher(t *testing.T, ch address.Address, voucherLane uint64, nonce uint64, voucherAmount big.Int, key []byte) *paych.SignedVoucher { sv := &paych.SignedVoucher{ ChannelAddr: ch, Lane: voucherLane, diff --git a/paychmgr/state.go b/paychmgr/state.go index db1b8ded2..00fe2adce 100644 --- a/paychmgr/state.go +++ b/paychmgr/state.go @@ -17,7 +17,7 @@ type stateAccessor struct { sm stateManagerAPI } -func (ca *stateAccessor) loadPaychState(ctx context.Context, ch address.Address) (*types.Actor, *paych.State, error) { +func (ca *stateAccessor) loadPaychActorState(ctx context.Context, ch address.Address) (*types.Actor, *paych.State, error) { var pcast paych.State act, err := ca.sm.LoadActorState(ctx, ch, &pcast, nil) if err != nil { @@ -28,7 +28,7 @@ func (ca *stateAccessor) loadPaychState(ctx context.Context, ch address.Address) } func (ca *stateAccessor) loadStateChannelInfo(ctx context.Context, ch address.Address, dir uint64) (*ChannelInfo, error) { - _, st, err := ca.loadPaychState(ctx, ch) + _, st, err := ca.loadPaychActorState(ctx, ch) if err != nil { return nil, err } diff --git a/paychmgr/store.go b/paychmgr/store.go index 62c4cf9b2..09790d311 100644 --- a/paychmgr/store.go +++ b/paychmgr/store.go @@ -84,15 +84,20 @@ type ChannelInfo struct { // TrackChannel stores a channel, returning an error if the channel was already // being tracked -func (ps *Store) TrackChannel(ci *ChannelInfo) error { +func (ps *Store) TrackChannel(ci *ChannelInfo) (*ChannelInfo, error) { _, err := ps.ByAddress(*ci.Channel) switch err { default: - return err + return nil, err case nil: - return fmt.Errorf("already tracking channel: %s", ci.Channel) + return nil, fmt.Errorf("already tracking channel: %s", ci.Channel) case ErrChannelNotTracked: - return ps.putChannelInfo(ci) + err = ps.putChannelInfo(ci) + if err != nil { + return nil, err + } + + return ps.ByAddress(*ci.Channel) } } diff --git a/paychmgr/store_test.go b/paychmgr/store_test.go index 65be6f1b1..36ff7a5b0 100644 --- a/paychmgr/store_test.go +++ b/paychmgr/store_test.go @@ -38,15 +38,15 @@ func TestStore(t *testing.T) { } // Track the channel - err = store.TrackChannel(ci) + _, err = store.TrackChannel(ci) require.NoError(t, err) // Tracking same channel again should error - err = store.TrackChannel(ci) + _, err = store.TrackChannel(ci) require.Error(t, err) // Track another channel - err = store.TrackChannel(ci2) + _, err = store.TrackChannel(ci2) require.NoError(t, err) // List channels should include all channels From d1592b01c385a5dbc7ec73fcf51a4d95ab3fed0c Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Tue, 18 Aug 2020 11:27:00 -0400 Subject: [PATCH 007/247] feat: paych cli voucher tests --- cli/paych.go | 79 ++++++++++------- cli/paych_test.go | 168 +++++++++++++++++++++++++++++------- paychmgr/settler/settler.go | 17 +--- paychmgr/util.go | 34 ++++++++ 4 files changed, 222 insertions(+), 76 deletions(-) create mode 100644 paychmgr/util.go diff --git a/cli/paych.go b/cli/paych.go index cf00be72c..79613f7d6 100644 --- a/cli/paych.go +++ b/cli/paych.go @@ -4,6 +4,10 @@ import ( "bytes" "encoding/base64" "fmt" + "io" + "sort" + + "github.com/filecoin-project/lotus/paychmgr" "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/build" @@ -322,7 +326,7 @@ var paychVoucherListCmd = &cli.Command{ Flags: []cli.Flag{ &cli.BoolFlag{ Name: "export", - Usage: "Print export strings", + Usage: "Print voucher as serialized string", }, }, Action: func(cctx *cli.Context) error { @@ -348,16 +352,11 @@ var paychVoucherListCmd = &cli.Command{ return err } - for _, v := range vouchers { - if cctx.Bool("export") { - enc, err := EncodedString(v) - if err != nil { - return err - } - - fmt.Fprintf(cctx.App.Writer, "Lane %d, Nonce %d: %s; %s\n", v.Lane, v.Nonce, v.Amount.String(), enc) - } else { - fmt.Fprintf(cctx.App.Writer, "Lane %d, Nonce %d: %s\n", v.Lane, v.Nonce, v.Amount.String()) + for _, v := range sortVouchers(vouchers) { + export := cctx.Bool("export") + err := outputVoucher(cctx.App.Writer, v, export) + if err != nil { + return err } } @@ -367,8 +366,14 @@ var paychVoucherListCmd = &cli.Command{ var paychVoucherBestSpendableCmd = &cli.Command{ Name: "best-spendable", - Usage: "Print voucher with highest value that is currently spendable", + Usage: "Print vouchers with highest value that is currently spendable for each lane", ArgsUsage: "[channelAddress]", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "export", + Usage: "Print voucher as serialized string", + }, + }, Action: func(cctx *cli.Context) error { if cctx.Args().Len() != 1 { return ShowHelp(cctx, fmt.Errorf("must pass payment channel address")) @@ -387,37 +392,53 @@ var paychVoucherBestSpendableCmd = &cli.Command{ ctx := ReqContext(cctx) - vouchers, err := api.PaychVoucherList(ctx, ch) + vouchersByLane, err := paychmgr.BestSpendableByLane(ctx, api, ch) if err != nil { return err } - var best *paych.SignedVoucher - for _, v := range vouchers { - spendable, err := api.PaychVoucherCheckSpendable(ctx, ch, v, nil, nil) + var vouchers []*paych.SignedVoucher + for _, vchr := range vouchersByLane { + vouchers = append(vouchers, vchr) + } + for _, best := range sortVouchers(vouchers) { + export := cctx.Bool("export") + err := outputVoucher(cctx.App.Writer, best, export) if err != nil { return err } - if spendable { - if best == nil || v.Amount.GreaterThan(best.Amount) { - best = v - } - } } - if best == nil { - return fmt.Errorf("No spendable vouchers for that channel") - } + return nil + }, +} - enc, err := EncodedString(best) +func sortVouchers(vouchers []*paych.SignedVoucher) []*paych.SignedVoucher { + sort.Slice(vouchers, func(i, j int) bool { + if vouchers[i].Lane == vouchers[j].Lane { + return vouchers[i].Nonce < vouchers[j].Nonce + } + return vouchers[i].Lane < vouchers[j].Lane + }) + return vouchers +} + +func outputVoucher(w io.Writer, v *paych.SignedVoucher, export bool) error { + var enc string + if export { + var err error + enc, err = EncodedString(v) if err != nil { return err } + } - fmt.Fprintln(cctx.App.Writer, enc) - fmt.Fprintf(cctx.App.Writer, "Amount: %s\n", best.Amount) - return nil - }, + fmt.Fprintf(w, "Lane %d, Nonce %d: %s", v.Lane, v.Nonce, v.Amount.String()) + if export { + fmt.Fprintf(w, "; %s", enc) + } + fmt.Fprintln(w) + return nil } var paychVoucherSubmitCmd = &cli.Command{ diff --git a/cli/paych_test.go b/cli/paych_test.go index ed883c228..396db905f 100644 --- a/cli/paych_test.go +++ b/cli/paych_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "flag" + "fmt" "os" "strconv" "strings" @@ -49,6 +50,139 @@ func TestPaymentChannels(t *testing.T) { blocktime := 5 * time.Millisecond ctx := context.Background() + nodes, addrs := startTwoNodesOneMiner(ctx, t, blocktime) + paymentCreator := nodes[0] + paymentReceiver := nodes[0] + creatorAddr := addrs[0] + receiverAddr := addrs[1] + + // Create mock CLI + mockCLI := newMockCLI(t) + creatorCLI := mockCLI.client(paymentCreator.ListenAddr) + receiverCLI := mockCLI.client(paymentReceiver.ListenAddr) + + // creator: paych get + channelAmt := "100000" + cmd := []string{creatorAddr.String(), receiverAddr.String(), channelAmt} + chstr := creatorCLI.runCmd(paychGetCmd, cmd) + + chAddr, err := address.NewFromString(chstr) + require.NoError(t, err) + + // creator: paych voucher create + voucherAmt := 100 + vamt := strconv.Itoa(voucherAmt) + cmd = []string{chAddr.String(), vamt} + voucher := creatorCLI.runCmd(paychVoucherCreateCmd, cmd) + + // receiver: paych voucher add + cmd = []string{chAddr.String(), voucher} + receiverCLI.runCmd(paychVoucherAddCmd, cmd) + + // creator: paych settle + cmd = []string{chAddr.String()} + creatorCLI.runCmd(paychSettleCmd, cmd) + + // Wait for the chain to reach the settle height + chState := getPaychState(ctx, t, paymentReceiver, chAddr) + waitForHeight(ctx, t, paymentReceiver, chState.SettlingAt) + + // receiver: paych collect + cmd = []string{chAddr.String()} + receiverCLI.runCmd(paychCloseCmd, cmd) +} + +type voucherSpec struct { + serialized string + amt int + lane int +} + +// TestPaymentChannelVouchers does a basic test to exercise some payment +// channel voucher commands +func TestPaymentChannelVouchers(t *testing.T) { + _ = os.Setenv("BELLMAN_NO_GPU", "1") + + blocktime := 5 * time.Millisecond + ctx := context.Background() + nodes, addrs := startTwoNodesOneMiner(ctx, t, blocktime) + paymentCreator := nodes[0] + creatorAddr := addrs[0] + receiverAddr := addrs[1] + + // Create mock CLI + mockCLI := newMockCLI(t) + creatorCLI := mockCLI.client(paymentCreator.ListenAddr) + + // creator: paych get + channelAmt := "100000" + cmd := []string{creatorAddr.String(), receiverAddr.String(), channelAmt} + chstr := creatorCLI.runCmd(paychGetCmd, cmd) + + chAddr, err := address.NewFromString(chstr) + require.NoError(t, err) + + var vouchers []voucherSpec + + // creator: paych voucher create + // Note: implied --lane=0 + voucherAmt1 := 100 + vamt1 := strconv.Itoa(voucherAmt1) + cmd = []string{chAddr.String(), vamt1} + voucher1 := creatorCLI.runCmd(paychVoucherCreateCmd, cmd) + vouchers = append(vouchers, voucherSpec{serialized: voucher1, lane: 0, amt: voucherAmt1}) + + // creator: paych voucher create --lane=5 + lane5 := "--lane=5" + voucherAmt2 := 50 + vamt2 := strconv.Itoa(voucherAmt2) + cmd = []string{lane5, chAddr.String(), vamt2} + voucher2 := creatorCLI.runCmd(paychVoucherCreateCmd, cmd) + vouchers = append(vouchers, voucherSpec{serialized: voucher2, lane: 5, amt: voucherAmt2}) + + // creator: paych voucher create --lane=5 + voucherAmt3 := 70 + vamt3 := strconv.Itoa(voucherAmt3) + cmd = []string{lane5, chAddr.String(), vamt3} + voucher3 := creatorCLI.runCmd(paychVoucherCreateCmd, cmd) + vouchers = append(vouchers, voucherSpec{serialized: voucher3, lane: 5, amt: voucherAmt3}) + + // creator: paych voucher list --export + cmd = []string{"--export", chAddr.String()} + list := creatorCLI.runCmd(paychVoucherListCmd, cmd) + + // Check that voucher list output is correct + checkVoucherOutput(t, list, vouchers) + + // creator: paych voucher best-spendable + cmd = []string{"--export", chAddr.String()} + bestSpendable := creatorCLI.runCmd(paychVoucherBestSpendableCmd, cmd) + + // Check that best spendable output is correct + bestVouchers := []voucherSpec{ + {serialized: voucher1, lane: 0, amt: voucherAmt1}, + {serialized: voucher3, lane: 5, amt: voucherAmt3}, + } + checkVoucherOutput(t, bestSpendable, bestVouchers) +} + +func checkVoucherOutput(t *testing.T, list string, vouchers []voucherSpec) { + lines := strings.Split(list, "\n") + listVouchers := make(map[string]string) + for _, line := range lines { + parts := strings.Split(line, ";") + serialized := strings.TrimSpace(parts[1]) + listVouchers[serialized] = strings.TrimSpace(parts[0]) + } + for _, vchr := range vouchers { + res, ok := listVouchers[vchr.serialized] + require.True(t, ok) + require.Regexp(t, fmt.Sprintf("Lane %d", vchr.lane), res) + require.Regexp(t, fmt.Sprintf("%d", vchr.amt), res) + } +} + +func startTwoNodesOneMiner(ctx context.Context, t *testing.T, blocktime time.Duration) ([]test.TestNode, []address.Address) { n, sn := builder.RPCMockSbBuilder(t, 2, test.OneMiner) paymentCreator := n[0] @@ -88,39 +222,7 @@ func TestPaymentChannels(t *testing.T) { } // Create mock CLI - mockCLI := newMockCLI(t) - creatorCLI := mockCLI.client(paymentCreator.ListenAddr) - receiverCLI := mockCLI.client(paymentReceiver.ListenAddr) - - // creator: paych get - channelAmt := "100000" - cmd := []string{creatorAddr.String(), receiverAddr.String(), channelAmt} - chstr := creatorCLI.runCmd(paychGetCmd, cmd) - - chAddr, err := address.NewFromString(chstr) - require.NoError(t, err) - - // creator: paych voucher create - voucherAmt := 100 - vamt := strconv.Itoa(voucherAmt) - cmd = []string{chAddr.String(), vamt} - voucher := creatorCLI.runCmd(paychVoucherCreateCmd, cmd) - - // receiver: paych voucher add - cmd = []string{chAddr.String(), voucher} - receiverCLI.runCmd(paychVoucherAddCmd, cmd) - - // creator: paych settle - cmd = []string{chAddr.String()} - creatorCLI.runCmd(paychSettleCmd, cmd) - - // Wait for the chain to reach the settle height - chState := getPaychState(ctx, t, paymentReceiver, chAddr) - waitForHeight(ctx, t, paymentReceiver, chState.SettlingAt) - - // receiver: paych collect - cmd = []string{chAddr.String()} - receiverCLI.runCmd(paychCloseCmd, cmd) + return n, []address.Address{creatorAddr, receiverAddr} } type mockCLI struct { diff --git a/paychmgr/settler/settler.go b/paychmgr/settler/settler.go index 636684118..cc12068ec 100644 --- a/paychmgr/settler/settler.go +++ b/paychmgr/settler/settler.go @@ -4,6 +4,8 @@ import ( "context" "sync" + "github.com/filecoin-project/lotus/paychmgr" + "go.uber.org/fx" "github.com/ipfs/go-cid" @@ -72,23 +74,10 @@ func (pcs *paymentChannelSettler) check(ts *types.TipSet) (done bool, more bool, } func (pcs *paymentChannelSettler) messageHandler(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (more bool, err error) { - vouchers, err := pcs.api.PaychVoucherList(pcs.ctx, msg.To) + bestByLane, err := paychmgr.BestSpendableByLane(pcs.ctx, pcs.api, msg.To) if err != nil { return true, err } - - bestByLane := make(map[uint64]*paych.SignedVoucher) - for _, voucher := range vouchers { - spendable, err := pcs.api.PaychVoucherCheckSpendable(pcs.ctx, msg.To, voucher, nil, nil) - if err != nil { - return true, err - } - if spendable { - if bestByLane[voucher.Lane] == nil || voucher.Amount.GreaterThan(bestByLane[voucher.Lane].Amount) { - bestByLane[voucher.Lane] = voucher - } - } - } var wg sync.WaitGroup wg.Add(len(bestByLane)) for _, voucher := range bestByLane { diff --git a/paychmgr/util.go b/paychmgr/util.go new file mode 100644 index 000000000..0509f8a24 --- /dev/null +++ b/paychmgr/util.go @@ -0,0 +1,34 @@ +package paychmgr + +import ( + "context" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/builtin/paych" +) + +type BestSpendableAPI interface { + PaychVoucherList(context.Context, address.Address) ([]*paych.SignedVoucher, error) + PaychVoucherCheckSpendable(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (bool, error) +} + +func BestSpendableByLane(ctx context.Context, api BestSpendableAPI, ch address.Address) (map[uint64]*paych.SignedVoucher, error) { + vouchers, err := api.PaychVoucherList(ctx, ch) + if err != nil { + return nil, err + } + + bestByLane := make(map[uint64]*paych.SignedVoucher) + for _, voucher := range vouchers { + spendable, err := api.PaychVoucherCheckSpendable(ctx, ch, voucher, nil, nil) + if err != nil { + return nil, err + } + if spendable { + if bestByLane[voucher.Lane] == nil || voucher.Amount.GreaterThan(bestByLane[voucher.Lane].Amount) { + bestByLane[voucher.Lane] = voucher + } + } + } + return bestByLane, nil +} From d317835535c031cb8ebf0ebf697745934ed055f6 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Wed, 19 Aug 2020 09:16:54 -0400 Subject: [PATCH 008/247] fix: paych check voucher should get inbound channel from state --- paychmgr/manager.go | 27 +++++++++++++++++++-------- paychmgr/paych_test.go | 22 ++++------------------ 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/paychmgr/manager.go b/paychmgr/manager.go index db685bbbf..666cd326b 100644 --- a/paychmgr/manager.go +++ b/paychmgr/manager.go @@ -178,9 +178,12 @@ func (pm *Manager) GetChannelInfo(addr address.Address) (*ChannelInfo, error) { return ca.getChannelInfo(addr) } -// CheckVoucherValid checks if the given voucher is valid (is or could become spendable at some point) +// CheckVoucherValid checks if the given voucher is valid (is or could become spendable at some point). +// If the channel is not in the store, fetches the channel from state (and checks that +// the channel To address is owned by the wallet). func (pm *Manager) CheckVoucherValid(ctx context.Context, ch address.Address, sv *paych.SignedVoucher) error { - ca, err := pm.accessorByAddress(ch) + // Get an accessor for the channel, creating it from state if necessary + ca, err := pm.inboundChannelAccessor(ctx, ch) if err != nil { return err } @@ -213,21 +216,29 @@ func (pm *Manager) AddVoucherOutbound(ctx context.Context, ch address.Address, s // If the channel is not in the store, fetches the channel from state (and checks that // the channel To address is owned by the wallet). func (pm *Manager) AddVoucherInbound(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { + // Get an accessor for the channel, creating it from state if necessary + ca, err := pm.inboundChannelAccessor(ctx, ch) + if err != nil { + return types.BigInt{}, err + } + return ca.addVoucher(ctx, ch, sv, proof, minDelta) +} + +// inboundChannelAccessor gets an accessor for the given channel. The channel +// must either exist in the store, or be an inbound channel that can be created +// from state. +func (pm *Manager) inboundChannelAccessor(ctx context.Context, ch address.Address) (*channelAccessor, error) { // Make sure channel is in store, or can be fetched from state, and that // the channel To address is owned by the wallet ci, err := pm.trackInboundChannel(ctx, ch) if err != nil { - return types.BigInt{}, err + return nil, err } // This is an inbound channel, so To is the Control address (this node) from := ci.Target to := ci.Control - ca, err := pm.accessorByFromTo(from, to) - if err != nil { - return types.BigInt{}, err - } - return ca.addVoucher(ctx, ch, sv, proof, minDelta) + return pm.accessorByFromTo(from, to) } func (pm *Manager) trackInboundChannel(ctx context.Context, ch address.Address) (*ChannelInfo, error) { diff --git a/paychmgr/paych_test.go b/paychmgr/paych_test.go index 0b8cd0f6f..455162cd3 100644 --- a/paychmgr/paych_test.go +++ b/paychmgr/paych_test.go @@ -222,15 +222,8 @@ func TestCheckVoucherValid(t *testing.T) { mgr, err := newManager(store, mock) require.NoError(t, err) - // Create the channel in the manager's store - ci := &ChannelInfo{ - Channel: &ch, - Control: toAcct, - Target: fromAcct, - Direction: DirInbound, - } - err = mgr.store.putChannelInfo(ci) - require.NoError(t, err) + // Add channel To address to wallet + mock.addWalletAddress(to) // Create a signed voucher sv := createTestVoucher(t, ch, tcase.voucherLane, tcase.voucherNonce, tcase.voucherAmount, tcase.key) @@ -298,15 +291,8 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) { mgr, err := newManager(store, mock) require.NoError(t, err) - // Create the channel in the manager's store - ci := &ChannelInfo{ - Channel: &ch, - Control: toAcct, - Target: fromAcct, - Direction: DirInbound, - } - err = mgr.store.putChannelInfo(ci) - require.NoError(t, err) + // Add channel To address to wallet + mock.addWalletAddress(to) // // Should not be possible to add a voucher with a value such that From a21234cd54d532106e6f89015dc3c6479917b74a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 19 Aug 2020 14:31:34 +0100 Subject: [PATCH 009/247] deploy the chaos actor. --- conformance/driver.go | 8 ++++++-- extern/test-vectors | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/conformance/driver.go b/conformance/driver.go index e25e5b9f2..6f23f8f69 100644 --- a/conformance/driver.go +++ b/conformance/driver.go @@ -5,12 +5,15 @@ import ( "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/puppet" + "github.com/ipfs/go-cid" + "github.com/filecoin-project/sector-storage/ffiwrapper" + "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/lib/blockstore" - "github.com/filecoin-project/sector-storage/ffiwrapper" + "github.com/filecoin-project/test-vectors/chaos" ) var ( @@ -44,9 +47,10 @@ func (d *Driver) ExecuteMessage(msg *types.Message, preroot cid.Cid, bs blocksto return nil, cid.Undef, err } - // add support for the puppet actor. + // add support for the puppet and chaos actors. invoker := vm.NewInvoker() invoker.Register(puppet.PuppetActorCodeID, puppet.Actor{}, puppet.State{}) + invoker.Register(chaos.ChaosActorCodeCID, chaos.Actor{}, chaos.State{}) lvm.SetInvoker(invoker) ret, err := lvm.ApplyMessage(d.ctx, msg) diff --git a/extern/test-vectors b/extern/test-vectors index 6da40aea2..9aec19782 160000 --- a/extern/test-vectors +++ b/extern/test-vectors @@ -1 +1 @@ -Subproject commit 6da40aea2981f87efec5bde76de95b68c1c21bf6 +Subproject commit 9aec197823427e302533f85df4c28dd4cc42dc36 From b13681df32055796b4cd31e87f89a03e0e19fe19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 19 Aug 2020 14:40:55 +0100 Subject: [PATCH 010/247] update test-vectors commit. --- go.mod | 14 ++++---------- go.sum | 2 ++ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index aeb96ffbd..431a39ef1 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,6 @@ require ( github.com/BurntSushi/toml v0.3.1 github.com/GeertJohan/go.rice v1.0.0 github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee - github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/coreos/go-systemd/v22 v22.0.0 github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e @@ -23,7 +22,6 @@ require ( github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef github.com/filecoin-project/filecoin-ffi v0.30.4-0.20200716204036-cddc56607e1d github.com/filecoin-project/go-address v0.0.3 - github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20200731171407-e559a0579161 // indirect github.com/filecoin-project/go-bitfield v0.2.0 github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 @@ -37,13 +35,13 @@ require ( github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370 github.com/filecoin-project/go-statestore v0.1.0 github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b - github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0 // indirect + github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0 github.com/filecoin-project/specs-actors v0.9.3 github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401 github.com/filecoin-project/storage-fsm v0.0.0-20200805013058-9d9ea4e6331f + github.com/filecoin-project/test-vectors v0.0.0-20200819133914-e20cc29cc926 github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 github.com/go-kit/kit v0.10.0 - github.com/go-ole/go-ole v1.2.4 // indirect github.com/google/uuid v1.1.1 github.com/gorilla/mux v1.7.4 github.com/gorilla/websocket v1.4.2 @@ -101,7 +99,6 @@ require ( github.com/libp2p/go-libp2p-tls v0.1.3 github.com/libp2p/go-libp2p-yamux v0.2.8 github.com/libp2p/go-maddr-filter v0.1.0 - github.com/mattn/go-isatty v0.0.12 // indirect github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 github.com/mitchellh/go-homedir v1.1.0 github.com/multiformats/go-base32 v0.0.3 @@ -112,7 +109,6 @@ require ( github.com/multiformats/go-multihash v0.0.14 github.com/opentracing/opentracing-go v1.2.0 github.com/raulk/clock v1.1.0 - github.com/stretchr/objx v0.2.0 // indirect github.com/stretchr/testify v1.6.1 github.com/supranational/blst v0.1.1 github.com/syndtr/goleveldb v1.0.0 @@ -123,18 +119,14 @@ require ( github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 go.opencensus.io v0.22.4 - go.uber.org/dig v1.8.0 // indirect go.uber.org/fx v1.9.0 go.uber.org/multierr v1.5.0 go.uber.org/zap v1.15.0 - go4.org v0.0.0-20190313082347-94abd6928b1d // indirect golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 golang.org/x/time v0.0.0-20191024005414-555d28b269f0 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 - google.golang.org/api v0.25.0 // indirect gotest.tools v2.2.0+incompatible - launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect ) replace github.com/golangci/golangci-lint => github.com/golangci/golangci-lint v1.18.0 @@ -142,3 +134,5 @@ replace github.com/golangci/golangci-lint => github.com/golangci/golangci-lint v replace github.com/filecoin-project/filecoin-ffi => ./extern/filecoin-ffi replace github.com/dgraph-io/badger/v2 => github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794 + +replace github.com/filecoin-project/test-vectors => ./extern/test-vectors diff --git a/go.sum b/go.sum index 26966c505..e5cbc206e 100644 --- a/go.sum +++ b/go.sum @@ -245,6 +245,7 @@ github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1 github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= github.com/filecoin-project/go-fil-markets v0.5.6 h1:WmBbV0qBU4NvLJ64xROpzrKUbkZxZqszZiEiCGmCEIY= github.com/filecoin-project/go-fil-markets v0.5.6/go.mod h1:SJApXAKr5jyGpbzDEOhvemui0pih7hhT8r2MXJxCP1E= +github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200814233340-494a301dc59c/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200817153016-2ea5cbaf5ec0 h1:/GT3V+3f+H5w5odb7LcCWJ1zPw8H8m9TsGQcU0cGSHo= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200817153016-2ea5cbaf5ec0/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= github.com/filecoin-project/go-multistore v0.0.3 h1:vaRBY4YiA2UZFPK57RNuewypB8u0DzzQwqsL0XarpnI= @@ -263,6 +264,7 @@ github.com/filecoin-project/go-statestore v0.1.0 h1:t56reH59843TwXHkMcwyuayStBIi github.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZOinUJB4WARkRfNl10O7kTnI= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b h1:fkRZSPrYpk42PV3/lIXiL0LHetxde7vyYYvSsttQtfg= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8= +github.com/filecoin-project/lotus v0.4.3-0.20200815233716-a0c0d9c98aae/go.mod h1:fqqwJa43SJzGnFA6fzsbiubRoo7UxRkpA7JwNs7LZLo= github.com/filecoin-project/sector-storage v0.0.0-20200712023225-1d67dcfa3c15/go.mod h1:salgVdX7qeXFo/xaiEQE29J4pPkjn71T0kt0n+VDBzo= github.com/filecoin-project/sector-storage v0.0.0-20200730050024-3ee28c3b6d9a/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0 h1:E1fZ27fhKK05bhZItfTwqr1i05vXnEZJznQFEYwEEUU= From dddf7951efa892006a47d37b0df5131f417755a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 19 Aug 2020 17:33:30 +0100 Subject: [PATCH 011/247] update test-vectors commit. --- conformance/runner_test.go | 5 +- conformance/schema.go | 123 ------------------------------------- extern/test-vectors | 2 +- go.mod | 2 +- go.sum | 7 +++ 5 files changed, 12 insertions(+), 127 deletions(-) delete mode 100644 conformance/schema.go diff --git a/conformance/runner_test.go b/conformance/runner_test.go index 1fca08d45..72a3ce0c9 100644 --- a/conformance/runner_test.go +++ b/conformance/runner_test.go @@ -15,6 +15,7 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/lib/blockstore" + "github.com/filecoin-project/test-vectors/schema" "github.com/ipld/go-car" ) @@ -110,7 +111,7 @@ func TestConformance(t *testing.T) { t.Fatalf("failed to read test raw file: %s", path) } - var vector TestVector + var vector schema.TestVector err = json.Unmarshal(raw, &vector) if err != nil { t.Errorf("failed to parse test vector %s: %s; skipping", path, err) @@ -130,7 +131,7 @@ func TestConformance(t *testing.T) { } // executeMessageVector executes a message-class test vector. -func executeMessageVector(t *testing.T, vector *TestVector) { +func executeMessageVector(t *testing.T, vector *schema.TestVector) { var ( ctx = context.Background() epoch = vector.Pre.Epoch diff --git a/conformance/schema.go b/conformance/schema.go deleted file mode 100644 index 6c44f7ea1..000000000 --- a/conformance/schema.go +++ /dev/null @@ -1,123 +0,0 @@ -package conformance - -import ( - "encoding/base64" - "encoding/json" - "fmt" - - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" - "github.com/ipfs/go-cid" -) - -// Class represents the type of test this instance is. -type Class string - -var ( - // ClassMessage tests the VM transition over a single message - ClassMessage Class = "message" - // ClassBlock tests the VM transition over a block of messages - ClassBlock Class = "block" - // ClassTipset tests the VM transition on a tipset update - ClassTipset Class = "tipset" - // ClassChain tests the VM transition across a chain segment - ClassChain Class = "chain" -) - -// Selector provides a filter to indicate what implementations this test is relevant for -type Selector string - -// Metadata provides information on the generation of this test case -type Metadata struct { - ID string `json:"id"` - Version string `json:"version,omitempty"` - Desc string `json:"description,omitempty"` - Comment string `json:"comment,omitempty"` - Gen GenerationData `json:"gen"` -} - -// GenerationData tags the source of this test case -type GenerationData struct { - Source string `json:"source,omitempty"` - Version string `json:"version,omitempty"` -} - -// StateTree represents a state tree within preconditions and postconditions. -type StateTree struct { - RootCID cid.Cid `json:"root_cid"` -} - -// Base64EncodedBytes is a base64-encoded binary value. -type Base64EncodedBytes []byte - -// Preconditions contain a representation of VM state at the beginning of the test -type Preconditions struct { - Epoch abi.ChainEpoch `json:"epoch"` - StateTree *StateTree `json:"state_tree"` -} - -// Receipt represents a receipt to match against. -type Receipt struct { - ExitCode exitcode.ExitCode `json:"exit_code"` - ReturnValue Base64EncodedBytes `json:"return"` - GasUsed int64 `json:"gas_used"` -} - -// Postconditions contain a representation of VM state at th end of the test -type Postconditions struct { - StateTree *StateTree `json:"state_tree"` - Receipts []*Receipt `json:"receipts"` -} - -// MarshalJSON implements json.Marshal for Base64EncodedBytes -func (beb Base64EncodedBytes) MarshalJSON() ([]byte, error) { - return json.Marshal(base64.StdEncoding.EncodeToString(beb)) -} - -// UnmarshalJSON implements json.Unmarshal for Base64EncodedBytes -func (beb *Base64EncodedBytes) UnmarshalJSON(v []byte) error { - var s string - if err := json.Unmarshal(v, &s); err != nil { - return err - } - - bytes, err := base64.StdEncoding.DecodeString(s) - if err != nil { - return err - } - *beb = bytes - return nil -} - -// TestVector is a single test case -type TestVector struct { - Class `json:"class"` - Selector `json:"selector,omitempty"` - Meta *Metadata `json:"_meta"` - - // CAR binary data to be loaded into the test environment, usually a CAR - // containing multiple state trees, addressed by root CID from the relevant - // objects. - CAR Base64EncodedBytes `json:"car"` - - Pre *Preconditions `json:"preconditions"` - ApplyMessages []Message `json:"apply_messages"` - Post *Postconditions `json:"postconditions"` -} - -type Message struct { - Bytes Base64EncodedBytes `json:"bytes"` - Epoch *abi.ChainEpoch `json:"epoch,omitempty"` -} - -// Validate validates this test vector against the JSON schema, and applies -// further validation rules that cannot be enforced through JSON Schema. -func (tv *TestVector) Validate() error { - // TODO validate against JSON Schema. - if tv.Class == ClassMessage { - if len(tv.Post.Receipts) != len(tv.ApplyMessages) { - return fmt.Errorf("length of postcondition receipts must match length of messages to apply") - } - } - return nil -} diff --git a/extern/test-vectors b/extern/test-vectors index 9aec19782..d0df1541d 160000 --- a/extern/test-vectors +++ b/extern/test-vectors @@ -1 +1 @@ -Subproject commit 9aec197823427e302533f85df4c28dd4cc42dc36 +Subproject commit d0df1541d7eaa7d2cf98e2192b2fb857944a162a diff --git a/go.mod b/go.mod index 431a39ef1..c54722b17 100644 --- a/go.mod +++ b/go.mod @@ -39,7 +39,7 @@ require ( github.com/filecoin-project/specs-actors v0.9.3 github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401 github.com/filecoin-project/storage-fsm v0.0.0-20200805013058-9d9ea4e6331f - github.com/filecoin-project/test-vectors v0.0.0-20200819133914-e20cc29cc926 + github.com/filecoin-project/test-vectors v0.0.0-20200819163125-d0df1541d7ea github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 github.com/go-kit/kit v0.10.0 github.com/google/uuid v1.1.1 diff --git a/go.sum b/go.sum index e5cbc206e..a9f850611 100644 --- a/go.sum +++ b/go.sum @@ -223,6 +223,7 @@ github.com/filecoin-project/go-address v0.0.3 h1:eVfbdjEbpbzIrbiSa+PiGUY+oDK9HnU github.com/filecoin-project/go-address v0.0.3/go.mod h1:jr8JxKsYx+lQlQZmF5i2U0Z+cGQ59wMIps/8YW/lDj8= github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200131012142-05d80eeccc5e/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg= github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200424220931-6263827e49f2/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg= +github.com/filecoin-project/go-amt-ipld/v2 v2.1.0 h1:t6qDiuGYYngDqaLc2ZUvdtAg4UNxPeOYaXhBWSNsVaM= github.com/filecoin-project/go-amt-ipld/v2 v2.1.0/go.mod h1:nfFPoGyX0CU9SkXX8EoCcSuHN1XcbN0c6KBh7yvP5fs= github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20200731171407-e559a0579161 h1:K6t4Hrs+rwUxBz2xg88Bdqeh4k5/rycQFdPseZhRyfE= github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20200731171407-e559a0579161/go.mod h1:vgmwKBkx+ca5OIeEvstiQgzAZnb7R6QaqE1oEDSqa6g= @@ -265,6 +266,8 @@ github.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZO github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b h1:fkRZSPrYpk42PV3/lIXiL0LHetxde7vyYYvSsttQtfg= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8= github.com/filecoin-project/lotus v0.4.3-0.20200815233716-a0c0d9c98aae/go.mod h1:fqqwJa43SJzGnFA6fzsbiubRoo7UxRkpA7JwNs7LZLo= +github.com/filecoin-project/lotus v0.4.3-0.20200819133134-a21234cd54d5/go.mod h1:YYUqCqyv4odVgKSFQAnIdAl0v1cIfbEYnF9E118dMGQ= +github.com/filecoin-project/lotus v0.4.3-0.20200819134055-b13681df3205/go.mod h1:rooripL/X8ixwUngDPzphAv/RKZXWBprbyxxDW0EJi0= github.com/filecoin-project/sector-storage v0.0.0-20200712023225-1d67dcfa3c15/go.mod h1:salgVdX7qeXFo/xaiEQE29J4pPkjn71T0kt0n+VDBzo= github.com/filecoin-project/sector-storage v0.0.0-20200730050024-3ee28c3b6d9a/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0 h1:E1fZ27fhKK05bhZItfTwqr1i05vXnEZJznQFEYwEEUU= @@ -337,6 +340,7 @@ github.com/gogo/status v1.1.0 h1:+eIkrewn5q6b30y+g/BJINVVdi2xH7je5MPJ3ZPK3JA= github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= @@ -1426,6 +1430,9 @@ github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSv github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg= github.com/whyrusleeping/yamux v1.1.5/go.mod h1:E8LnQQ8HKx5KD29HZFUwM1PxCOdPRzGwur1mcYhXcD8= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/c-for-go v0.0.0-20200718154222-87b0065af829 h1:wb7xrDzfkLgPHsSEBm+VSx6aDdi64VtV0xvP0E6j8bk= github.com/xlab/c-for-go v0.0.0-20200718154222-87b0065af829/go.mod h1:h/1PEBwj7Ym/8kOuMWvO2ujZ6Lt+TMbySEXNhjjR87I= From 04e4bab313bee432ed6d80a61806d0f8f92b79e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 19 Aug 2020 18:10:56 +0100 Subject: [PATCH 012/247] register chaos actor only if selector says to do so. --- conformance/driver.go | 13 +++- conformance/runner_test.go | 2 +- extern/test-vectors | 2 +- go.mod | 6 +- go.sum | 156 ++----------------------------------- 5 files changed, 24 insertions(+), 155 deletions(-) diff --git a/conformance/driver.go b/conformance/driver.go index 6f23f8f69..5a8813801 100644 --- a/conformance/driver.go +++ b/conformance/driver.go @@ -5,6 +5,7 @@ import ( "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/puppet" + "github.com/filecoin-project/test-vectors/schema" "github.com/ipfs/go-cid" @@ -23,11 +24,12 @@ var ( ) type Driver struct { - ctx context.Context + ctx context.Context + vector *schema.TestVector } -func NewDriver(ctx context.Context) *Driver { - return &Driver{ctx: ctx} +func NewDriver(ctx context.Context, vector *schema.TestVector) *Driver { + return &Driver{ctx: ctx, vector: vector} } // ExecuteMessage executes a conformance test vector message in a temporary VM. @@ -50,7 +52,10 @@ func (d *Driver) ExecuteMessage(msg *types.Message, preroot cid.Cid, bs blocksto // add support for the puppet and chaos actors. invoker := vm.NewInvoker() invoker.Register(puppet.PuppetActorCodeID, puppet.Actor{}, puppet.State{}) - invoker.Register(chaos.ChaosActorCodeCID, chaos.Actor{}, chaos.State{}) + if chaosOn, ok := d.vector.Selector.Unpack()["chaos_actor"]; ok && chaosOn == "true" { + invoker.Register(chaos.ChaosActorCodeCID, chaos.Actor{}, chaos.State{}) + } + lvm.SetInvoker(invoker) ret, err := lvm.ApplyMessage(d.ctx, msg) diff --git a/conformance/runner_test.go b/conformance/runner_test.go index 72a3ce0c9..43d58255d 100644 --- a/conformance/runner_test.go +++ b/conformance/runner_test.go @@ -155,7 +155,7 @@ func executeMessageVector(t *testing.T, vector *schema.TestVector) { } // Create a new Driver. - driver := NewDriver(ctx) + driver := NewDriver(ctx, vector) // Apply every message. for i, m := range vector.ApplyMessages { diff --git a/extern/test-vectors b/extern/test-vectors index d0df1541d..fa30b4759 160000 --- a/extern/test-vectors +++ b/extern/test-vectors @@ -1 +1 @@ -Subproject commit d0df1541d7eaa7d2cf98e2192b2fb857944a162a +Subproject commit fa30b4759106172fb78dbda260a81d038f3f6e12 diff --git a/go.mod b/go.mod index c54722b17..ce75ac1ac 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/BurntSushi/toml v0.3.1 github.com/GeertJohan/go.rice v1.0.0 github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee + github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/coreos/go-systemd/v22 v22.0.0 github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e @@ -39,9 +40,10 @@ require ( github.com/filecoin-project/specs-actors v0.9.3 github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401 github.com/filecoin-project/storage-fsm v0.0.0-20200805013058-9d9ea4e6331f - github.com/filecoin-project/test-vectors v0.0.0-20200819163125-d0df1541d7ea + github.com/filecoin-project/test-vectors v0.0.0-20200819170627-fa30b4759106 github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 github.com/go-kit/kit v0.10.0 + github.com/go-ole/go-ole v1.2.4 // indirect github.com/google/uuid v1.1.1 github.com/gorilla/mux v1.7.4 github.com/gorilla/websocket v1.4.2 @@ -119,6 +121,7 @@ require ( github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 go.opencensus.io v0.22.4 + go.uber.org/dig v1.10.0 // indirect go.uber.org/fx v1.9.0 go.uber.org/multierr v1.5.0 go.uber.org/zap v1.15.0 @@ -127,6 +130,7 @@ require ( golang.org/x/time v0.0.0-20191024005414-555d28b269f0 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 gotest.tools v2.2.0+incompatible + launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect ) replace github.com/golangci/golangci-lint => github.com/golangci/golangci-lint v1.18.0 diff --git a/go.sum b/go.sum index a9f850611..acbf281bd 100644 --- a/go.sum +++ b/go.sum @@ -2,32 +2,11 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= contrib.go.opencensus.io/exporter/jaeger v0.1.0 h1:WNc9HbA38xEQmsI40Tjd/MNU/g8byN2Of7lwIjv0Jdc= contrib.go.opencensus.io/exporter/jaeger v0.1.0/go.mod h1:VYianECmuFPwU37O699Vc1GOcy+y8kOsfaxHRImmjbA= contrib.go.opencensus.io/exporter/prometheus v0.1.0 h1:SByaIoWwNgMdPSgl5sMqM2KDE5H/ukPWBRo314xiDvg= contrib.go.opencensus.io/exporter/prometheus v0.1.0/go.mod h1:cGFniUXGZlKRjzOyuZJ6mgB+PgBcCIa79kEKR8YCW+A= dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= @@ -37,7 +16,6 @@ github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9 h1:HD8gA2tkBy github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/GeertJohan/go.incremental v1.0.0 h1:7AH+pY1XUgQE4Y1HcXYaMqAI0m9yrFqo/jt0CW30vsg= @@ -122,9 +100,6 @@ github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -225,8 +200,6 @@ github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200131012142-05d80eeccc5e/ github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200424220931-6263827e49f2/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg= github.com/filecoin-project/go-amt-ipld/v2 v2.1.0 h1:t6qDiuGYYngDqaLc2ZUvdtAg4UNxPeOYaXhBWSNsVaM= github.com/filecoin-project/go-amt-ipld/v2 v2.1.0/go.mod h1:nfFPoGyX0CU9SkXX8EoCcSuHN1XcbN0c6KBh7yvP5fs= -github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20200731171407-e559a0579161 h1:K6t4Hrs+rwUxBz2xg88Bdqeh4k5/rycQFdPseZhRyfE= -github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20200731171407-e559a0579161/go.mod h1:vgmwKBkx+ca5OIeEvstiQgzAZnb7R6QaqE1oEDSqa6g= github.com/filecoin-project/go-bitfield v0.0.0-20200416002808-b3ee67ec9060/go.mod h1:iodsLxOFZnqKtjj2zkgqzoGNrv6vUqj69AT/J8DKXEw= github.com/filecoin-project/go-bitfield v0.0.1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= github.com/filecoin-project/go-bitfield v0.0.3/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= @@ -246,7 +219,6 @@ github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1 github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= github.com/filecoin-project/go-fil-markets v0.5.6 h1:WmBbV0qBU4NvLJ64xROpzrKUbkZxZqszZiEiCGmCEIY= github.com/filecoin-project/go-fil-markets v0.5.6/go.mod h1:SJApXAKr5jyGpbzDEOhvemui0pih7hhT8r2MXJxCP1E= -github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200814233340-494a301dc59c/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200817153016-2ea5cbaf5ec0 h1:/GT3V+3f+H5w5odb7LcCWJ1zPw8H8m9TsGQcU0cGSHo= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200817153016-2ea5cbaf5ec0/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= github.com/filecoin-project/go-multistore v0.0.3 h1:vaRBY4YiA2UZFPK57RNuewypB8u0DzzQwqsL0XarpnI= @@ -265,8 +237,6 @@ github.com/filecoin-project/go-statestore v0.1.0 h1:t56reH59843TwXHkMcwyuayStBIi github.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZOinUJB4WARkRfNl10O7kTnI= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b h1:fkRZSPrYpk42PV3/lIXiL0LHetxde7vyYYvSsttQtfg= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8= -github.com/filecoin-project/lotus v0.4.3-0.20200815233716-a0c0d9c98aae/go.mod h1:fqqwJa43SJzGnFA6fzsbiubRoo7UxRkpA7JwNs7LZLo= -github.com/filecoin-project/lotus v0.4.3-0.20200819133134-a21234cd54d5/go.mod h1:YYUqCqyv4odVgKSFQAnIdAl0v1cIfbEYnF9E118dMGQ= github.com/filecoin-project/lotus v0.4.3-0.20200819134055-b13681df3205/go.mod h1:rooripL/X8ixwUngDPzphAv/RKZXWBprbyxxDW0EJi0= github.com/filecoin-project/sector-storage v0.0.0-20200712023225-1d67dcfa3c15/go.mod h1:salgVdX7qeXFo/xaiEQE29J4pPkjn71T0kt0n+VDBzo= github.com/filecoin-project/sector-storage v0.0.0-20200730050024-3ee28c3b6d9a/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= @@ -304,9 +274,6 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= @@ -342,22 +309,16 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0 h1:Rd1kQnQu0Hq3qvJppYSG0HtP+f5LPPUiDswTLiEegLg= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -384,18 +345,12 @@ github.com/google/gopacket v1.1.18 h1:lum7VRA9kdlvBi7/v2p7/zcbkduHaCH/SVVyurs7Op github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f h1:KMlcu9X58lhTA/KrfX8Bi1LQSO4pzoVjTiL3h4Jk+Zk= @@ -468,7 +423,6 @@ github.com/huin/goupnp v0.0.0-20180415215157-1395d1447324/go.mod h1:MZ2ZmwcBpvOo github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d h1:/WZQPMZNsjZ7IlCpsLGdQBINg5bxKQ1K1sh6awxLtkA= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= @@ -694,7 +648,6 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -1046,9 +999,8 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= @@ -1343,9 +1295,8 @@ github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3 github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -1402,7 +1353,6 @@ github.com/whyrusleeping/cbor-gen v0.0.0-20200414195334-429a0b5e922e/go.mod h1:X github.com/whyrusleeping/cbor-gen v0.0.0-20200504204219-64967432584d/go.mod h1:W5MvapuoHRP8rz4vxjwCK1pDqF1aQcWsV5PZ+AHbqdg= github.com/whyrusleeping/cbor-gen v0.0.0-20200710004633-5379fc63235d/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200715143311-227fab5a2377/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= -github.com/whyrusleeping/cbor-gen v0.0.0-20200723185710-6a3894a6352b/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200810223238-211df3b9e24c h1:BMg3YUwLEUIYBJoYZVhA4ZDTciXRj6r7ffOCshWrsoE= github.com/whyrusleeping/cbor-gen v0.0.0-20200810223238-211df3b9e24c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200812213548-958ddffe352c h1:otRnI08JoahNBxUFqX3372Ab9GnTj8L5J9iP5ImyxGU= @@ -1461,7 +1411,6 @@ go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -1473,8 +1422,8 @@ go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/dig v1.8.0 h1:1rR6hnL/bu1EVcjnRDN5kx1vbIjEJDTGhSQ2B3ddpcI= -go.uber.org/dig v1.8.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= +go.uber.org/dig v1.10.0 h1:yLmDDj9/zuDjv3gz8GQGviXMs9TfysIUMUilCpgzUJY= +go.uber.org/dig v1.10.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= go.uber.org/fx v1.9.0 h1:7OAz8ucp35AU8eydejpYG7QrbE8rLKzGhHbZlJi5LYY= go.uber.org/fx v1.9.0/go.mod h1:mFdUyAUuJ3w4jAckiKSKbldsxy1ojpAMJ+dVZg5Y0Aw= go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo= @@ -1492,9 +1441,8 @@ go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +go4.org v0.0.0-20190218023631-ce4c26f7be8e h1:m9LfARr2VIOW0vsV19kEKp/sWQvZnGobA8JHui/XJoY= go4.org v0.0.0-20190218023631-ce4c26f7be8e/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= -go4.org v0.0.0-20190313082347-94abd6928b1d h1:JkRdGP3zvTtTbabWSAC6n67ka30y7gOzWAah4XYJSfw= -go4.org v0.0.0-20190313082347-94abd6928b1d/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1511,7 +1459,6 @@ golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1529,37 +1476,20 @@ golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4 h1:c2HOrn5iMezYjSlGPncknSEr/8x5LELb/ilJbXi9DEA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= @@ -1583,8 +1513,6 @@ golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1597,12 +1525,8 @@ golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200519113804-d87ec0cfa476/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -1612,8 +1536,6 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1649,13 +1571,10 @@ golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190524122548-abf6ff778158/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190524152521-dbbf3f1254d4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1665,27 +1584,20 @@ golang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191025090151-53bf42e6b339/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200427175716-29b57079015a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1699,7 +1611,6 @@ golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1711,43 +1622,25 @@ golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191030062658-86caa796c7ab/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200108195415-316d2f248479/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200318150045-ba25ddc85566/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4 h1:kDtqNkeBrZb8B+atrj50B5XLHpzXXqcCdZPP/ApQ5NY= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200711155855-7342f9734a7d h1:F3OmlXCzYtG9YE6tXDnUOlJBzVzHF8EcmZ1yTJlcgIk= golang.org/x/tools v0.0.0-20200711155855-7342f9734a7d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1760,26 +1653,12 @@ google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+ google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.3.2 h1:iTp+3yyl/KOtxa/d1/JUE0GGSoR6FuW5udver22iwpw= google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.25.0 h1:LodzhlzZEUfhXzNUMIfVlf9Gr6Ua5MMtoFWh7+f47qA= -google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -1787,23 +1666,9 @@ google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482 h1:i+Aiej6cta/Frzp13/swvwz5O00kYcSe0A/C5Wd7zX8= @@ -1816,15 +1681,12 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200617041141-9a465503579e/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= @@ -1875,7 +1737,6 @@ grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJd honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U= @@ -1894,7 +1755,6 @@ modernc.org/strutil v1.1.0 h1:+1/yCzZxY2pZwwrsbH+4T7BQMoLQ9QiBshRC9eicYsc= modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= modernc.org/xc v1.0.0 h1:7ccXrupWZIS3twbUGrtKmHS2DXY6xegFua+6O3xgAFU= modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= From 30b6f387041d4466db4b36cb11eae96480270218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 19 Aug 2020 18:14:19 +0100 Subject: [PATCH 013/247] update test-vectors commit. --- extern/test-vectors | 2 +- go.mod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extern/test-vectors b/extern/test-vectors index fa30b4759..0d7704a7a 160000 --- a/extern/test-vectors +++ b/extern/test-vectors @@ -1 +1 @@ -Subproject commit fa30b4759106172fb78dbda260a81d038f3f6e12 +Subproject commit 0d7704a7a3fcb284b846982051ef9d040c0a3c9f diff --git a/go.mod b/go.mod index ce75ac1ac..6aa8fb23b 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,7 @@ require ( github.com/filecoin-project/specs-actors v0.9.3 github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401 github.com/filecoin-project/storage-fsm v0.0.0-20200805013058-9d9ea4e6331f - github.com/filecoin-project/test-vectors v0.0.0-20200819170627-fa30b4759106 + github.com/filecoin-project/test-vectors v0.0.0-20200819171321-0d7704a7a3fc github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 github.com/go-kit/kit v0.10.0 github.com/go-ole/go-ole v1.2.4 // indirect From e38f4219c5497bda7a8a19b2befad018c1462c60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 19 Aug 2020 18:19:03 +0100 Subject: [PATCH 014/247] update test-vectors commit. --- extern/test-vectors | 2 +- go.mod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extern/test-vectors b/extern/test-vectors index 0d7704a7a..30e047041 160000 --- a/extern/test-vectors +++ b/extern/test-vectors @@ -1 +1 @@ -Subproject commit 0d7704a7a3fcb284b846982051ef9d040c0a3c9f +Subproject commit 30e047041d46f2131881690b589ce57b093678a7 diff --git a/go.mod b/go.mod index 6aa8fb23b..cb0a8218a 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,7 @@ require ( github.com/filecoin-project/specs-actors v0.9.3 github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401 github.com/filecoin-project/storage-fsm v0.0.0-20200805013058-9d9ea4e6331f - github.com/filecoin-project/test-vectors v0.0.0-20200819171321-0d7704a7a3fc + github.com/filecoin-project/test-vectors v0.0.0-20200819171811-30e047041d46 github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 github.com/go-kit/kit v0.10.0 github.com/go-ole/go-ole v1.2.4 // indirect From 4a3c2730727e4b9e439ea195d0cd32eb0f5a4504 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Wed, 19 Aug 2020 18:56:51 -0400 Subject: [PATCH 015/247] fix: paych - check wallet for key for channel To address --- paychmgr/manager.go | 7 ++++++- paychmgr/mock_test.go | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/paychmgr/manager.go b/paychmgr/manager.go index db685bbbf..fe41100ae 100644 --- a/paychmgr/manager.go +++ b/paychmgr/manager.go @@ -45,6 +45,7 @@ type stateManagerAPI interface { // paychAPI defines the API methods needed by the payment channel manager type paychAPI interface { + StateAccountKey(context.Context, address.Address, types.TipSetKey) (address.Address, error) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) MpoolPushMessage(ctx context.Context, msg *types.Message, maxFee *api.MessageSendSpec) (*types.SignedMessage, error) WalletHas(ctx context.Context, addr address.Address) (bool, error) @@ -256,7 +257,11 @@ func (pm *Manager) trackInboundChannel(ctx context.Context, ch address.Address) // Check that channel To address is in wallet to := stateCi.Control // Inbound channel so To addr is Control (this node) - has, err := pm.pchapi.WalletHas(ctx, to) + toKey, err := pm.pchapi.StateAccountKey(ctx, to, types.EmptyTSK) + if err != nil { + return nil, err + } + has, err := pm.pchapi.WalletHas(ctx, toKey) if err != nil { return nil, err } diff --git a/paychmgr/mock_test.go b/paychmgr/mock_test.go index 26b47976a..1c8674ae4 100644 --- a/paychmgr/mock_test.go +++ b/paychmgr/mock_test.go @@ -202,6 +202,10 @@ func (pchapi *mockPaychAPI) pushedMessageCount() int { return len(pchapi.messages) } +func (pchapi *mockPaychAPI) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) { + return addr, nil +} + func (pchapi *mockPaychAPI) WalletHas(ctx context.Context, addr address.Address) (bool, error) { pchapi.lk.Lock() defer pchapi.lk.Unlock() From 4ce71bce2df82623ba7b175cf0a5ec7e895392e2 Mon Sep 17 00:00:00 2001 From: anorth <445306+anorth@users.noreply.github.com> Date: Thu, 20 Aug 2020 14:37:21 +1000 Subject: [PATCH 016/247] Change Message.Version to be a uint64 --- api/cbor_gen.go | 4 ++-- chain/blocksync/cbor_gen.go | 4 ++-- chain/types/cbor_gen.go | 46 ++++++++++++------------------------- chain/types/message.go | 2 +- node/hello/cbor_gen.go | 4 ++-- paychmgr/cbor_gen.go | 4 ++-- 6 files changed, 24 insertions(+), 40 deletions(-) diff --git a/api/cbor_gen.go b/api/cbor_gen.go index a90ea8b21..8889e6021 100644 --- a/api/cbor_gen.go +++ b/api/cbor_gen.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" + abi "github.com/filecoin-project/specs-actors/actors/abi" + paych "github.com/filecoin-project/specs-actors/actors/builtin/paych" cbg "github.com/whyrusleeping/cbor-gen" xerrors "golang.org/x/xerrors" ) diff --git a/chain/blocksync/cbor_gen.go b/chain/blocksync/cbor_gen.go index ad8e1de7f..cd43f4a64 100644 --- a/chain/blocksync/cbor_gen.go +++ b/chain/blocksync/cbor_gen.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - "github.com/filecoin-project/lotus/chain/types" - "github.com/ipfs/go-cid" + types "github.com/filecoin-project/lotus/chain/types" + cid "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" xerrors "golang.org/x/xerrors" ) diff --git a/chain/types/cbor_gen.go b/chain/types/cbor_gen.go index 451971aca..35abf2828 100644 --- a/chain/types/cbor_gen.go +++ b/chain/types/cbor_gen.go @@ -6,10 +6,10 @@ import ( "fmt" "io" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" - "github.com/ipfs/go-cid" + abi "github.com/filecoin-project/specs-actors/actors/abi" + crypto "github.com/filecoin-project/specs-actors/actors/crypto" + exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + cid "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" xerrors "golang.org/x/xerrors" ) @@ -637,15 +637,10 @@ func (t *Message) MarshalCBOR(w io.Writer) error { scratch := make([]byte, 9) - // t.Version (int64) (int64) - if t.Version >= 0 { - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Version)); err != nil { - return err - } - } else { - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.Version-1)); err != nil { - return err - } + // t.Version (uint64) (uint64) + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Version)); err != nil { + return err } // t.To (address.Address) (struct) @@ -729,30 +724,19 @@ func (t *Message) UnmarshalCBOR(r io.Reader) error { return fmt.Errorf("cbor input had wrong number of fields") } - // t.Version (int64) (int64) + // t.Version (uint64) (uint64) + { - maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) - var extraI int64 + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) if err != nil { return err } - switch maj { - case cbg.MajUnsignedInt: - extraI = int64(extra) - if extraI < 0 { - return fmt.Errorf("int64 positive overflow") - } - case cbg.MajNegativeInt: - extraI = int64(extra) - if extraI < 0 { - return fmt.Errorf("int64 negative oveflow") - } - extraI = -1 - extraI - default: - return fmt.Errorf("wrong type for int64 field: %d", maj) + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") } + t.Version = uint64(extra) - t.Version = int64(extraI) } // t.To (address.Address) (struct) diff --git a/chain/types/message.go b/chain/types/message.go index e9d932ac2..288fcf6d9 100644 --- a/chain/types/message.go +++ b/chain/types/message.go @@ -25,7 +25,7 @@ type ChainMsg interface { } type Message struct { - Version int64 + Version uint64 To address.Address From address.Address diff --git a/node/hello/cbor_gen.go b/node/hello/cbor_gen.go index e28d5c1b4..48d111c6b 100644 --- a/node/hello/cbor_gen.go +++ b/node/hello/cbor_gen.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/ipfs/go-cid" + abi "github.com/filecoin-project/specs-actors/actors/abi" + cid "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" xerrors "golang.org/x/xerrors" ) diff --git a/paychmgr/cbor_gen.go b/paychmgr/cbor_gen.go index aa86bc106..1a6d17783 100644 --- a/paychmgr/cbor_gen.go +++ b/paychmgr/cbor_gen.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" + address "github.com/filecoin-project/go-address" + paych "github.com/filecoin-project/specs-actors/actors/builtin/paych" cbg "github.com/whyrusleeping/cbor-gen" xerrors "golang.org/x/xerrors" ) From c02c69a8d6e59396ecdd8f5f09c71d1e43dfa14d Mon Sep 17 00:00:00 2001 From: Ingar Shu Date: Thu, 20 Aug 2020 09:16:18 -0700 Subject: [PATCH 017/247] Check deal id when emitting events Make sure to unsubscribe from retrieval events --- node/impl/client/client.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/node/impl/client/client.go b/node/impl/client/client.go index 3b992fe54..cbdbf9cb7 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -463,8 +463,10 @@ func (a *API) clientRetrieve(ctx context.Context, order api.RetrievalOrder, ref retrievalResult := make(chan error, 1) + var dealId retrievalmarket.DealID + unsubscribe := a.Retrieval.SubscribeToEvents(func(event rm.ClientEvent, state rm.ClientDealState) { - if state.PayloadCID.Equals(order.Root) { + if state.PayloadCID.Equals(order.Root) && state.ID == dealId { events <- marketevents.RetrievalEvent{ Event: event, @@ -504,7 +506,7 @@ func (a *API) clientRetrieve(ctx context.Context, order api.RetrievalOrder, ref _ = a.RetrievalStoreMgr.ReleaseStore(store) }() - _, err = a.Retrieval.Retrieve( + dealId, err = a.Retrieval.Retrieve( ctx, order.Root, params, @@ -521,17 +523,17 @@ func (a *API) clientRetrieve(ctx context.Context, order api.RetrievalOrder, ref select { case <-ctx.Done(): + unsubscribe() finish(xerrors.New("Retrieval Timed Out")) return case err := <-retrievalResult: + unsubscribe() if err != nil { finish(xerrors.Errorf("Retrieve: %w", err)) return } } - unsubscribe() - // If ref is nil, it only fetches the data into the configured blockstore. if ref == nil { finish(nil) From db240359f7108e51bc233e7ab96ef54ea865d896 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Thu, 20 Aug 2020 13:30:01 -0400 Subject: [PATCH 018/247] upgrade libp2p-quic-transport to v0.8.0 for go 1.15 compatibility --- go.mod | 2 +- go.sum | 26 ++++++++++++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 140525640..678d87f33 100644 --- a/go.mod +++ b/go.mod @@ -95,7 +95,7 @@ require ( github.com/libp2p/go-libp2p-peer v0.2.0 github.com/libp2p/go-libp2p-peerstore v0.2.6 github.com/libp2p/go-libp2p-pubsub v0.3.5-0.20200820150332-b7c28b504da7 - github.com/libp2p/go-libp2p-quic-transport v0.7.1 + github.com/libp2p/go-libp2p-quic-transport v0.8.0 github.com/libp2p/go-libp2p-record v0.1.3 github.com/libp2p/go-libp2p-routing-helpers v0.2.3 github.com/libp2p/go-libp2p-swarm v0.2.8 diff --git a/go.sum b/go.sum index d1148ff09..421486e80 100644 --- a/go.sum +++ b/go.sum @@ -295,6 +295,8 @@ github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVB github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 h1:EzDjxMg43q1tA2c0MV3tNbaontnHLplHyFF6M5KiVP0= github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1/go.mod h1:0eHX/BVySxPc6SE2mZRoppGq7qcEagxdmQnA3dzork8= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -338,6 +340,7 @@ github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -348,6 +351,8 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -889,8 +894,8 @@ github.com/libp2p/go-libp2p-pubsub v0.3.5-0.20200820150332-b7c28b504da7 h1:Ze6e0 github.com/libp2p/go-libp2p-pubsub v0.3.5-0.20200820150332-b7c28b504da7/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= github.com/libp2p/go-libp2p-quic-transport v0.1.1/go.mod h1:wqG/jzhF3Pu2NrhJEvE+IE0NTHNXslOPn9JQzyCAxzU= github.com/libp2p/go-libp2p-quic-transport v0.5.0/go.mod h1:IEcuC5MLxvZ5KuHKjRu+dr3LjCT1Be3rcD/4d8JrX8M= -github.com/libp2p/go-libp2p-quic-transport v0.7.1 h1:X6Ond9GANspXpgwJlSR9yxcMMD6SLBnGKRtwjBG5awc= -github.com/libp2p/go-libp2p-quic-transport v0.7.1/go.mod h1:TD31to4E5exogR/GWHClXCfkktigjAl5rXSt7HoxNvY= +github.com/libp2p/go-libp2p-quic-transport v0.8.0 h1:mHA94K2+TD0e9XtjWx/P5jGGZn0GdQ4OFYwNllagv4E= +github.com/libp2p/go-libp2p-quic-transport v0.8.0/go.mod h1:F2FG/6Bzz0U6essUVxDzE0s9CrY4XGLbl7QEmDNvU7A= github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q= github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= github.com/libp2p/go-libp2p-record v0.1.1/go.mod h1:VRgKajOyMVgP/F0L5g3kH7SVskp17vFi2xheb5uMJtg= @@ -1021,8 +1026,8 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= github.com/lucas-clemente/quic-go v0.16.0/go.mod h1:I0+fcNTdb9eS1ZcjQZbDVPGchJ86chcIxPALn9lEJqE= -github.com/lucas-clemente/quic-go v0.17.3 h1:jMX/MmDNCljfisgMmPGUcBJ+zUh9w3d3ia4YJjYS3TM= -github.com/lucas-clemente/quic-go v0.17.3/go.mod h1:I0+fcNTdb9eS1ZcjQZbDVPGchJ86chcIxPALn9lEJqE= +github.com/lucas-clemente/quic-go v0.18.0 h1:JhQDdqxdwdmGdKsKgXi1+coHRoGhvU6z0rNzOJqZ/4o= +github.com/lucas-clemente/quic-go v0.18.0/go.mod h1:yXttHsSNxQi8AWijC/vLP+OJczXqzHSOcJrM5ITUlCg= github.com/lufia/iostat v1.1.0/go.mod h1:rEPNA0xXgjHQjuI5Cy05sLlS2oRcSlWHRLrvh/AQ+Pg= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= @@ -1030,9 +1035,14 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI= +github.com/marten-seemann/qpack v0.2.0/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= github.com/marten-seemann/qtls v0.9.1 h1:O0YKQxNVPaiFgMng0suWEOY2Sb4LT2sRn9Qimq3Z1IQ= github.com/marten-seemann/qtls v0.9.1/go.mod h1:T1MmAdDPyISzxlK6kjRr0pcZFBVd1OZbBb/j3cvzHhk= +github.com/marten-seemann/qtls v0.10.0 h1:ECsuYUKalRL240rRD4Ri33ISb7kAQ3qGDlrrl55b2pc= +github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs= +github.com/marten-seemann/qtls-go1-15 v0.1.0 h1:i/YPXVxz8q9umso/5y474CNcHmTpA+5DH+mFPjx6PZg= +github.com/marten-seemann/qtls-go1-15 v0.1.0/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -1171,12 +1181,16 @@ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02/go.mod h1:JNdpVEzCpXBgIiv4ds+TzhN1hrtxq6ClLrTlT9OQRSc= github.com/opentracing-contrib/go-grpc v0.0.0-20191001143057-db30781987df h1:vdYtBU6zvL7v+Tr+0xFM/qhahw/EvY8DMMunZHKH6eE= @@ -1597,10 +1611,13 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200519113804-d87ec0cfa476/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1659,6 +1676,7 @@ golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191025090151-53bf42e6b339/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= From 0ada762971d3504ef15b1b9ef7c0df73eb590bef Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Thu, 20 Aug 2020 21:14:12 +0200 Subject: [PATCH 019/247] Compensate for DestoryActor in gas limit estimation Signed-off-by: Jakub Sztandera --- node/impl/full/gas.go | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/node/impl/full/gas.go b/node/impl/full/gas.go index d501af2f7..bb0d82972 100644 --- a/node/impl/full/gas.go +++ b/node/impl/full/gas.go @@ -14,6 +14,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "go.uber.org/fx" @@ -174,5 +175,23 @@ func (a *GasAPI) GasEstimateGasLimit(ctx context.Context, msgIn *types.Message, return -1, xerrors.Errorf("message execution failed: exit %s, reason: %s", res.MsgRct.ExitCode, res.Error) } - return res.MsgRct.GasUsed, nil + // Special case for PaymentChannel collect, which is deleting actor + var act types.Actor + err = a.Stmgr.WithParentState(ts, a.Stmgr.WithActor(msg.From, stmgr.GetActor(&act))) + if err != nil { + _ = err + // somewhat ignore it as it can happen and we just want to detect + // an existing PaymentChannel actor + return res.MsgRct.GasUsed, nil + } + + if !act.Code.Equals(builtin.PaymentChannelActorCodeID) { + return res.MsgRct.GasUsed, nil + } + if msgIn.Method != builtin.MethodsPaych.Collect { + return res.MsgRct.GasUsed, nil + } + + // return GasUsed without the refund for DestoryActor + return res.MsgRct.GasUsed + 76e3, nil } From d08458a03c59095ec3f55a01d47715c2c71f6390 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Fri, 21 Aug 2020 00:16:48 +0200 Subject: [PATCH 020/247] s/From/To Signed-off-by: Jakub Sztandera --- node/impl/full/gas.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/impl/full/gas.go b/node/impl/full/gas.go index bb0d82972..d0820b41a 100644 --- a/node/impl/full/gas.go +++ b/node/impl/full/gas.go @@ -177,7 +177,7 @@ func (a *GasAPI) GasEstimateGasLimit(ctx context.Context, msgIn *types.Message, // Special case for PaymentChannel collect, which is deleting actor var act types.Actor - err = a.Stmgr.WithParentState(ts, a.Stmgr.WithActor(msg.From, stmgr.GetActor(&act))) + err = a.Stmgr.WithParentState(ts, a.Stmgr.WithActor(msg.To, stmgr.GetActor(&act))) if err != nil { _ = err // somewhat ignore it as it can happen and we just want to detect From 393ac5a7c70addc21819e0fd131b57249af3e178 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Thu, 20 Aug 2020 19:45:47 -0400 Subject: [PATCH 021/247] Update changelog --- CHANGELOG.md | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e85d6461..112494db1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,145 @@ -# lotus changelog +# Lotus changelog + +## 0.5.0 / 2020-08-2020 + +This version of Lotus will be used for the incentivized testnet Space Race competition, +and can be considered mainnet-ready code. It includes some protocol +changes, upgrades of core dependencies, and various bugfixes and UX/performance improvements. + +# Highlights + +Among the highlights included in this release are: + +- Gas changes: We implemented EIP-1559 and introduced real gas values. +- Deal-making: We now support "Committed Capacity" sectors, "fast-retrieval" deals, +and the packing of multiple deals into a single sector. +- Renamed features: We renamed some of the binaries, environment variables, and default +paths associated with a Lotus node. + +## Gas changes + +We made some significant changes to the mechanics of gas in this release. + +#### Network fee + +We implemented something similar to +[Ethereum's EIP-1559](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md). +The `Message` structure had three changes: +- The `GasPrice` field has been removed +- A new `GasFeeCap` field has been added, which controls the maximum cost +the sender incurs for the message +- A new `GasPremium` field has been added, which controls the reward a miner +earns for including the message + +A sender will never be charged more than `GasFeeCap * GasLimit`. +A miner will typically earn `GasPremium * GasLimit` as a reward. + +The `Blockheader` structure has one new field, called `ParentBaseFee`. +Informally speaking,the `ParentBaseFee` +is increased when blocks are densely packed with messages, and decreased otherwise. + +The `ParentBaseFee` is used when calculating how much a sender burns when executing a message. _Burning_ simply refers to sending attoFIL to a dedicated, unreachable account. +A message causes `ParentBaseFee * GasUsed` attoFIL to be burnt. + +#### Real gas values + +This release also includes our first "real" gas costs for primitive operations. +The costs were designed to account for both the _time_ that message execution takes, +as well as the _space_ a message adds to the state tree. + +## Deal-making changes + +There are three key changes to the deal-making process. + +#### Committed Capacity sectors + +Miners can now pledge "Committed Capacity" (CC) sectors, which are explicitly +stated as containing junk data, and must not include any deals. Miners can do this +to increase their storage power, and win block rewards from this pledged storage. + +They can mark these sectors as "upgradable" with `lotus-miner sectors mark-for-upgrade`. +If the miner receives and accepts one or more storage deals, the sector that includes +those deals will _replace_ the CC sector. This is intended to maximize the amount of useful +storage on the Filecoin network. + +#### Fast-retrieval deals + +Clients can now include a `fast-retrieval` flag when proposing deals with storage miners. +If set to true, the miner will include an extra copy of the deal data. This +data can be quickly served in a retrieval deal, since it will not need to be unsealed. + +#### Multiple deals per sector + +Miners can now pack multiple deals into a single sector, so long as all the deals +fit into the sector capacity. This should increase the packing efficiency of miners. + +## Renamed features + +To improve the user experience, we updated several names to mainatin +standard prefixing, and to better reflect the meaning of the features being referenced. + +In particular, the Lotus miner binary is now called `lotus-miner`, the default +path for miner data is now `~/.lotusminer`, and the environment variable +that sets the path for miner data is now `$LOTUS_MINER_PATH`. A full list of renamed +features can be found [here](https://github.com/filecoin-project/lotus/issues/2304). + +# Changelog + +#### Downstream upgrades +- Upgrades markets to v0.5.6 (https://github.com/filecoin-project/lotus/pull/3058) +- Upgrades specs-actors to v0.9.3 (https://github.com/filecoin-project/lotus/pull/3151) + +#### Core protocol +- Introduces gas values, replacing placeholders (https://github.com/filecoin-project/lotus/pull/2343) +- Implements EIP-1559, introducing a network base fee, message gas fee cap, and message gas fee premium (https://github.com/filecoin-project/lotus/pull/2874) +- Implements Poisson Sortition for elections (https://github.com/filecoin-project/lotus/pull/2084) + +#### Deal-making lifecycle +- Introduces "Committed Capacity" sectors (https://github.com/filecoin-project/lotus/pull/2220) +- Introduces "fast-retrieval" flag for deals (https://github.com/filecoin-project/lotus/pull/2323 +- Supports packing multiple deals into one sector (https://github.com/filecoin-project/storage-fsm/pull/38) + +#### Enhancements + +- Optimized message pool selection logic (https://github.com/filecoin-project/lotus/pull/2838) +- Window-based scheduling of sealing tasks (https://github.com/filecoin-project/sector-storage/pull/67) +- Faster window PoSt (https://github.com/filecoin-project/lotus/pull/2209/files) +- Refactors the payment channel manager (https://github.com/filecoin-project/lotus/pull/2640) +- Refactors blocksync (https://github.com/filecoin-project/lotus/pull/2715/files) + +#### UX + +- Provide status updates for data-transfer (https://github.com/filecoin-project/lotus/pull/3162, https://github.com/filecoin-project/lotus/pull/3191) +- Miners can customise asks (https://github.com/filecoin-project/lotus/pull/2046) +- Miners can toggle auto-acceptance of deals (https://github.com/filecoin-project/lotus/pull/1994) +- Miners can maintain a blocklist of piece CIDs (https://github.com/filecoin-project/lotus/pull/2069) + +# Contributors + +The following contributors had 10 or more commits go into this release. +We are grateful for every contribution! + +| Contributor | Commits | Lines ± | +|--------------------|---------|---------------| +| magik6k | 361 | +13197/-6136 | +| Kubuxu | 227 | +5670/-2587 | +| arajasek | 120 | +2916/-1264 | +| whyrusleeping | 112 | +3979/-1089 | +| vyzo | 99 | +3343/-1305 | +| dirkmc | 68 | +8732/-3621 | +| laser | 45 | +1489/-501 | +| hannahhoward | 43 | +2654/-990 | +| frrist | 37 | +6630/-4338 | +| schomatis | 28 | +3016/-1368 | +| placer14 | 27 | +824/-350 | +| raulk | 25 | +28718/-29849 | +| mrsmkl | 22 | +560/-368 | +| travisperson | 18 | +1354/-314 | +| nonsense | 16 | +2956/-2842 | +| ingar | 13 | +331/-123 | +| daviddias | 11 | +311/-11 | +| Stebalien | 11 | +1204/-980 | +| RobQuistNL | 10 | +69/-74 | ## 0.1.0 / 2019-12-11 From 7f895f03f5d1fdd5e4cdc6bedba98c95eee296c0 Mon Sep 17 00:00:00 2001 From: lanzafame Date: Fri, 21 Aug 2020 10:02:43 +1000 Subject: [PATCH 022/247] fix golog cli docs --- cli/log.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/log.go b/cli/log.go index a7d95799d..c00482557 100644 --- a/cli/log.go +++ b/cli/log.go @@ -60,7 +60,8 @@ var logSetLevel = &cli.Command{ Environment Variables: GOLOG_LOG_LEVEL - Default log level for all log systems GOLOG_LOG_FMT - Change output log format (json, nocolor) - GOLOG_FILE - Write logs to file in addition to stderr + GOLOG_FILE - Write logs to file + GOLOG_OUTPUT - Specify whether to output to file, stderr, stdout or a combination, i.e. file+stderr `, Flags: []cli.Flag{ &cli.StringSliceFlag{ From 0eac90b596a78a42ab05e6ea84ace471ed4ed80b Mon Sep 17 00:00:00 2001 From: Travis Person Date: Fri, 21 Aug 2020 00:11:30 +0000 Subject: [PATCH 023/247] Testnet peers --- build/bootstrap/bootstrappers.pi | 18 ++++++------------ build/genesis/devnet.car | Bin 25893 -> 0 bytes 2 files changed, 6 insertions(+), 12 deletions(-) delete mode 100644 build/genesis/devnet.car diff --git a/build/bootstrap/bootstrappers.pi b/build/bootstrap/bootstrappers.pi index 0854ac0ed..465f3b5e9 100644 --- a/build/bootstrap/bootstrappers.pi +++ b/build/bootstrap/bootstrappers.pi @@ -1,12 +1,6 @@ -/dns4/bootstrap-0-sin.fil-test.net/tcp/1347/p2p/12D3KooWPdUquftaQvoQEtEdsRBAhwD6jopbF2oweVTzR59VbHEd -/ip4/86.109.15.57/tcp/1347/p2p/12D3KooWPdUquftaQvoQEtEdsRBAhwD6jopbF2oweVTzR59VbHEd -/dns4/bootstrap-0-dfw.fil-test.net/tcp/1347/p2p/12D3KooWQSCkHCzosEyrh8FgYfLejKgEPM5VB6qWzZE3yDAuXn8d -/ip4/139.178.84.45/tcp/1347/p2p/12D3KooWQSCkHCzosEyrh8FgYfLejKgEPM5VB6qWzZE3yDAuXn8d -/dns4/bootstrap-0-fra.fil-test.net/tcp/1347/p2p/12D3KooWEXN2eQmoyqnNjde9PBAQfQLHN67jcEdWU6JougWrgXJK -/ip4/136.144.49.17/tcp/1347/p2p/12D3KooWEXN2eQmoyqnNjde9PBAQfQLHN67jcEdWU6JougWrgXJK -/dns4/bootstrap-1-sin.fil-test.net/tcp/1347/p2p/12D3KooWLmJkZd33mJhjg5RrpJ6NFep9SNLXWc4uVngV4TXKwzYw -/ip4/86.109.15.123/tcp/1347/p2p/12D3KooWLmJkZd33mJhjg5RrpJ6NFep9SNLXWc4uVngV4TXKwzYw -/dns4/bootstrap-1-dfw.fil-test.net/tcp/1347/p2p/12D3KooWGXLHjiz6pTRu7x2pkgTVCoxcCiVxcNLpMnWcJ3JiNEy5 -/ip4/139.178.86.3/tcp/1347/p2p/12D3KooWGXLHjiz6pTRu7x2pkgTVCoxcCiVxcNLpMnWcJ3JiNEy5 -/dns4/bootstrap-1-fra.fil-test.net/tcp/1347/p2p/12D3KooW9szZmKttS9A1FafH3Zc2pxKwwmvCWCGKkRP4KmbhhC4R -/ip4/136.144.49.131/tcp/1347/p2p/12D3KooW9szZmKttS9A1FafH3Zc2pxKwwmvCWCGKkRP4KmbhhC4R +/dns4/bootstrap-0.testnet.fildev.network/tcp/1347/p2p/12D3KooWJTUBUjtzWJGWU1XSiY21CwmHaCNLNYn2E7jqHEHyZaP7 +/dns4/bootstrap-1.testnet.fildev.network/tcp/1347/p2p/12D3KooW9yeKXha4hdrJKq74zEo99T8DhriQdWNoojWnnQbsgB3v +/dns4/bootstrap-2.testnet.fildev.network/tcp/1347/p2p/12D3KooWCrx8yVG9U9Kf7w8KLN3Edkj5ZKDhgCaeMqQbcQUoB6CT +/dns4/bootstrap-4.testnet.fildev.network/tcp/1347/p2p/12D3KooWPkL9LrKRQgHtq7kn9ecNhGU9QaziG8R5tX8v9v7t3h34 +/dns4/bootstrap-3.testnet.fildev.network/tcp/1347/p2p/12D3KooWKYSsbpgZ3HAjax5M1BXCwXLa6gVkUARciz7uN3FNtr7T +/dns4/bootstrap-5.testnet.fildev.network/tcp/1347/p2p/12D3KooWQYzqnLASJAabyMpPb1GcWZvNSe7JDcRuhdRqonFoiK9W diff --git a/build/genesis/devnet.car b/build/genesis/devnet.car deleted file mode 100644 index 3e156de61764ee49afa5b090f86511a29a661e5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25893 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 Date: Thu, 20 Aug 2020 17:21:33 -0700 Subject: [PATCH 024/247] space race parameters --- build/drand.go | 2 +- build/params_testnet.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/drand.go b/build/drand.go index 4e29bdc74..e24b802d6 100644 --- a/build/drand.go +++ b/build/drand.go @@ -2,7 +2,7 @@ package build import "github.com/filecoin-project/lotus/node/modules/dtypes" -var DrandNetwork = DrandMainnet +var DrandNetwork = DrandTestnet func DrandConfig() dtypes.DrandConfig { return DrandConfigs[DrandNetwork] diff --git a/build/params_testnet.go b/build/params_testnet.go index e0e3fc3fa..f422b3861 100644 --- a/build/params_testnet.go +++ b/build/params_testnet.go @@ -13,7 +13,7 @@ import ( ) func init() { - power.ConsensusMinerMinPower = big.NewInt(1024 << 30) + power.ConsensusMinerMinPower = big.NewInt(10 << 40) miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ abi.RegisteredSealProof_StackedDrg32GiBV1: {}, abi.RegisteredSealProof_StackedDrg64GiBV1: {}, From 38a2f82f784241cfb389218bd1367618bea0e206 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Thu, 20 Aug 2020 18:43:13 -0700 Subject: [PATCH 025/247] fix fd limit test --- lib/ulimit/ulimit_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ulimit/ulimit_test.go b/lib/ulimit/ulimit_test.go index 1e7fc7d16..c99b7fb57 100644 --- a/lib/ulimit/ulimit_test.go +++ b/lib/ulimit/ulimit_test.go @@ -44,7 +44,7 @@ func TestManageInvalidNFds(t *testing.T) { t.Errorf("ManageFdLimit should return an error: changed %t, new: %d", changed, new) } else if err != nil { flag := strings.Contains(err.Error(), - "failed to raise ulimit to IPFS_FD_MAX") + "failed to raise ulimit to LOTUS_FD_MAX") if !flag { t.Error("ManageFdLimit returned unexpected error", err) } From 4bf7619d32a8c989ca91571636293d2944f4b63e Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Thu, 20 Aug 2020 18:11:34 -0700 Subject: [PATCH 026/247] Actually set genesis remainder account balance --- chain/gen/genesis/genesis.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index a6a320b97..40f006522 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -297,6 +297,8 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge return nil, nil, err } + template.RemainderAccount.Balance = remainingFil + if err := createMultisigAccount(ctx, bs, cst, state, remAccKey, template.RemainderAccount, keyIDs); err != nil { return nil, nil, xerrors.Errorf("failed to set up remainder account: %w", err) } From 5733c71c50cf2416e529adc1298073b49cb63380 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Wed, 19 Aug 2020 21:49:10 -0700 Subject: [PATCH 027/247] Lint everything We were ignoring quite a few error cases, and had one case where we weren't actually updating state where we wanted to. Unfortunately, if the linter doesn't pass, nobody has any reason to actually check lint failures in CI. There are three remaining XXXs marked in the code for lint. --- .circleci/config.yml | 6 +- .golangci.yml | 21 +++++ api/docgen/docgen.go | 4 +- api/test/deals.go | 8 +- api/test/mining.go | 1 + api/test/paych.go | 3 + api/test/window_post.go | 11 ++- chain/block_receipt_tracker.go | 4 +- chain/blocksync/client.go | 4 +- chain/blocksync/protocol.go | 3 +- chain/events/state/diff_adt.go | 1 + chain/events/state/predicates.go | 1 + chain/events/state/predicates_test.go | 18 ++-- chain/gen/gen.go | 7 +- chain/gen/genesis/miners.go | 10 +- chain/gen/genesis/util.go | 4 - chain/market/fundmgr_test.go | 1 + chain/messagepool/block_proba.go | 2 +- chain/messagepool/provider.go | 2 +- chain/metrics/consensus.go | 3 +- chain/state/statetree.go | 4 +- chain/store/index_test.go | 2 +- chain/store/store.go | 4 +- chain/sub/incoming.go | 5 +- chain/sync_manager.go | 10 +- chain/sync_test.go | 26 ++--- chain/types/signedmessage.go | 4 +- chain/types/tipset.go | 4 + chain/validation/factories.go | 1 + chain/validation/keymanager.go | 3 +- chain/vectors/vectors_test.go | 2 +- chain/vm/runtime.go | 12 ++- chain/vm/vm.go | 3 + cli/auth.go | 1 + cli/chain.go | 4 +- cli/client.go | 94 +++++++++---------- cli/helper.go | 2 +- cli/mpool.go | 2 +- cli/net.go | 2 +- cli/pprof.go | 2 +- cli/state.go | 14 ++- cli/wallet.go | 5 +- cmd/lotus-bench/import.go | 34 ++----- cmd/lotus-chainwatch/processor/reward.go | 2 +- cmd/lotus-chainwatch/run.go | 2 +- .../refresh_top_miners_by_base_reward.go | 4 +- cmd/lotus-chainwatch/scheduler/scheduler.go | 8 +- cmd/lotus-fountain/main.go | 69 ++++++-------- cmd/lotus-keygen/main.go | 7 +- cmd/lotus-pcr/main.go | 20 ++-- cmd/lotus-seal-worker/main.go | 9 +- cmd/lotus-seed/main.go | 3 + cmd/lotus-shed/keyinfo.go | 10 +- cmd/lotus-storage-miner/info_all.go | 4 +- cmd/lotus-storage-miner/run.go | 5 +- cmd/lotus-storage-miner/sealing.go | 3 +- cmd/lotus-storage-miner/sectors.go | 3 +- cmd/lotus-townhall/main.go | 3 +- .../sector-storage/ffiwrapper/partialfile.go | 2 +- extern/sector-storage/fsutil/statfs_unix.go | 2 + extern/sector-storage/mock/mock.go | 2 +- extern/sector-storage/tarutil/systar.go | 2 + extern/storage-sealing/fsm.go | 4 +- extern/storage-sealing/sealing.go | 7 +- extern/storage-sealing/types.go | 1 + go.mod | 1 - journal/journal.go | 16 ++-- lib/blockstore/blockstore.go | 4 +- lib/cachebs/cachebs.go | 1 + lib/rpcenc/reader.go | 2 +- lib/rpcenc/reader_test.go | 2 +- lib/sigs/bls/bls_bench_test.go | 7 +- lotuspond/api.go | 2 +- lotuspond/outmux.go | 2 +- markets/storageadapter/client.go | 6 +- markets/storageadapter/provider.go | 6 +- miner/miner.go | 11 +-- node/builder.go | 1 + node/impl/client/client.go | 6 +- node/impl/full/mpool.go | 7 +- node/impl/full/multisig.go | 2 +- node/impl/full/state.go | 16 ++-- node/impl/full/sync.go | 3 +- node/impl/full/wallet.go | 14 ++- node/modules/client.go | 3 +- node/modules/core.go | 4 +- node/modules/graphsync.go | 2 +- node/modules/services.go | 4 +- storage/adapter_storage_miner.go | 2 +- storage/addresses.go | 1 + storage/wdpost_run.go | 2 +- tools/stats/head_buffer.go | 6 +- tools/stats/head_buffer_test.go | 40 ++++---- tools/stats/metrics.go | 9 +- tools/stats/rpc.go | 11 ++- 95 files changed, 372 insertions(+), 347 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8b304da90..0b2329954 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -288,9 +288,6 @@ jobs: command: | $HOME/.local/bin/golangci-lint run -v --timeout 2m \ --concurrency << parameters.concurrency >> << parameters.args >> - lint-changes: - <<: *lint - lint-all: <<: *lint @@ -319,8 +316,7 @@ workflows: version: 2.1 ci: jobs: - - lint-changes: - args: "--new-from-rev origin/next" + - lint-all - mod-tidy-check - gofmt - test: diff --git a/.golangci.yml b/.golangci.yml index 76bbc1949..8bdba64f0 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -23,6 +23,14 @@ issues: - "Potential file inclusion via variable" - "should have( a package)? comment" - "Error return value of `logging.SetLogLevel` is not checked" + - "comment on exported" + - "(func|method) \\w+ should be \\w+" + - "(type|var|struct field|(method|func) parameter) `\\w+` should be `\\w+`" + - "(G306|G301|G307|G108|G302|G204|G104)" + - "don't use ALL_CAPS in Go names" + - "string .* has .* occurrences, make it a constant" + - "a blank import should be only in a main or test package, or have a comment justifying it" + - "package comment should be of the form" exclude-use-default: false exclude-rules: @@ -46,6 +54,19 @@ issues: linters: - gosec + - path: chain/vectors/gen/.* + linters: + - gosec + + - path: cmd/lotus-bench/.* + linters: + - gosec + + - path: api/test/.* + text: "context.Context should be the first parameter" + linters: + - golint + linters-settings: goconst: min-occurrences: 6 diff --git a/api/docgen/docgen.go b/api/docgen/docgen.go index c9d8e8aa4..f9e614677 100644 --- a/api/docgen/docgen.go +++ b/api/docgen/docgen.go @@ -26,7 +26,7 @@ import ( "github.com/ipfs/go-cid" "github.com/ipfs/go-filestore" "github.com/libp2p/go-libp2p-core/network" - peer "github.com/libp2p/go-libp2p-peer" + "github.com/libp2p/go-libp2p-core/peer" "github.com/multiformats/go-multiaddr" ) @@ -66,7 +66,7 @@ func init() { ExampleValues[reflect.TypeOf(addr)] = addr - pid, err := peer.IDB58Decode("12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf") + pid, err := peer.Decode("12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf") if err != nil { panic(err) } diff --git a/api/test/deals.go b/api/test/deals.go index d36f57eb5..fc469da15 100644 --- a/api/test/deals.go +++ b/api/test/deals.go @@ -141,7 +141,7 @@ func makeDeal(t *testing.T, ctx context.Context, rseed int, client *impl.FullNod info, err := client.ClientGetDealInfo(ctx, *deal) require.NoError(t, err) - testRetrieval(t, ctx, err, client, fcid, &info.PieceCID, carExport, data) + testRetrieval(t, ctx, client, fcid, &info.PieceCID, carExport, data) } func TestFastRetrievalDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) { @@ -193,7 +193,7 @@ func TestFastRetrievalDealFlow(t *testing.T, b APIBuilder, blocktime time.Durati info, err := client.ClientGetDealInfo(ctx, *deal) require.NoError(t, err) - testRetrieval(t, ctx, err, client, fcid, &info.PieceCID, false, data) + testRetrieval(t, ctx, client, fcid, &info.PieceCID, false, data) atomic.AddInt64(&mine, -1) fmt.Println("shutting down mining") <-done @@ -267,7 +267,7 @@ func TestSenondDealRetrieval(t *testing.T, b APIBuilder, blocktime time.Duration rf, _ := miner.SectorsRefs(ctx) fmt.Printf("refs: %+v\n", rf) - testRetrieval(t, ctx, err, client, fcid2, &info.PieceCID, false, data2) + testRetrieval(t, ctx, client, fcid2, &info.PieceCID, false, data2) } atomic.AddInt64(&mine, -1) @@ -373,7 +373,7 @@ func startSealingWaiting(t *testing.T, ctx context.Context, miner TestStorageNod } } -func testRetrieval(t *testing.T, ctx context.Context, err error, client *impl.FullNodeAPI, fcid cid.Cid, piece *cid.Cid, carExport bool, data []byte) { +func testRetrieval(t *testing.T, ctx context.Context, client *impl.FullNodeAPI, fcid cid.Cid, piece *cid.Cid, carExport bool, data []byte) { offers, err := client.ClientFindData(ctx, fcid, piece) if err != nil { t.Fatal(err) diff --git a/api/test/mining.go b/api/test/mining.go index ee1268ed2..07070101b 100644 --- a/api/test/mining.go +++ b/api/test/mining.go @@ -20,6 +20,7 @@ import ( "github.com/filecoin-project/lotus/node/impl" ) +//nolint:deadcode,varcheck var log = logging.Logger("apitest") func (ts *testSuite) testMining(t *testing.T) { diff --git a/api/test/paych.go b/api/test/paych.go index 09e6f5d96..faa0bf8d9 100644 --- a/api/test/paych.go +++ b/api/test/paych.go @@ -153,6 +153,9 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) { }, int(build.MessageConfidence)+1, build.SealRandomnessLookbackLimit, func(oldTs, newTs *types.TipSet) (bool, events.StateChange, error) { return preds.OnPaymentChannelActorChanged(channel, preds.OnToSendAmountChanges())(ctx, oldTs.Key(), newTs.Key()) }) + if err != nil { + t.Fatal(err) + } select { case <-finished: diff --git a/api/test/window_post.go b/api/test/window_post.go index e2a553c21..7dd4a0742 100644 --- a/api/test/window_post.go +++ b/api/test/window_post.go @@ -24,9 +24,14 @@ import ( "github.com/filecoin-project/lotus/node/impl" ) -func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) { - os.Setenv("BELLMAN_NO_GPU", "1") +func init() { + err := os.Setenv("BELLMAN_NO_GPU", "1") + if err != nil { + panic(fmt.Sprintf("failed to set BELLMAN_NO_GPU env variable: %s", err)) + } +} +func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) { ctx := context.Background() n, sn := b(t, 1, OneMiner) client := n[0].FullNode.(*impl.FullNodeAPI) @@ -110,8 +115,6 @@ func pledgeSectors(t *testing.T, ctx context.Context, miner TestStorageNode, n, } func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) { - os.Setenv("BELLMAN_NO_GPU", "1") - ctx := context.Background() n, sn := b(t, 1, OneMiner) client := n[0].FullNode.(*impl.FullNodeAPI) diff --git a/chain/block_receipt_tracker.go b/chain/block_receipt_tracker.go index 466adef9d..a4a6743d1 100644 --- a/chain/block_receipt_tracker.go +++ b/chain/block_receipt_tracker.go @@ -7,8 +7,8 @@ import ( "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" - "github.com/hashicorp/golang-lru" - peer "github.com/libp2p/go-libp2p-core/peer" + lru "github.com/hashicorp/golang-lru" + "github.com/libp2p/go-libp2p-core/peer" ) type blockReceiptTracker struct { diff --git a/chain/blocksync/client.go b/chain/blocksync/client.go index bc1826527..f5a88a525 100644 --- a/chain/blocksync/client.go +++ b/chain/blocksync/client.go @@ -172,7 +172,7 @@ func (client *BlockSync) processResponse( resLength, req.Length) } if resLength < int(req.Length) && res.Status != Partial { - return nil, xerrors.Errorf("got less than requested without a proper status: %s", res.Status) + return nil, xerrors.Errorf("got less than requested without a proper status: %d", res.Status) } validRes := &validatedResponse{} @@ -205,7 +205,7 @@ func (client *BlockSync) processResponse( validRes.messages = make([]*CompactedMessages, resLength) for i := 0; i < resLength; i++ { if res.Chain[i].Messages == nil { - return nil, xerrors.Errorf("no messages included for tipset at height (head - %d): %w", i) + return nil, xerrors.Errorf("no messages included for tipset at height (head - %d)", i) } validRes.messages[i] = res.Chain[i].Messages } diff --git a/chain/blocksync/protocol.go b/chain/blocksync/protocol.go index 5a499f367..6a2861b80 100644 --- a/chain/blocksync/protocol.go +++ b/chain/blocksync/protocol.go @@ -1,9 +1,10 @@ package blocksync import ( + "time" + "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/store" - "time" "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log" diff --git a/chain/events/state/diff_adt.go b/chain/events/state/diff_adt.go index 1b921dd9e..39d7e8556 100644 --- a/chain/events/state/diff_adt.go +++ b/chain/events/state/diff_adt.go @@ -2,6 +2,7 @@ package state import ( "bytes" + "github.com/filecoin-project/specs-actors/actors/util/adt" typegen "github.com/whyrusleeping/cbor-gen" ) diff --git a/chain/events/state/predicates.go b/chain/events/state/predicates.go index bf85f1f1a..2019a38eb 100644 --- a/chain/events/state/predicates.go +++ b/chain/events/state/predicates.go @@ -3,6 +3,7 @@ package state import ( "bytes" "context" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi/big" diff --git a/chain/events/state/predicates_test.go b/chain/events/state/predicates_test.go index 27354105e..944b7e61c 100644 --- a/chain/events/state/predicates_test.go +++ b/chain/events/state/predicates_test.go @@ -114,10 +114,10 @@ func TestMarketPredicates(t *testing.T) { } oldBalances := map[address.Address]balance{ - tutils.NewIDAddr(t, 1): balance{abi.NewTokenAmount(1000), abi.NewTokenAmount(1000)}, - tutils.NewIDAddr(t, 2): balance{abi.NewTokenAmount(2000), abi.NewTokenAmount(500)}, - tutils.NewIDAddr(t, 3): balance{abi.NewTokenAmount(3000), abi.NewTokenAmount(2000)}, - tutils.NewIDAddr(t, 5): balance{abi.NewTokenAmount(3000), abi.NewTokenAmount(1000)}, + tutils.NewIDAddr(t, 1): {abi.NewTokenAmount(1000), abi.NewTokenAmount(1000)}, + tutils.NewIDAddr(t, 2): {abi.NewTokenAmount(2000), abi.NewTokenAmount(500)}, + tutils.NewIDAddr(t, 3): {abi.NewTokenAmount(3000), abi.NewTokenAmount(2000)}, + tutils.NewIDAddr(t, 5): {abi.NewTokenAmount(3000), abi.NewTokenAmount(1000)}, } oldStateC := createMarketState(ctx, t, store, oldDeals, oldProps, oldBalances) @@ -162,10 +162,10 @@ func TestMarketPredicates(t *testing.T) { // NB: DealProposals cannot be modified, so don't test that case. } newBalances := map[address.Address]balance{ - tutils.NewIDAddr(t, 1): balance{abi.NewTokenAmount(3000), abi.NewTokenAmount(0)}, - tutils.NewIDAddr(t, 2): balance{abi.NewTokenAmount(2000), abi.NewTokenAmount(500)}, - tutils.NewIDAddr(t, 4): balance{abi.NewTokenAmount(5000), abi.NewTokenAmount(0)}, - tutils.NewIDAddr(t, 5): balance{abi.NewTokenAmount(1000), abi.NewTokenAmount(3000)}, + tutils.NewIDAddr(t, 1): {abi.NewTokenAmount(3000), abi.NewTokenAmount(0)}, + tutils.NewIDAddr(t, 2): {abi.NewTokenAmount(2000), abi.NewTokenAmount(500)}, + tutils.NewIDAddr(t, 4): {abi.NewTokenAmount(5000), abi.NewTokenAmount(0)}, + tutils.NewIDAddr(t, 5): {abi.NewTokenAmount(1000), abi.NewTokenAmount(3000)}, } newStateC := createMarketState(ctx, t, store, newDeals, newProps, newBalances) @@ -505,6 +505,7 @@ func createBalanceTable(ctx context.Context, t *testing.T, store adt.Store, bala lockedMapRootCid, err := lockedMapRoot.Root() require.NoError(t, err) lockedRoot, err := adt.AsBalanceTable(store, lockedMapRootCid) + require.NoError(t, err) for addr, balance := range balances { err := escrowRoot.Add(addr, big.Add(balance.available, balance.locked)) @@ -542,6 +543,7 @@ func createEmptyMinerState(ctx context.Context, t *testing.T, store adt.Store, o emptyVestingFunds := miner.ConstructVestingFunds() emptyVestingFundsCid, err := store.Put(store.Context(), emptyVestingFunds) + require.NoError(t, err) emptyDeadlines := miner.ConstructDeadlines(emptyDeadline) emptyDeadlinesCid, err := store.Put(store.Context(), emptyDeadlines) diff --git a/chain/gen/gen.go b/chain/gen/gen.go index e34bb586b..551c3703f 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -41,10 +41,11 @@ import ( "github.com/filecoin-project/lotus/node/repo" ) -var log = logging.Logger("gen") - const msgsPerBlock = 20 +//nolint:deadcode,varcheck +var log = logging.Logger("gen") + var ValidWpostForTesting = []abi.PoStProof{{ ProofBytes: []byte("valid proof"), }} @@ -605,7 +606,7 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch, buf := new(bytes.Buffer) if err := miner.MarshalCBOR(buf); err != nil { - return nil, xerrors.Errorf("failed to cbor marshal address: %w") + return nil, xerrors.Errorf("failed to cbor marshal address: %w", err) } electionRand, err := store.DrawRandomness(brand.Data, crypto.DomainSeparationTag_ElectionProofProduction, round, buf.Bytes()) diff --git a/chain/gen/genesis/miners.go b/chain/gen/genesis/miners.go index 04c121d41..770581238 100644 --- a/chain/gen/genesis/miners.go +++ b/chain/gen/genesis/miners.go @@ -129,6 +129,9 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid return nil }) + if err != nil { + return cid.Undef, xerrors.Errorf("mutating state: %w", err) + } } // Add market funds @@ -217,9 +220,12 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid } err = vm.MutateState(ctx, builtin.RewardActorAddr, func(sct cbor.IpldStore, st *reward.State) error { - st = reward.ConstructState(qaPow) + *st = *reward.ConstructState(qaPow) return nil }) + if err != nil { + return cid.Undef, xerrors.Errorf("mutating state: %w", err) + } } for i, m := range miners { @@ -244,7 +250,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid // we've added fake power for this sector above, remove it now err = vm.MutateState(ctx, builtin.StoragePowerActorAddr, func(cst cbor.IpldStore, st *power.State) error { - st.TotalQualityAdjPower = types.BigSub(st.TotalQualityAdjPower, sectorWeight) + st.TotalQualityAdjPower = types.BigSub(st.TotalQualityAdjPower, sectorWeight) //nolint:scopelint st.TotalRawBytePower = types.BigSub(st.TotalRawBytePower, types.NewInt(uint64(m.SectorSize))) return nil }) diff --git a/chain/gen/genesis/util.go b/chain/gen/genesis/util.go index e78f6a0d2..10081c763 100644 --- a/chain/gen/genesis/util.go +++ b/chain/gen/genesis/util.go @@ -21,10 +21,6 @@ func mustEnc(i cbg.CBORMarshaler) []byte { return enc } -func doExec(ctx context.Context, vm *vm.VM, to, from address.Address, method abi.MethodNum, params []byte) ([]byte, error) { - return doExecValue(ctx, vm, to, from, types.NewInt(0), method, params) -} - func doExecValue(ctx context.Context, vm *vm.VM, to, from address.Address, value types.BigInt, method abi.MethodNum, params []byte) ([]byte, error) { act, err := vm.StateTree().GetActor(from) if err != nil { diff --git a/chain/market/fundmgr_test.go b/chain/market/fundmgr_test.go index d1b0fb7e6..5e8800528 100644 --- a/chain/market/fundmgr_test.go +++ b/chain/market/fundmgr_test.go @@ -147,6 +147,7 @@ func TestAddFunds(t *testing.T) { } for testCase, data := range testCases { + //nolint:scopelint t.Run(testCase, func(t *testing.T) { ctx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() diff --git a/chain/messagepool/block_proba.go b/chain/messagepool/block_proba.go index 6634f5b46..61bb018d7 100644 --- a/chain/messagepool/block_proba.go +++ b/chain/messagepool/block_proba.go @@ -56,7 +56,7 @@ func binomialCoefficient(n, k float64) float64 { for d := 1.0; d <= k; d++ { r *= n r /= d - n -= 1 + n-- } return r } diff --git a/chain/messagepool/provider.go b/chain/messagepool/provider.go index a6aa79ef6..fa8b8ea83 100644 --- a/chain/messagepool/provider.go +++ b/chain/messagepool/provider.go @@ -43,7 +43,7 @@ func (mpp *mpoolProvider) PutMessage(m types.ChainMsg) (cid.Cid, error) { } func (mpp *mpoolProvider) PubSubPublish(k string, v []byte) error { - return mpp.ps.Publish(k, v) + return mpp.ps.Publish(k, v) //nolint } func (mpp *mpoolProvider) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) { diff --git a/chain/metrics/consensus.go b/chain/metrics/consensus.go index 7d19d5bd6..25e299247 100644 --- a/chain/metrics/consensus.go +++ b/chain/metrics/consensus.go @@ -44,7 +44,7 @@ func SendHeadNotifs(nickname string) func(mctx helpers.MetricsCtx, lc fx.Lifecyc } }() go func() { - sub, err := ps.Subscribe(topic) + sub, err := ps.Subscribe(topic) //nolint if err != nil { return } @@ -116,6 +116,7 @@ func sendHeadNotifs(ctx context.Context, ps *pubsub.PubSub, topic string, chain return err } + //nolint if err := ps.Publish(topic, b); err != nil { return err } diff --git a/chain/state/statetree.go b/chain/state/statetree.go index d2a98b1e4..c083f1817 100644 --- a/chain/state/statetree.go +++ b/chain/state/statetree.go @@ -246,7 +246,7 @@ func (st *StateTree) DeleteActor(addr address.Address) error { } func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) { - ctx, span := trace.StartSpan(ctx, "stateTree.Flush") + ctx, span := trace.StartSpan(ctx, "stateTree.Flush") //nolint:staticcheck defer span.End() if len(st.snaps.layers) != 1 { return cid.Undef, xerrors.Errorf("tried to flush state tree with snapshots on the stack") @@ -268,7 +268,7 @@ func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) { } func (st *StateTree) Snapshot(ctx context.Context) error { - ctx, span := trace.StartSpan(ctx, "stateTree.SnapShot") + ctx, span := trace.StartSpan(ctx, "stateTree.SnapShot") //nolint:staticcheck defer span.End() st.snaps.addLayer() diff --git a/chain/store/index_test.go b/chain/store/index_test.go index 9443b4c07..5c49c6791 100644 --- a/chain/store/index_test.go +++ b/chain/store/index_test.go @@ -42,7 +42,7 @@ func TestIndexSeeks(t *testing.T) { if err := cs.PutTipSet(ctx, mock.TipSet(gen)); err != nil { t.Fatal(err) } - cs.SetGenesis(gen) + assert.NoError(t, cs.SetGenesis(gen)) // Put 113 blocks from genesis for i := 0; i < 113; i++ { diff --git a/chain/store/store.go b/chain/store/store.go index 9c424dc3b..139444f67 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -925,7 +925,7 @@ func (cs *ChainStore) LoadMessagesFromCids(cids []cid.Cid) ([]*types.Message, er for i, c := range cids { m, err := cs.GetMessage(c) if err != nil { - return nil, xerrors.Errorf("failed to get message: (%s):%d: %w", err, c, i) + return nil, xerrors.Errorf("failed to get message: (%s):%d: %w", c, i, err) } msgs = append(msgs, m) @@ -939,7 +939,7 @@ func (cs *ChainStore) LoadSignedMessagesFromCids(cids []cid.Cid) ([]*types.Signe for i, c := range cids { m, err := cs.GetSignedMessage(c) if err != nil { - return nil, xerrors.Errorf("failed to get message: (%s):%d: %w", err, c, i) + return nil, xerrors.Errorf("failed to get message: (%s):%d: %w", c, i, err) } msgs = append(msgs, m) diff --git a/chain/sub/incoming.go b/chain/sub/incoming.go index 561d2c3f1..c036bf1f6 100644 --- a/chain/sub/incoming.go +++ b/chain/sub/incoming.go @@ -292,10 +292,9 @@ func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub log.Warnf("received block from unknown miner or miner that doesn't meet min power over pubsub; rejecting message") recordFailure("unknown_miner") return pubsub.ValidationReject - } else { - log.Warnf("cannot validate block message; unknown miner or miner that doesn't meet min power in unsynced chain") - return pubsub.ValidationIgnore } + log.Warnf("cannot validate block message; unknown miner or miner that doesn't meet min power in unsynced chain") + return pubsub.ValidationIgnore } err = sigs.CheckBlockSignature(ctx, blk.Header, key) diff --git a/chain/sync_manager.go b/chain/sync_manager.go index e3fbdf4e1..8c77b47c5 100644 --- a/chain/sync_manager.go +++ b/chain/sync_manager.go @@ -343,12 +343,12 @@ func (sm *SyncManager) scheduleProcessResult(res *syncResult) { sm.syncQueue.buckets = append(sm.syncQueue.buckets, relbucket) } return - } else { - // TODO: this is the case where we try to sync a chain, and - // fail, and we have more blocks on top of that chain that - // have come in since. The question is, should we try to - // sync these? or just drop them? } + // TODO: this is the case where we try to sync a chain, and + // fail, and we have more blocks on top of that chain that + // have come in since. The question is, should we try to + // sync these? or just drop them? + log.Error("failed to sync chain but have new unconnected blocks from chain") } if sm.nextSyncTarget == nil && !sm.syncQueue.Empty() { diff --git a/chain/sync_test.go b/chain/sync_test.go index 2774571b2..cf1385baa 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -3,11 +3,12 @@ package chain_test import ( "context" "fmt" - "github.com/ipfs/go-cid" "os" "testing" "time" + "github.com/ipfs/go-cid" + ds "github.com/ipfs/go-datastore" logging "github.com/ipfs/go-log/v2" "github.com/libp2p/go-libp2p-core/peer" @@ -36,7 +37,10 @@ import ( func init() { build.InsecurePoStValidation = true - os.Setenv("TRUST_PARAMS", "1") + err := os.Setenv("TRUST_PARAMS", "1") + if err != nil { + panic(err) + } miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ abi.RegisteredSealProof_StackedDrg2KiBV1: {}, } @@ -212,20 +216,6 @@ func (tu *syncTestUtil) mineNewBlock(src int, miners []int) { tu.g.CurTipset = mts } -func fblkToBlkMsg(fb *types.FullBlock) *types.BlockMsg { - out := &types.BlockMsg{ - Header: fb.Header, - } - - for _, msg := range fb.BlsMessages { - out.BlsMessages = append(out.BlsMessages, msg.Cid()) - } - for _, msg := range fb.SecpkMessages { - out.SecpkMessages = append(out.SecpkMessages, msg.Cid()) - } - return out -} - func (tu *syncTestUtil) addSourceNode(gen int) { if tu.genesis != nil { tu.t.Fatal("source node already exists") @@ -454,7 +444,7 @@ func (wpp badWpp) GenerateCandidates(context.Context, abi.PoStRandomness, uint64 func (wpp badWpp) ComputeProof(context.Context, []abi.SectorInfo, abi.PoStRandomness) ([]abi.PoStProof, error) { return []abi.PoStProof{ - abi.PoStProof{ + { PoStProof: abi.RegisteredPoStProof_StackedDrgWinning2KiBV1, ProofBytes: []byte("evil"), }, @@ -587,7 +577,7 @@ func TestDuplicateNonce(t *testing.T) { msgs := make([][]*types.SignedMessage, 2) // Each miner includes a message from the banker with the same nonce, but to different addresses - for k, _ := range msgs { + for k := range msgs { msgs[k] = []*types.SignedMessage{makeMsg(tu.g.Miners[k])} } diff --git a/chain/types/signedmessage.go b/chain/types/signedmessage.go index 77374ca38..47592feb1 100644 --- a/chain/types/signedmessage.go +++ b/chain/types/signedmessage.go @@ -62,8 +62,8 @@ func (sm *SignedMessage) Serialize() ([]byte, error) { return buf.Bytes(), nil } -func (m *SignedMessage) ChainLength() int { - ser, err := m.Serialize() +func (sm *SignedMessage) ChainLength() int { + ser, err := sm.Serialize() if err != nil { panic(err) } diff --git a/chain/types/tipset.go b/chain/types/tipset.go index 271301ea6..4217d2a86 100644 --- a/chain/types/tipset.go +++ b/chain/types/tipset.go @@ -238,3 +238,7 @@ func (ts *TipSet) IsChildOf(parent *TipSet) bool { // height for their processing logic at the moment to obviate it. ts.height > parent.height } + +func (ts *TipSet) String() string { + return fmt.Sprintf("%v", ts.cids) +} diff --git a/chain/validation/factories.go b/chain/validation/factories.go index 6d5386023..b7781cacc 100644 --- a/chain/validation/factories.go +++ b/chain/validation/factories.go @@ -2,6 +2,7 @@ package validation import ( "context" + "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/specs-actors/actors/runtime" cbor "github.com/ipfs/go-ipld-cbor" diff --git a/chain/validation/keymanager.go b/chain/validation/keymanager.go index a826d5ea0..95fbf2142 100644 --- a/chain/validation/keymanager.go +++ b/chain/validation/keymanager.go @@ -2,9 +2,10 @@ package validation import ( "fmt" - "github.com/minio/blake2b-simd" "math/rand" + "github.com/minio/blake2b-simd" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-crypto" acrypto "github.com/filecoin-project/specs-actors/actors/crypto" diff --git a/chain/vectors/vectors_test.go b/chain/vectors/vectors_test.go index 77073a07e..68cc5ac45 100644 --- a/chain/vectors/vectors_test.go +++ b/chain/vectors/vectors_test.go @@ -18,7 +18,7 @@ func LoadVector(t *testing.T, f string, out interface{}) { if err != nil { t.Fatal(err) } - defer fi.Close() + defer fi.Close() //nolint:errcheck if err := json.NewDecoder(fi).Decode(out); err != nil { t.Fatal(err) diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 772bc9750..d39c14beb 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -410,8 +410,10 @@ type shimStateHandle struct { func (ssh *shimStateHandle) Create(obj vmr.CBORMarshaler) { c := ssh.rt.Put(obj) - // TODO: handle error below - ssh.rt.stateCommit(EmptyObjectCid, c) + err := ssh.rt.stateCommit(EmptyObjectCid, c) + if err != nil { + panic(fmt.Errorf("failed to commit state after creating object: %w", err)) + } } func (ssh *shimStateHandle) Readonly(obj vmr.CBORUnmarshaler) { @@ -440,8 +442,10 @@ func (ssh *shimStateHandle) Transaction(obj vmr.CBORer, f func()) { c := ssh.rt.Put(obj) - // TODO: handle error below - ssh.rt.stateCommit(baseState, c) + err = ssh.rt.stateCommit(baseState, c) + if err != nil { + panic(fmt.Errorf("failed to commit state after transaction: %w", err)) + } } func (rt *Runtime) GetBalance(a address.Address) (types.BigInt, aerrors.ActorError) { diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 42570392f..7be5417b7 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -254,6 +254,9 @@ func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime, if aerr := rt.chargeGasSafe(rt.Pricelist().OnMethodInvocation(msg.Value, msg.Method)); aerr != nil { return nil, aerrors.Wrap(aerr, "not enough gas for method invocation") } + + // not charging any gas, just logging + //nolint:errcheck defer rt.chargeGasSafe(newGasCharge("OnMethodInvocationDone", 0, 0)) if types.BigCmp(msg.Value, types.NewInt(0)) != 0 { diff --git a/cli/auth.go b/cli/auth.go index 40947d797..ba20b2bcc 100644 --- a/cli/auth.go +++ b/cli/auth.go @@ -2,6 +2,7 @@ package cli import ( "fmt" + "github.com/urfave/cli/v2" "golang.org/x/xerrors" diff --git a/cli/chain.go b/cli/chain.go index 22c35abb3..1f8339e93 100644 --- a/cli/chain.go +++ b/cli/chain.go @@ -319,7 +319,7 @@ var chainSetHeadCmd = &cli.Command{ ts, err = api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Uint64("epoch")), types.EmptyTSK) } if ts == nil { - ts, err = parseTipSet(api, ctx, cctx.Args().Slice()) + ts, err = parseTipSet(ctx, api, cctx.Args().Slice()) } if err != nil { return err @@ -337,7 +337,7 @@ var chainSetHeadCmd = &cli.Command{ }, } -func parseTipSet(api api.FullNode, ctx context.Context, vals []string) (*types.TipSet, error) { +func parseTipSet(ctx context.Context, api api.FullNode, vals []string) (*types.TipSet, error) { var headers []*types.BlockHeader for _, c := range vals { blkc, err := cid.Decode(c) diff --git a/cli/client.go b/cli/client.go index 159fef41b..008ca8799 100644 --- a/cli/client.go +++ b/cli/client.go @@ -930,11 +930,11 @@ var clientQueryAskCmd = &cli.Command{ return xerrors.Errorf("failed to get peerID for miner: %w", err) } - if peer.ID(*mi.PeerId) == peer.ID("SETME") { + if *mi.PeerId == peer.ID("SETME") { return fmt.Errorf("the miner hasn't initialized yet") } - pid = peer.ID(*mi.PeerId) + pid = *mi.PeerId } ask, err := api.ClientQueryAsk(ctx, pid, maddr) @@ -1045,55 +1045,55 @@ var clientListDeals = &cli.Command{ fmt.Fprintf(w, "%s\t%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%d\t%s\n", d.LocalDeal.CreationTime.Format(time.Stamp), d.LocalDeal.ProposalCid, d.LocalDeal.DealID, d.LocalDeal.Provider, dealStateString(color, d.LocalDeal.State), onChain, slashed, d.LocalDeal.PieceCID, types.SizeStr(types.NewInt(d.LocalDeal.Size)), price, d.LocalDeal.Duration, d.LocalDeal.Message) } return w.Flush() - } else { - w := tablewriter.New(tablewriter.Col("DealCid"), - tablewriter.Col("DealId"), - tablewriter.Col("Provider"), - tablewriter.Col("State"), - tablewriter.Col("On Chain?"), - tablewriter.Col("Slashed?"), - tablewriter.Col("PieceCID"), - tablewriter.Col("Size"), - tablewriter.Col("Price"), - tablewriter.Col("Duration"), - tablewriter.NewLineCol("Message")) + } - for _, d := range deals { - propcid := d.LocalDeal.ProposalCid.String() - propcid = "..." + propcid[len(propcid)-8:] + w := tablewriter.New(tablewriter.Col("DealCid"), + tablewriter.Col("DealId"), + tablewriter.Col("Provider"), + tablewriter.Col("State"), + tablewriter.Col("On Chain?"), + tablewriter.Col("Slashed?"), + tablewriter.Col("PieceCID"), + tablewriter.Col("Size"), + tablewriter.Col("Price"), + tablewriter.Col("Duration"), + tablewriter.NewLineCol("Message")) - onChain := "N" - if d.OnChainDealState.SectorStartEpoch != -1 { - onChain = fmt.Sprintf("Y (epoch %d)", d.OnChainDealState.SectorStartEpoch) - } + for _, d := range deals { + propcid := d.LocalDeal.ProposalCid.String() + propcid = "..." + propcid[len(propcid)-8:] - slashed := "N" - if d.OnChainDealState.SlashEpoch != -1 { - slashed = fmt.Sprintf("Y (epoch %d)", d.OnChainDealState.SlashEpoch) - } - - piece := d.LocalDeal.PieceCID.String() - piece = "..." + piece[len(piece)-8:] - - price := types.FIL(types.BigMul(d.LocalDeal.PricePerEpoch, types.NewInt(d.LocalDeal.Duration))) - - w.Write(map[string]interface{}{ - "DealCid": propcid, - "DealId": d.LocalDeal.DealID, - "Provider": d.LocalDeal.Provider, - "State": dealStateString(color, d.LocalDeal.State), - "On Chain?": onChain, - "Slashed?": slashed, - "PieceCID": piece, - "Size": types.SizeStr(types.NewInt(d.LocalDeal.Size)), - "Price": price, - "Duration": d.LocalDeal.Duration, - "Message": d.LocalDeal.Message, - }) + onChain := "N" + if d.OnChainDealState.SectorStartEpoch != -1 { + onChain = fmt.Sprintf("Y (epoch %d)", d.OnChainDealState.SectorStartEpoch) } - return w.Flush(os.Stdout) + slashed := "N" + if d.OnChainDealState.SlashEpoch != -1 { + slashed = fmt.Sprintf("Y (epoch %d)", d.OnChainDealState.SlashEpoch) + } + + piece := d.LocalDeal.PieceCID.String() + piece = "..." + piece[len(piece)-8:] + + price := types.FIL(types.BigMul(d.LocalDeal.PricePerEpoch, types.NewInt(d.LocalDeal.Duration))) + + w.Write(map[string]interface{}{ + "DealCid": propcid, + "DealId": d.LocalDeal.DealID, + "Provider": d.LocalDeal.Provider, + "State": dealStateString(color, d.LocalDeal.State), + "On Chain?": onChain, + "Slashed?": slashed, + "PieceCID": piece, + "Size": types.SizeStr(types.NewInt(d.LocalDeal.Size)), + "Price": price, + "Duration": d.LocalDeal.Duration, + "Message": d.LocalDeal.Message, + }) } + + return w.Flush(os.Stdout) }, } @@ -1318,7 +1318,7 @@ func OutputDataTransferChannels(out io.Writer, channels []lapi.DataTransferChann for _, channel := range sendingChannels { w.Write(toChannelOutput(color, "Sending To", channel)) } - w.Flush(out) + w.Flush(out) //nolint:errcheck fmt.Fprintf(out, "\nReceiving Channels\n\n") w = tablewriter.New(tablewriter.Col("ID"), @@ -1332,7 +1332,7 @@ func OutputDataTransferChannels(out io.Writer, channels []lapi.DataTransferChann for _, channel := range receivingChannels { w.Write(toChannelOutput(color, "Receiving From", channel)) } - w.Flush(out) + w.Flush(out) //nolint:errcheck } func channelStatusString(useColor bool, status datatransfer.Status) string { diff --git a/cli/helper.go b/cli/helper.go index 536301e87..70a168145 100644 --- a/cli/helper.go +++ b/cli/helper.go @@ -39,7 +39,7 @@ func RunApp(app *cli.App) { } var phe *PrintHelpErr if xerrors.As(err, &phe) { - cli.ShowCommandHelp(phe.Ctx, phe.Ctx.Command.Name) + _ = cli.ShowCommandHelp(phe.Ctx, phe.Ctx.Command.Name) } os.Exit(1) } diff --git a/cli/mpool.go b/cli/mpool.go index 62ab06dae..eed507482 100644 --- a/cli/mpool.go +++ b/cli/mpool.go @@ -313,7 +313,7 @@ var mpoolReplaceCmd = &cli.Command{ if err != nil { return fmt.Errorf("parsing gas-premium: %w", err) } - // TODO: estiamte fee cap here + // 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) diff --git a/cli/net.go b/cli/net.go index fb902e39c..6dd11d045 100644 --- a/cli/net.go +++ b/cli/net.go @@ -180,7 +180,7 @@ var netFindPeer = &cli.Command{ return nil } - pid, err := peer.IDB58Decode(cctx.Args().First()) + pid, err := peer.Decode(cctx.Args().First()) if err != nil { return err } diff --git a/cli/pprof.go b/cli/pprof.go index 50a67ef86..2ac4206b5 100644 --- a/cli/pprof.go +++ b/cli/pprof.go @@ -44,7 +44,7 @@ var PprofGoroutines = &cli.Command{ addr = "http://" + addr + "/debug/pprof/goroutine?debug=2" - r, err := http.Get(addr) + r, err := http.Get(addr) //nolint:gosec if err != nil { return err } diff --git a/cli/state.go b/cli/state.go index c49994e2a..1e75cc7cd 100644 --- a/cli/state.go +++ b/cli/state.go @@ -353,6 +353,9 @@ var stateReplaySetCmd = &cli.Command{ } ts, err = types.NewTipSet(headers) + if err != nil { + return err + } } else { var r *api.MsgLookup r, err = fapi.StateWaitMsg(ctx, mcid, build.MessageConfidence) @@ -365,9 +368,9 @@ var stateReplaySetCmd = &cli.Command{ return xerrors.Errorf("loading tipset: %w", err) } ts, err = fapi.ChainGetTipSet(ctx, childTs.Parents()) - } - if err != nil { - return err + if err != nil { + return err + } } } @@ -1499,7 +1502,7 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er } p.Elem().Field(i).Set(reflect.ValueOf(val)) case reflect.TypeOf(peer.ID("")): - pid, err := peer.IDB58Decode(args[i]) + pid, err := peer.Decode(args[i]) if err != nil { return nil, fmt.Errorf("failed to parse peer ID: %s", err) } @@ -1584,6 +1587,9 @@ var stateMarketBalanceCmd = &cli.Command{ } balance, err := api.StateMarketBalance(ctx, addr, ts.Key()) + if err != nil { + return err + } fmt.Printf("Escrow: %s\n", types.FIL(balance.Escrow)) fmt.Printf("Locked: %s\n", types.FIL(balance.Locked)) diff --git a/cli/wallet.go b/cli/wallet.go index 29f0b2db9..025e3a7b6 100644 --- a/cli/wallet.go +++ b/cli/wallet.go @@ -385,10 +385,9 @@ var walletVerify = &cli.Command{ if api.WalletVerify(ctx, addr, msg, &sig) { fmt.Println("valid") return nil - } else { - fmt.Println("invalid") - return NewCliError("CLI Verify called with invalid signature") } + fmt.Println("invalid") + return NewCliError("CLI Verify called with invalid signature") }, } diff --git a/cmd/lotus-bench/import.go b/cmd/lotus-bench/import.go index 9944adc0b..7400cd92e 100644 --- a/cmd/lotus-bench/import.go +++ b/cmd/lotus-bench/import.go @@ -214,7 +214,7 @@ func countGasCosts(et *types.ExecutionTrace) (int64, int64) { } for _, sub := range et.Subcalls { - c, v := countGasCosts(&sub) + c, v := countGasCosts(&sub) //nolint cgas += c vgas += v } @@ -222,24 +222,6 @@ func countGasCosts(et *types.ExecutionTrace) (int64, int64) { return cgas, vgas } -func compStats(vals []float64) (float64, float64) { - var sum float64 - - for _, v := range vals { - sum += v - } - - av := sum / float64(len(vals)) - - var varsum float64 - for _, v := range vals { - delta := av - v - varsum += delta * delta - } - - return av, math.Sqrt(varsum / float64(len(vals))) -} - type stats struct { timeTaken meanVar gasRatio meanVar @@ -264,20 +246,20 @@ func (cov1 *covar) VarianceX() float64 { return cov1.m2x / (cov1.n - 1) } -func (v1 *covar) StddevX() float64 { - return math.Sqrt(v1.VarianceX()) +func (cov1 *covar) StddevX() float64 { + return math.Sqrt(cov1.VarianceX()) } func (cov1 *covar) VarianceY() float64 { return cov1.m2y / (cov1.n - 1) } -func (v1 *covar) StddevY() float64 { - return math.Sqrt(v1.VarianceY()) +func (cov1 *covar) StddevY() float64 { + return math.Sqrt(cov1.VarianceY()) } func (cov1 *covar) AddPoint(x, y float64) { - cov1.n += 1 + cov1.n++ dx := x - cov1.meanX cov1.meanX += dx / cov1.n @@ -344,7 +326,7 @@ type meanVar struct { func (v1 *meanVar) AddPoint(value float64) { // based on https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm - v1.n += 1 + v1.n++ delta := value - v1.mean v1.mean += delta / v1.n delta2 := value - v1.mean @@ -481,7 +463,7 @@ var importAnalyzeCmd = &cli.Command{ } go func() { - http.ListenAndServe("localhost:6060", nil) + http.ListenAndServe("localhost:6060", nil) //nolint:errcheck }() fi, err := os.Open(cctx.Args().First()) diff --git a/cmd/lotus-chainwatch/processor/reward.go b/cmd/lotus-chainwatch/processor/reward.go index d6f2ddad0..230b3c6c1 100644 --- a/cmd/lotus-chainwatch/processor/reward.go +++ b/cmd/lotus-chainwatch/processor/reward.go @@ -159,7 +159,7 @@ func (p *Processor) persistRewardActors(ctx context.Context, rewards []rewardAct log.Debugw("Persisted Reward Actors", "duration", time.Since(start).String()) }() - grp, ctx := errgroup.WithContext(ctx) + grp, ctx := errgroup.WithContext(ctx) //nolint grp.Go(func() error { if err := p.storeChainPower(rewards); err != nil { diff --git a/cmd/lotus-chainwatch/run.go b/cmd/lotus-chainwatch/run.go index f5f1afa53..3442ec714 100644 --- a/cmd/lotus-chainwatch/run.go +++ b/cmd/lotus-chainwatch/run.go @@ -29,7 +29,7 @@ var runCmd = &cli.Command{ }, Action: func(cctx *cli.Context) error { go func() { - http.ListenAndServe(":6060", nil) + http.ListenAndServe(":6060", nil) //nolint:errcheck }() ll := cctx.String("log-level") if err := logging.SetLogLevel("*", ll); err != nil { diff --git a/cmd/lotus-chainwatch/scheduler/refresh_top_miners_by_base_reward.go b/cmd/lotus-chainwatch/scheduler/refresh_top_miners_by_base_reward.go index 550f7a2bd..b6a24507f 100644 --- a/cmd/lotus-chainwatch/scheduler/refresh_top_miners_by_base_reward.go +++ b/cmd/lotus-chainwatch/scheduler/refresh_top_miners_by_base_reward.go @@ -49,11 +49,11 @@ func setupTopMinerByBaseRewardSchema(ctx context.Context, db *sql.DB) error { order by 1 desc limit 1; `); err != nil { - return xerrors.Errorf("create top_miner_by_base_reward views", err) + return xerrors.Errorf("create top_miner_by_base_reward views: %w", err) } if err := tx.Commit(); err != nil { - return xerrors.Errorf("commiting top_miner_by_base_reward views", err) + return xerrors.Errorf("committing top_miner_by_base_reward views; %w", err) } return nil } diff --git a/cmd/lotus-chainwatch/scheduler/scheduler.go b/cmd/lotus-chainwatch/scheduler/scheduler.go index c2b02e325..936b61ce7 100644 --- a/cmd/lotus-chainwatch/scheduler/scheduler.go +++ b/cmd/lotus-chainwatch/scheduler/scheduler.go @@ -25,7 +25,7 @@ func PrepareScheduler(db *sql.DB) *Scheduler { func (s *Scheduler) setupSchema(ctx context.Context) error { if err := setupTopMinerByBaseRewardSchema(ctx, s.db); err != nil { - return xerrors.Errorf("setup top miners by reward schema", err) + return xerrors.Errorf("setup top miners by reward schema: %w", err) } return nil } @@ -35,14 +35,14 @@ func (s *Scheduler) Start(ctx context.Context) { log.Debug("Starting Scheduler") if err := s.setupSchema(ctx); err != nil { - log.Fatalw("applying scheduling schema", err) + log.Fatalw("applying scheduling schema", "error", err) } go func() { // run once on start after schema has initialized time.Sleep(5 * time.Second) if err := refreshTopMinerByBaseReward(ctx, s.db); err != nil { - log.Errorf(err.Error()) + log.Errorw("failed to refresh top miner", "error", err) } refreshTopMinerCh := time.NewTicker(30 * time.Second) defer refreshTopMinerCh.Stop() @@ -50,7 +50,7 @@ func (s *Scheduler) Start(ctx context.Context) { select { case <-refreshTopMinerCh.C: if err := refreshTopMinerByBaseReward(ctx, s.db); err != nil { - log.Errorf(err.Error()) + log.Errorw("failed to refresh top miner", "error", err) } case <-ctx.Done(): return diff --git a/cmd/lotus-fountain/main.go b/cmd/lotus-fountain/main.go index 8e3461595..021335cc3 100644 --- a/cmd/lotus-fountain/main.go +++ b/cmd/lotus-fountain/main.go @@ -47,7 +47,7 @@ var supportedSectors struct { } func init() { - for supportedSector, _ := range miner.SupportedProofTypes { + for supportedSector := range miner.SupportedProofTypes { sectorSize, err := supportedSector.SectorSize() if err != nil { panic(err) @@ -207,24 +207,24 @@ type handler struct { func (h *handler) minerhtml(w http.ResponseWriter, r *http.Request) { f, err := rice.MustFindBox("site").Open("_miner.html") if err != nil { - w.WriteHeader(500) - _, _ = w.Write([]byte(err.Error())) + http.Error(w, err.Error(), http.StatusInternalServerError) return } tmpl, err := ioutil.ReadAll(f) if err != nil { - w.WriteHeader(500) - _, _ = w.Write([]byte(err.Error())) + http.Error(w, err.Error(), http.StatusInternalServerError) return } var executedTmpl bytes.Buffer t, err := template.New("miner.html").Parse(string(tmpl)) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } if err := t.Execute(&executedTmpl, supportedSectors); err != nil { - w.WriteHeader(500) - _, _ = w.Write([]byte(err.Error())) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -238,8 +238,7 @@ func (h *handler) minerhtml(w http.ResponseWriter, r *http.Request) { func (h *handler) send(w http.ResponseWriter, r *http.Request) { to, err := address.NewFromString(r.FormValue("address")) if err != nil { - w.WriteHeader(400) - _, _ = w.Write([]byte(err.Error())) + http.Error(w, err.Error(), http.StatusBadRequest) return } @@ -282,8 +281,7 @@ func (h *handler) send(w http.ResponseWriter, r *http.Request) { To: to, }, nil) if err != nil { - w.WriteHeader(400) - _, _ = w.Write([]byte(err.Error())) + http.Error(w, err.Error(), http.StatusBadRequest) return } @@ -293,15 +291,15 @@ func (h *handler) send(w http.ResponseWriter, r *http.Request) { func (h *handler) mkminer(w http.ResponseWriter, r *http.Request) { owner, err := address.NewFromString(r.FormValue("address")) if err != nil { - w.WriteHeader(400) - _, _ = w.Write([]byte(err.Error())) + http.Error(w, err.Error(), http.StatusBadRequest) return } if owner.Protocol() != address.BLS { - w.WriteHeader(400) - _, _ = w.Write([]byte("Miner address must use BLS. A BLS address starts with the prefix 't3'.")) - _, _ = w.Write([]byte("Please create a BLS address by running \"lotus wallet new bls\" while connected to a Lotus node.")) + http.Error(w, + "Miner address must use BLS. A BLS address starts with the prefix 't3'."+ + "Please create a BLS address by running \"lotus wallet new bls\" while connected to a Lotus node.", + http.StatusBadRequest) return } @@ -346,16 +344,14 @@ func (h *handler) mkminer(w http.ResponseWriter, r *http.Request) { To: owner, }, nil) if err != nil { - w.WriteHeader(400) - w.Write([]byte("pushfunds: " + err.Error())) + http.Error(w, "pushfunds: "+err.Error(), http.StatusBadRequest) return } log.Infof("%s: push funds %s", owner, smsg.Cid()) spt, err := ffiwrapper.SealProofTypeFromSectorSize(abi.SectorSize(ssize)) if err != nil { - w.WriteHeader(400) - w.Write([]byte("sealprooftype: " + err.Error())) + http.Error(w, "sealprooftype: "+err.Error(), http.StatusBadRequest) return } @@ -366,8 +362,7 @@ func (h *handler) mkminer(w http.ResponseWriter, r *http.Request) { Peer: abi.PeerID(h.defaultMinerPeer), }) if err != nil { - w.WriteHeader(400) - w.Write([]byte(err.Error())) + http.Error(w, err.Error(), http.StatusBadRequest) return } @@ -382,66 +377,58 @@ func (h *handler) mkminer(w http.ResponseWriter, r *http.Request) { signed, err := h.api.MpoolPushMessage(r.Context(), createStorageMinerMsg, nil) if err != nil { - w.WriteHeader(400) - w.Write([]byte(err.Error())) + http.Error(w, err.Error(), http.StatusBadRequest) return } log.Infof("%s: create miner msg: %s", owner, signed.Cid()) - http.Redirect(w, r, fmt.Sprintf("/wait.html?f=%s&m=%s&o=%s", signed.Cid(), smsg.Cid(), owner), 303) + http.Redirect(w, r, fmt.Sprintf("/wait.html?f=%s&m=%s&o=%s", signed.Cid(), smsg.Cid(), owner), http.StatusSeeOther) } func (h *handler) msgwait(w http.ResponseWriter, r *http.Request) { c, err := cid.Parse(r.FormValue("cid")) if err != nil { - w.WriteHeader(400) - w.Write([]byte(err.Error())) + http.Error(w, err.Error(), http.StatusBadRequest) return } mw, err := h.api.StateWaitMsg(r.Context(), c, build.MessageConfidence) if err != nil { - w.WriteHeader(400) - w.Write([]byte(err.Error())) + http.Error(w, err.Error(), http.StatusBadRequest) return } if mw.Receipt.ExitCode != 0 { - w.WriteHeader(400) - w.Write([]byte(xerrors.Errorf("create miner failed: exit code %d", mw.Receipt.ExitCode).Error())) + http.Error(w, err.Error(), http.StatusBadRequest) return } - w.WriteHeader(200) + w.WriteHeader(http.StatusOK) } func (h *handler) msgwaitaddr(w http.ResponseWriter, r *http.Request) { c, err := cid.Parse(r.FormValue("cid")) if err != nil { - w.WriteHeader(400) - w.Write([]byte(err.Error())) + http.Error(w, err.Error(), http.StatusBadRequest) return } mw, err := h.api.StateWaitMsg(r.Context(), c, build.MessageConfidence) if err != nil { - w.WriteHeader(400) - w.Write([]byte(err.Error())) + http.Error(w, err.Error(), http.StatusBadRequest) return } if mw.Receipt.ExitCode != 0 { - w.WriteHeader(400) - w.Write([]byte(xerrors.Errorf("create miner failed: exit code %d", mw.Receipt.ExitCode).Error())) + http.Error(w, xerrors.Errorf("create miner failed: exit code %d", mw.Receipt.ExitCode).Error(), http.StatusBadRequest) return } - w.WriteHeader(200) + w.WriteHeader(http.StatusOK) var ma power.CreateMinerReturn if err := ma.UnmarshalCBOR(bytes.NewReader(mw.Receipt.Return)); err != nil { log.Errorf("%w", err) - w.WriteHeader(400) - w.Write([]byte(err.Error())) + http.Error(w, err.Error(), http.StatusBadRequest) return } diff --git a/cmd/lotus-keygen/main.go b/cmd/lotus-keygen/main.go index d4c7a2548..33124107e 100644 --- a/cmd/lotus-keygen/main.go +++ b/cmd/lotus-keygen/main.go @@ -54,7 +54,12 @@ func main() { if err != nil { return err } - defer fi.Close() + defer func() { + err2 := fi.Close() + if err == nil { + err = err2 + } + }() b, err := json.Marshal(ki) if err != nil { diff --git a/cmd/lotus-pcr/main.go b/cmd/lotus-pcr/main.go index 0540e843d..d86eb60e9 100644 --- a/cmd/lotus-pcr/main.go +++ b/cmd/lotus-pcr/main.go @@ -142,7 +142,7 @@ var runCmd = &cli.Command{ }, Action: func(cctx *cli.Context) error { go func() { - http.ListenAndServe(":6060", nil) + http.ListenAndServe(":6060", nil) //nolint:errcheck }() ctx := context.Background() @@ -445,7 +445,7 @@ func (r *refunder) Refund(ctx context.Context, tipset *types.TipSet, refunds *Mi // Calculate the minimum balance as the total refund we need to issue plus 5% to cover fees minBalance := types.BigAdd(refundSum, types.BigDiv(refundSum, types.NewInt(500))) if balance.LessThan(minBalance) { - log.Errorw("not sufficent funds to cover refunds", "balance", balance, "refund_sum", refundSum, "minimum_required", minBalance) + log.Errorw("not sufficient funds to cover refunds", "balance", balance, "refund_sum", refundSum, "minimum_required", minBalance) return xerrors.Errorf("wallet does not have enough balance to cover refund") } @@ -467,24 +467,24 @@ func (r *refunder) Refund(ctx context.Context, tipset *types.TipSet, refunds *Mi return nil } -type repo struct { +type Repo struct { last abi.ChainEpoch path string } -func NewRepo(path string) (*repo, error) { +func NewRepo(path string) (*Repo, error) { path, err := homedir.Expand(path) if err != nil { return nil, err } - return &repo{ + return &Repo{ last: 0, path: path, }, nil } -func (r *repo) exists() (bool, error) { +func (r *Repo) exists() (bool, error) { _, err := os.Stat(r.path) notexist := os.IsNotExist(err) if notexist { @@ -494,7 +494,7 @@ func (r *repo) exists() (bool, error) { } -func (r *repo) init() error { +func (r *Repo) init() error { exist, err := r.exists() if err != nil { return err @@ -511,7 +511,7 @@ func (r *repo) init() error { return nil } -func (r *repo) Open() (err error) { +func (r *Repo) Open() (err error) { if err = r.init(); err != nil { return } @@ -542,11 +542,11 @@ func (r *repo) Open() (err error) { return } -func (r *repo) Height() abi.ChainEpoch { +func (r *Repo) Height() abi.ChainEpoch { return r.last } -func (r *repo) SetHeight(last abi.ChainEpoch) (err error) { +func (r *Repo) SetHeight(last abi.ChainEpoch) (err error) { r.last = last var f *os.File f, err = os.OpenFile(filepath.Join(r.path, "height"), os.O_RDWR, 0644) diff --git a/cmd/lotus-seal-worker/main.go b/cmd/lotus-seal-worker/main.go index d190142e4..1b6ed2782 100644 --- a/cmd/lotus-seal-worker/main.go +++ b/cmd/lotus-seal-worker/main.go @@ -185,7 +185,7 @@ var runCmd = &cli.Command{ return err } if v.APIVersion != build.APIVersion { - return xerrors.Errorf("lotus-miner API version doesn't match: local: ", api.Version{APIVersion: build.APIVersion}) + return xerrors.Errorf("lotus-miner API version doesn't match: local: %s", api.Version{APIVersion: build.APIVersion}) } log.Infof("Remote version %s", v) @@ -420,10 +420,11 @@ func watchMinerConn(ctx context.Context, cctx *cli.Context, nodeApi api.StorageM log.Errorf("getting executable for auto-restart: %+v", err) } - log.Sync() + _ = log.Sync() // TODO: there are probably cleaner/more graceful ways to restart, // but this is good enough for now (FSM can recover from the mess this creates) + //nolint:gosec if err := syscall.Exec(exe, []string{exe, fmt.Sprintf("--worker-repo=%s", cctx.String("worker-repo")), fmt.Sprintf("--miner-repo=%s", cctx.String("miner-repo")), @@ -450,7 +451,7 @@ func extractRoutableIP(timeout time.Duration) (string, error) { env, ok := os.LookupEnv(minerMultiAddrKey) if !ok { // TODO remove after deprecation period - env, ok = os.LookupEnv(deprecatedMinerMultiAddrKey) + _, ok = os.LookupEnv(deprecatedMinerMultiAddrKey) if ok { log.Warnf("Using a deprecated env(%s) value, please use env(%s) instead.", deprecatedMinerMultiAddrKey, minerMultiAddrKey) } @@ -461,7 +462,7 @@ func extractRoutableIP(timeout time.Duration) (string, error) { if err != nil { return "", err } - defer conn.Close() + defer conn.Close() //nolint:errcheck localAddr := conn.LocalAddr().(*net.TCPAddr) diff --git a/cmd/lotus-seed/main.go b/cmd/lotus-seed/main.go index 508d1d222..48691d5ec 100644 --- a/cmd/lotus-seed/main.go +++ b/cmd/lotus-seed/main.go @@ -114,6 +114,9 @@ var preSealCmd = &cli.Command{ return err } kb, err := hex.DecodeString(string(kh)) + if err != nil { + return err + } if err := json.Unmarshal(kb, k); err != nil { return err } diff --git a/cmd/lotus-shed/keyinfo.go b/cmd/lotus-shed/keyinfo.go index b3a42e1c1..f397bd4c7 100644 --- a/cmd/lotus-shed/keyinfo.go +++ b/cmd/lotus-shed/keyinfo.go @@ -69,7 +69,7 @@ var keyinfoImportCmd = &cli.Command{ if err != nil { return err } - defer inputFile.Close() + defer inputFile.Close() //nolint:errcheck input = bufio.NewReader(inputFile) } @@ -98,7 +98,7 @@ var keyinfoImportCmd = &cli.Command{ return err } - defer lkrepo.Close() + defer lkrepo.Close() //nolint:errcheck keystore, err := lkrepo.KeyStore() if err != nil { @@ -150,7 +150,7 @@ var keyinfoInfoCmd = &cli.Command{ The 'format' flag takes a golang text/template template as its value. - The following fields can be retrived through this command + The following fields can be retrieved through this command Type Address PublicKey @@ -159,7 +159,7 @@ var keyinfoInfoCmd = &cli.Command{ Examples - Retreive the address of a lotus wallet + Retrieve the address of a lotus wallet lotus-shed keyinfo info --format '{{ .Address }}' wallet.keyinfo `, Flags: []cli.Flag{ @@ -181,7 +181,7 @@ var keyinfoInfoCmd = &cli.Command{ if err != nil { return err } - defer inputFile.Close() + defer inputFile.Close() //nolint:errcheck input = bufio.NewReader(inputFile) } diff --git a/cmd/lotus-storage-miner/info_all.go b/cmd/lotus-storage-miner/info_all.go index 78b7cb0d5..265ba78a4 100644 --- a/cmd/lotus-storage-miner/info_all.go +++ b/cmd/lotus-storage-miner/info_all.go @@ -126,7 +126,9 @@ var infoAllCmd = &cli.Command{ fs := &flag.FlagSet{} for _, f := range sectorsStatusCmd.Flags { - f.Apply(fs) + if err := f.Apply(fs); err != nil { + return err + } } if err := fs.Parse([]string{"--log", "--on-chain-info", fmt.Sprint(s)}); err != nil { return err diff --git a/cmd/lotus-storage-miner/run.go b/cmd/lotus-storage-miner/run.go index 8b10e7c1e..38fa8340e 100644 --- a/cmd/lotus-storage-miner/run.go +++ b/cmd/lotus-storage-miner/run.go @@ -53,7 +53,10 @@ var runCmd = &cli.Command{ }, Action: func(cctx *cli.Context) error { if !cctx.Bool("enable-gpu-proving") { - os.Setenv("BELLMAN_NO_GPU", "true") + err := os.Setenv("BELLMAN_NO_GPU", "true") + if err != nil { + return err + } } nodeApi, ncloser, err := lcli.GetFullNodeAPI(cctx) diff --git a/cmd/lotus-storage-miner/sealing.go b/cmd/lotus-storage-miner/sealing.go index c9ed224b3..2f966dcca 100644 --- a/cmd/lotus-storage-miner/sealing.go +++ b/cmd/lotus-storage-miner/sealing.go @@ -3,13 +3,14 @@ package main import ( "encoding/json" "fmt" - "golang.org/x/xerrors" "os" "sort" "strings" "text/tabwriter" "time" + "golang.org/x/xerrors" + "github.com/fatih/color" "github.com/urfave/cli/v2" diff --git a/cmd/lotus-storage-miner/sectors.go b/cmd/lotus-storage-miner/sectors.go index 59bb97c99..454162d87 100644 --- a/cmd/lotus-storage-miner/sectors.go +++ b/cmd/lotus-storage-miner/sectors.go @@ -2,13 +2,14 @@ package main import ( "fmt" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" "os" "sort" "strconv" "text/tabwriter" "time" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/urfave/cli/v2" "golang.org/x/xerrors" diff --git a/cmd/lotus-townhall/main.go b/cmd/lotus-townhall/main.go index 5f9603fba..7e8f6df7f 100644 --- a/cmd/lotus-townhall/main.go +++ b/cmd/lotus-townhall/main.go @@ -106,10 +106,11 @@ func handler(ps *pubsub.PubSub) func(w http.ResponseWriter, r *http.Request) { return } - sub, err := ps.Subscribe(topic) + sub, err := ps.Subscribe(topic) //nolint if err != nil { return } + defer sub.Cancel() //nolint:errcheck fmt.Println("new conn") diff --git a/extern/sector-storage/ffiwrapper/partialfile.go b/extern/sector-storage/ffiwrapper/partialfile.go index 74992f7ba..597e33105 100644 --- a/extern/sector-storage/ffiwrapper/partialfile.go +++ b/extern/sector-storage/ffiwrapper/partialfile.go @@ -118,7 +118,7 @@ func openPartialFile(maxPieceSize abi.PaddedPieceSize, path string) (*partialFil trailerLen := binary.LittleEndian.Uint32(tlen[:]) expectLen := int64(trailerLen) + int64(len(tlen)) + int64(maxPieceSize) if expectLen != st.Size() { - return xerrors.Errorf("file '%d' has inconsistent length; has %d bytes; expected %d (%d trailer, %d sector data)", path, st.Size(), expectLen, int64(trailerLen)+int64(len(tlen)), maxPieceSize) + return xerrors.Errorf("file '%s' has inconsistent length; has %d bytes; expected %d (%d trailer, %d sector data)", path, st.Size(), expectLen, int64(trailerLen)+int64(len(tlen)), maxPieceSize) } if trailerLen > veryLargeRle { log.Warnf("Partial file '%s' has a VERY large trailer with %d bytes", path, trailerLen) diff --git a/extern/sector-storage/fsutil/statfs_unix.go b/extern/sector-storage/fsutil/statfs_unix.go index 7fcb8af37..831fd8b4f 100644 --- a/extern/sector-storage/fsutil/statfs_unix.go +++ b/extern/sector-storage/fsutil/statfs_unix.go @@ -12,6 +12,8 @@ func Statfs(path string) (FsStat, error) { return FsStat{}, xerrors.Errorf("statfs: %w", err) } + // force int64 to handle platform specific differences + //nolint:unconvert return FsStat{ Capacity: int64(stat.Blocks) * int64(stat.Bsize), Available: int64(stat.Bavail) * int64(stat.Bsize), diff --git a/extern/sector-storage/mock/mock.go b/extern/sector-storage/mock/mock.go index 783d2e19c..e3fcc3f5b 100644 --- a/extern/sector-storage/mock/mock.go +++ b/extern/sector-storage/mock/mock.go @@ -438,7 +438,7 @@ func (m mockVerif) VerifyWindowPoSt(ctx context.Context, info abi.WindowPoStVeri } if !bytes.Equal(b1, b2) { - return false, xerrors.Errorf("proven and challenged sector sets didn't match: %s != !s", string(b1), string(b2)) + return false, xerrors.Errorf("proven and challenged sector sets didn't match: %s != %s", string(b1), string(b2)) } } diff --git a/extern/sector-storage/tarutil/systar.go b/extern/sector-storage/tarutil/systar.go index 6811cb46a..2329aafc7 100644 --- a/extern/sector-storage/tarutil/systar.go +++ b/extern/sector-storage/tarutil/systar.go @@ -36,6 +36,8 @@ func ExtractTar(body io.Reader, dir string) error { return xerrors.Errorf("creating file %s: %w", filepath.Join(dir, header.Name), err) } + // This data is coming from a trusted source, no need to check the size. + //nolint:gosec if _, err := io.Copy(f, tr); err != nil { return err } diff --git a/extern/storage-sealing/fsm.go b/extern/storage-sealing/fsm.go index d9648a99d..82db5c15a 100644 --- a/extern/storage-sealing/fsm.go +++ b/extern/storage-sealing/fsm.go @@ -348,7 +348,9 @@ func (m *Sealing) restartSectors(ctx context.Context) error { timer := time.NewTimer(cfg.WaitDealsDelay) go func() { <-timer.C - m.StartPacking(sector.SectorNumber) + if err := m.StartPacking(sector.SectorNumber); err != nil { + log.Errorf("starting sector %d: %+v", sector.SectorNumber, err) + } }() } } diff --git a/extern/storage-sealing/sealing.go b/extern/storage-sealing/sealing.go index 062ade2a3..a19ada176 100644 --- a/extern/storage-sealing/sealing.go +++ b/extern/storage-sealing/sealing.go @@ -355,7 +355,9 @@ func (m *Sealing) newDealSector() (abi.SectorNumber, error) { timer := time.NewTimer(cf.WaitDealsDelay) go func() { <-timer.C - m.StartPacking(sid) + if err := m.StartPacking(sid); err != nil { + log.Errorf("starting sector %d: %+v", sid, err) + } }() } @@ -396,7 +398,6 @@ func (m *Sealing) Address() address.Address { func getDealPerSectorLimit(size abi.SectorSize) uint64 { if size < 64<<30 { return 256 - } else { - return 512 } + return 512 } diff --git a/extern/storage-sealing/types.go b/extern/storage-sealing/types.go index a9c2a7203..9d82ea2c2 100644 --- a/extern/storage-sealing/types.go +++ b/extern/storage-sealing/types.go @@ -3,6 +3,7 @@ package sealing import ( "bytes" "context" + "github.com/ipfs/go-cid" "github.com/filecoin-project/specs-actors/actors/abi" diff --git a/go.mod b/go.mod index a8a2f2e0e..813636d93 100644 --- a/go.mod +++ b/go.mod @@ -92,7 +92,6 @@ require ( github.com/libp2p/go-libp2p-kad-dht v0.8.3 github.com/libp2p/go-libp2p-mplex v0.2.4 github.com/libp2p/go-libp2p-noise v0.1.1 - github.com/libp2p/go-libp2p-peer v0.2.0 github.com/libp2p/go-libp2p-peerstore v0.2.6 github.com/libp2p/go-libp2p-pubsub v0.3.5-0.20200820194335-bfc96c2cd081 github.com/libp2p/go-libp2p-quic-transport v0.7.1 diff --git a/journal/journal.go b/journal/journal.go index 74208c62e..f043d37d6 100644 --- a/journal/journal.go +++ b/journal/journal.go @@ -5,7 +5,6 @@ import ( "fmt" "os" "path/filepath" - "sync" "time" logging "github.com/ipfs/go-log" @@ -48,8 +47,6 @@ type fsJournal struct { fi *os.File fSize int64 - lk sync.Mutex - journalDir string incoming chan *JournalEntry @@ -58,7 +55,7 @@ type fsJournal struct { closing chan struct{} } -func OpenFSJournal(dir string) (*fsJournal, error) { +func OpenFSJournal(dir string) (Journal, error) { fsj := &fsJournal{ journalDir: dir, incoming: make(chan *JournalEntry, 32), @@ -94,7 +91,7 @@ func (fsj *fsJournal) putEntry(je *JournalEntry) error { fsj.fSize += int64(n) if fsj.fSize >= fsj.journalSizeLimit { - fsj.rollJournalFile() + return fsj.rollJournalFile() } return nil @@ -104,7 +101,10 @@ const RFC3339nocolon = "2006-01-02T150405Z0700" func (fsj *fsJournal) rollJournalFile() error { if fsj.fi != nil { - fsj.fi.Close() + err := fsj.fi.Close() + if err != nil { + return err + } } nfi, err := os.Create(filepath.Join(fsj.journalDir, fmt.Sprintf("lotus-journal-%s.ndjson", build.Clock.Now().Format(RFC3339nocolon)))) @@ -125,7 +125,9 @@ func (fsj *fsJournal) runLoop() { log.Errorw("failed to write out journal entry", "entry", je, "err", err) } case <-fsj.closing: - fsj.fi.Close() + if err := fsj.fi.Close(); err != nil { + log.Errorw("failed to close journal", "err", err) + } return } } diff --git a/lib/blockstore/blockstore.go b/lib/blockstore/blockstore.go index 079338041..9e74f4373 100644 --- a/lib/blockstore/blockstore.go +++ b/lib/blockstore/blockstore.go @@ -28,12 +28,12 @@ func NewTemporary() blockstore.Blockstore { return NewBlockstore(ds.NewMapDatastore()) } -// NewTemporary returns a thread-safe temporary blockstore. +// NewTemporarySync returns a thread-safe temporary blockstore. func NewTemporarySync() blockstore.Blockstore { return NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore())) } -// Wraps the underlying blockstore in an "identity" blockstore. +// WrapIDStore wraps the underlying blockstore in an "identity" blockstore. func WrapIDStore(bstore blockstore.Blockstore) blockstore.Blockstore { return blockstore.NewIdStore(bstore) } diff --git a/lib/cachebs/cachebs.go b/lib/cachebs/cachebs.go index 0880acc6e..046f100c0 100644 --- a/lib/cachebs/cachebs.go +++ b/lib/cachebs/cachebs.go @@ -11,6 +11,7 @@ import ( bstore "github.com/filecoin-project/lotus/lib/blockstore" ) +//nolint:deadcode,varcheck var log = logging.Logger("cachebs") type CacheBS struct { diff --git a/lib/rpcenc/reader.go b/lib/rpcenc/reader.go index ffb13577f..3f4d5c604 100644 --- a/lib/rpcenc/reader.go +++ b/lib/rpcenc/reader.go @@ -64,7 +64,7 @@ func ReaderParamEncoder(addr string) jsonrpc.Option { return } - defer resp.Body.Close() + defer resp.Body.Close() //nolint:errcheck if resp.StatusCode != 200 { b, _ := ioutil.ReadAll(resp.Body) diff --git a/lib/rpcenc/reader_test.go b/lib/rpcenc/reader_test.go index d33bbbd26..d6289c150 100644 --- a/lib/rpcenc/reader_test.go +++ b/lib/rpcenc/reader_test.go @@ -56,7 +56,7 @@ func TestReaderProxy(t *testing.T) { read, err := client.ReadAll(context.TODO(), strings.NewReader("pooooootato")) require.NoError(t, err) - require.Equal(t, "pooooootato", string(read), "potatos weren't equal") + require.Equal(t, "pooooootato", string(read), "potatoes weren't equal") } func TestNullReaderProxy(t *testing.T) { diff --git a/lib/sigs/bls/bls_bench_test.go b/lib/sigs/bls/bls_bench_test.go index a6c033912..118d25975 100644 --- a/lib/sigs/bls/bls_bench_test.go +++ b/lib/sigs/bls/bls_bench_test.go @@ -2,8 +2,9 @@ package bls import ( "crypto/rand" - "github.com/filecoin-project/go-address" "testing" + + "github.com/filecoin-project/go-address" ) func BenchmarkBLSSign(b *testing.B) { @@ -12,7 +13,7 @@ func BenchmarkBLSSign(b *testing.B) { b.StopTimer() pk, _ := signer.GenPrivate() randMsg := make([]byte, 32) - rand.Read(randMsg) + _, _ = rand.Read(randMsg) b.StartTimer() _, _ = signer.Sign(pk, randMsg) @@ -24,7 +25,7 @@ func BenchmarkBLSVerify(b *testing.B) { for i := 0; i < b.N; i++ { b.StopTimer() randMsg := make([]byte, 32) - rand.Read(randMsg) + _, _ = rand.Read(randMsg) priv, _ := signer.GenPrivate() pk, _ := signer.ToPublic(priv) diff --git a/lotuspond/api.go b/lotuspond/api.go index 169cec1de..e61372a87 100644 --- a/lotuspond/api.go +++ b/lotuspond/api.go @@ -17,7 +17,7 @@ import ( type NodeState int const ( - NodeUnknown = iota + NodeUnknown = iota //nolint:deadcode NodeRunning NodeStopped ) diff --git a/lotuspond/outmux.go b/lotuspond/outmux.go index 406001078..199c83ef1 100644 --- a/lotuspond/outmux.go +++ b/lotuspond/outmux.go @@ -73,7 +73,7 @@ func (m *outmux) run() { case msg := <-stdout: for k, out := range m.outs { if err := out.WriteMessage(websocket.BinaryMessage, msg); err != nil { - out.Close() + _ = out.Close() fmt.Printf("outmux write failed: %s\n", err) delete(m.outs, k) } diff --git a/markets/storageadapter/client.go b/markets/storageadapter/client.go index 576a0e98a..91fc6a054 100644 --- a/markets/storageadapter/client.go +++ b/markets/storageadapter/client.go @@ -266,7 +266,7 @@ func (c *ClientNodeAdapter) OnDealSectorCommitted(ctx context.Context, provider return false, nil } - sd, err := stmgr.GetStorageDeal(ctx, c.StateManager, abi.DealID(dealId), ts) + sd, err := stmgr.GetStorageDeal(ctx, c.StateManager, dealId, ts) if err != nil { return false, xerrors.Errorf("failed to look up deal on chain: %w", err) } @@ -303,7 +303,7 @@ func (c *ClientNodeAdapter) OnDealSectorCommitted(ctx context.Context, provider } for _, did := range params.DealIDs { - if did == abi.DealID(dealId) { + if did == dealId { sectorNumber = params.SectorNumber sectorFound = true return true, false, nil @@ -464,7 +464,7 @@ func (c *ClientNodeAdapter) ValidateAskSignature(ctx context.Context, ask *stora mi, err := c.StateMinerInfo(ctx, ask.Ask.Miner, tsk) if err != nil { - return false, xerrors.Errorf("failed to get worker for miner in ask", err) + return false, xerrors.Errorf("failed to get worker for miner in ask: %w", err) } sigb, err := cborutil.Dump(ask.Ask) diff --git a/markets/storageadapter/provider.go b/markets/storageadapter/provider.go index f796a2300..eaa2a3ae2 100644 --- a/markets/storageadapter/provider.go +++ b/markets/storageadapter/provider.go @@ -69,7 +69,7 @@ func (n *ProviderNodeAdapter) PublishDeals(ctx context.Context, deal storagemark }) if err != nil { - return cid.Undef, xerrors.Errorf("serializing PublishStorageDeals params failed: ", err) + return cid.Undef, xerrors.Errorf("serializing PublishStorageDeals params failed: %w", err) } // TODO: We may want this to happen after fetching data @@ -267,7 +267,7 @@ func (n *ProviderNodeAdapter) OnDealSectorCommitted(ctx context.Context, provide return false, nil } - sd, err := n.StateMarketStorageDeal(ctx, abi.DealID(dealID), ts.Key()) + sd, err := n.StateMarketStorageDeal(ctx, dealID, ts.Key()) if err != nil { return false, xerrors.Errorf("failed to look up deal on chain: %w", err) } @@ -305,7 +305,7 @@ func (n *ProviderNodeAdapter) OnDealSectorCommitted(ctx context.Context, provide } for _, did := range params.DealIDs { - if did == abi.DealID(dealID) { + if did == dealID { sectorNumber = params.SectorNumber sectorFound = true return true, false, nil diff --git a/miner/miner.go b/miner/miner.go index 27d3c040d..ed407a0c7 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -36,7 +36,7 @@ type waitFunc func(ctx context.Context, baseTime uint64) (func(bool, error), abi func randTimeOffset(width time.Duration) time.Duration { buf := make([]byte, 8) - rand.Reader.Read(buf) + rand.Reader.Read(buf) //nolint:errcheck val := time.Duration(binary.BigEndian.Uint64(buf) % uint64(width)) return val - (width / 2) @@ -508,12 +508,3 @@ func (c *cachedActorLookup) StateGetActor(ctx context.Context, a address.Address } type ActorLookup func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) - -func countFrom(msgs []*types.SignedMessage, from address.Address) (out int) { - for _, msg := range msgs { - if msg.Message.From == from { - out++ - } - } - return out -} diff --git a/node/builder.go b/node/builder.go index 2b132a7de..86d2aff7a 100644 --- a/node/builder.go +++ b/node/builder.go @@ -67,6 +67,7 @@ import ( "github.com/filecoin-project/lotus/storage/sectorblocks" ) +//nolint:deadcode,varcheck var log = logging.Logger("builder") // special is a type used to give keys to modules which diff --git a/node/impl/client/client.go b/node/impl/client/client.go index 3adc559a5..3cba94ddb 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -109,7 +109,7 @@ func (a *API) ClientStartDeal(ctx context.Context, params *api.StartDealParams) continue } if c.Equals(params.Data.Root) { - storeID = &importID + storeID = &importID //nolint break } } @@ -614,7 +614,7 @@ func (a *API) ClientCalcCommP(ctx context.Context, inpath string) (*api.CommPRet if err != nil { return nil, err } - defer rdr.Close() + defer rdr.Close() //nolint:errcheck stat, err := rdr.Stat() if err != nil { @@ -700,7 +700,7 @@ func (a *API) clientImport(ctx context.Context, ref api.FileRef, store *multisto if err != nil { return cid.Undef, err } - defer f.Close() + defer f.Close() //nolint:errcheck stat, err := f.Stat() if err != nil { diff --git a/node/impl/full/mpool.go b/node/impl/full/mpool.go index bde7d4f81..bd10b2ca8 100644 --- a/node/impl/full/mpool.go +++ b/node/impl/full/mpool.go @@ -2,14 +2,15 @@ package full import ( "context" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-address" "github.com/ipfs/go-cid" "go.uber.org/fx" "golang.org/x/xerrors" - "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/messagepool" "github.com/filecoin-project/lotus/chain/store" diff --git a/node/impl/full/multisig.go b/node/impl/full/multisig.go index 88ff4cdc9..f1e3c61fd 100644 --- a/node/impl/full/multisig.go +++ b/node/impl/full/multisig.go @@ -28,7 +28,7 @@ type MsigAPI struct { MpoolAPI MpoolAPI } -// TODO: remove gp (gasPrice) from arguemnts +// TODO: remove gp (gasPrice) from arguments func (a *MsigAPI) MsigCreate(ctx context.Context, req uint64, addrs []address.Address, duration abi.ChainEpoch, val types.BigInt, src address.Address, gp types.BigInt) (cid.Cid, error) { lenAddrs := uint64(len(addrs)) diff --git a/node/impl/full/state.go b/node/impl/full/state.go index f5421e2ba..36721a93d 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -443,9 +443,8 @@ func (a *StateAPI) StateSearchMsg(ctx context.Context, msg cid.Cid) (*api.MsgLoo TipSet: ts.Key(), Height: ts.Height(), }, nil - } else { - return nil, nil } + return nil, nil } func (a *StateAPI) StateGetReceipt(ctx context.Context, msg cid.Cid, tsk types.TipSetKey) (*types.MessageReceipt, error) { @@ -557,7 +556,7 @@ func (a *StateAPI) StateMarketDeals(ctx context.Context, tsk types.TipSetKey) (m } else if !found { s.SectorStartEpoch = -1 } - out[strconv.FormatInt(int64(i), 10)] = api.MarketDeal{ + out[strconv.FormatInt(i, 10)] = api.MarketDeal{ Proposal: d, State: s, } @@ -785,10 +784,6 @@ func (a *StateAPI) StateSectorPartition(ctx context.Context, maddr address.Addre return nil, err } - if found == nil { - - } - return found, nil } @@ -1147,12 +1142,12 @@ func (a *StateAPI) StateDealProviderCollateralBounds(ctx context.Context, size a }) if err != nil { - return api.DealCollateralBounds{}, xerrors.Errorf("getting power and reward actor states: %w") + return api.DealCollateralBounds{}, xerrors.Errorf("getting power and reward actor states: %w", err) } circ, err := a.StateCirculatingSupply(ctx, ts.Key()) if err != nil { - return api.DealCollateralBounds{}, xerrors.Errorf("getting total circulating supply: %w") + return api.DealCollateralBounds{}, xerrors.Errorf("getting total circulating supply: %w", err) } min, max := market.DealProviderCollateralBounds(size, verified, powerState.ThisEpochQualityAdjPower, rewardState.ThisEpochBaselinePower, circ.FilCirculating) @@ -1175,6 +1170,9 @@ func (a *StateAPI) StateCirculatingSupply(ctx context.Context, tsk types.TipSetK cst := cbor.NewCborStore(a.Chain.Blockstore()) sTree, err := state.LoadStateTree(cst, st) + if err != nil { + return api.CirculatingSupply{}, err + } return a.StateManager.GetCirculatingSupplyDetailed(ctx, ts.Height(), sTree) } diff --git a/node/impl/full/sync.go b/node/impl/full/sync.go index 758ecb34d..9066df56f 100644 --- a/node/impl/full/sync.go +++ b/node/impl/full/sync.go @@ -90,8 +90,7 @@ func (a *SyncAPI) SyncSubmitBlock(ctx context.Context, blk *types.BlockMsg) erro return xerrors.Errorf("serializing block for pubsub publishing failed: %w", err) } - // TODO: anything else to do here? - return a.PubSub.Publish(build.BlocksTopic(a.NetName), b) + return a.PubSub.Publish(build.BlocksTopic(a.NetName), b) //nolint:staticcheck } func (a *SyncAPI) SyncIncomingBlocks(ctx context.Context) (<-chan *types.BlockHeader, error) { diff --git a/node/impl/full/wallet.go b/node/impl/full/wallet.go index b1d963f1f..440f9642f 100644 --- a/node/impl/full/wallet.go +++ b/node/impl/full/wallet.go @@ -2,19 +2,18 @@ package full import ( "context" - "github.com/filecoin-project/specs-actors/actors/abi/big" - - "github.com/filecoin-project/lotus/lib/sigs" "github.com/filecoin-project/go-address" + "go.uber.org/fx" + "golang.org/x/xerrors" + + "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet" - - "go.uber.org/fx" - "golang.org/x/xerrors" + "github.com/filecoin-project/lotus/lib/sigs" ) type WalletAPI struct { @@ -45,9 +44,8 @@ func (a *WalletAPI) WalletBalance(ctx context.Context, addr address.Address) (ty if xerrors.Is(err, types.ErrActorNotFound) { return big.Zero(), nil - } else { - return bal, err } + return bal, err } func (a *WalletAPI) WalletSign(ctx context.Context, k address.Address, msg []byte) (*crypto.Signature, error) { diff --git a/node/modules/client.go b/node/modules/client.go index 80675a3d2..284e254d6 100644 --- a/node/modules/client.go +++ b/node/modules/client.go @@ -123,8 +123,7 @@ func StorageClient(lc fx.Lifecycle, h host.Host, ibs dtypes.ClientBlockstore, md return c.Start(ctx) }, OnStop: func(context.Context) error { - c.Stop() - return nil + return c.Stop() }, }) return c, nil diff --git a/node/modules/core.go b/node/modules/core.go index 6d2ca64d0..0305c737e 100644 --- a/node/modules/core.go +++ b/node/modules/core.go @@ -36,8 +36,8 @@ func RecordValidator(ps peerstore.Peerstore) record.Validator { } } -const JWTSecretName = "auth-jwt-private" //nolint:gosec -const KTJwtHmacSecret = "jwt-hmac-secret" +const JWTSecretName = "auth-jwt-private" //nolint:gosec +const KTJwtHmacSecret = "jwt-hmac-secret" //nolint:gosec type JwtPayload struct { Allow []auth.Permission diff --git a/node/modules/graphsync.go b/node/modules/graphsync.go index 601ad8840..9bdc9bcca 100644 --- a/node/modules/graphsync.go +++ b/node/modules/graphsync.go @@ -8,7 +8,7 @@ import ( gsnet "github.com/ipfs/go-graphsync/network" "github.com/ipfs/go-graphsync/storeutil" "github.com/libp2p/go-libp2p-core/host" - peer "github.com/libp2p/go-libp2p-peer" + "github.com/libp2p/go-libp2p-core/peer" "go.uber.org/fx" ) diff --git a/node/modules/services.go b/node/modules/services.go index 013a6c0af..fc7486abe 100644 --- a/node/modules/services.go +++ b/node/modules/services.go @@ -76,7 +76,7 @@ func RunBlockSync(h host.Host, svc *blocksync.BlockSyncService) { func HandleIncomingBlocks(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, s *chain.Syncer, bserv dtypes.ChainBlockService, chain *store.ChainStore, stmgr *stmgr.StateManager, h host.Host, nn dtypes.NetworkName) { ctx := helpers.LifecycleCtx(mctx, lc) - blocksub, err := ps.Subscribe(build.BlocksTopic(nn)) + blocksub, err := ps.Subscribe(build.BlocksTopic(nn)) //nolint if err != nil { panic(err) } @@ -98,7 +98,7 @@ func HandleIncomingBlocks(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.P func HandleIncomingMessages(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, mpool *messagepool.MessagePool, h host.Host, nn dtypes.NetworkName) { ctx := helpers.LifecycleCtx(mctx, lc) - msgsub, err := ps.Subscribe(build.MessagesTopic(nn)) + msgsub, err := ps.Subscribe(build.MessagesTopic(nn)) //nolint:staticcheck if err != nil { panic(err) } diff --git a/storage/adapter_storage_miner.go b/storage/adapter_storage_miner.go index 1890a369f..0963b07e6 100644 --- a/storage/adapter_storage_miner.go +++ b/storage/adapter_storage_miner.go @@ -3,7 +3,6 @@ package storage import ( "bytes" "context" - "github.com/filecoin-project/lotus/api" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -18,6 +17,7 @@ import ( "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/apibstore" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors" diff --git a/storage/addresses.go b/storage/addresses.go index e041024c6..a1c05660f 100644 --- a/storage/addresses.go +++ b/storage/addresses.go @@ -2,6 +2,7 @@ package storage import ( "context" + "golang.org/x/xerrors" "github.com/filecoin-project/go-address" diff --git a/storage/wdpost_run.go b/storage/wdpost_run.go index 7367ceafa..821c23cd7 100644 --- a/storage/wdpost_run.go +++ b/storage/wdpost_run.go @@ -4,13 +4,13 @@ import ( "bytes" "context" "errors" - "github.com/filecoin-project/specs-actors/actors/abi/big" "time" "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-address" "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/crypto" diff --git a/tools/stats/head_buffer.go b/tools/stats/head_buffer.go index 1c3bf9777..0a7c63e6e 100644 --- a/tools/stats/head_buffer.go +++ b/tools/stats/head_buffer.go @@ -11,7 +11,7 @@ type headBuffer struct { size int } -func NewHeadBuffer(size int) *headBuffer { +func newHeadBuffer(size int) *headBuffer { buffer := list.New() buffer.Init() @@ -21,7 +21,7 @@ func NewHeadBuffer(size int) *headBuffer { } } -func (h *headBuffer) Push(hc *api.HeadChange) (rethc *api.HeadChange) { +func (h *headBuffer) push(hc *api.HeadChange) (rethc *api.HeadChange) { if h.buffer.Len() == h.size { var ok bool @@ -39,7 +39,7 @@ func (h *headBuffer) Push(hc *api.HeadChange) (rethc *api.HeadChange) { return } -func (h *headBuffer) Pop() { +func (h *headBuffer) pop() { el := h.buffer.Back() if el != nil { h.buffer.Remove(el) diff --git a/tools/stats/head_buffer_test.go b/tools/stats/head_buffer_test.go index 098c90a96..4059f730e 100644 --- a/tools/stats/head_buffer_test.go +++ b/tools/stats/head_buffer_test.go @@ -10,34 +10,34 @@ import ( func TestHeadBuffer(t *testing.T) { t.Run("Straight push through", func(t *testing.T) { - hb := NewHeadBuffer(5) - require.Nil(t, hb.Push(&api.HeadChange{Type: "1"})) - require.Nil(t, hb.Push(&api.HeadChange{Type: "2"})) - require.Nil(t, hb.Push(&api.HeadChange{Type: "3"})) - require.Nil(t, hb.Push(&api.HeadChange{Type: "4"})) - require.Nil(t, hb.Push(&api.HeadChange{Type: "5"})) + hb := newHeadBuffer(5) + require.Nil(t, hb.push(&api.HeadChange{Type: "1"})) + require.Nil(t, hb.push(&api.HeadChange{Type: "2"})) + require.Nil(t, hb.push(&api.HeadChange{Type: "3"})) + require.Nil(t, hb.push(&api.HeadChange{Type: "4"})) + require.Nil(t, hb.push(&api.HeadChange{Type: "5"})) - hc := hb.Push(&api.HeadChange{Type: "6"}) + hc := hb.push(&api.HeadChange{Type: "6"}) require.Equal(t, hc.Type, "1") }) t.Run("Reverts", func(t *testing.T) { - hb := NewHeadBuffer(5) - require.Nil(t, hb.Push(&api.HeadChange{Type: "1"})) - require.Nil(t, hb.Push(&api.HeadChange{Type: "2"})) - require.Nil(t, hb.Push(&api.HeadChange{Type: "3"})) - hb.Pop() - require.Nil(t, hb.Push(&api.HeadChange{Type: "3a"})) - hb.Pop() - require.Nil(t, hb.Push(&api.HeadChange{Type: "3b"})) - require.Nil(t, hb.Push(&api.HeadChange{Type: "4"})) - require.Nil(t, hb.Push(&api.HeadChange{Type: "5"})) + hb := newHeadBuffer(5) + require.Nil(t, hb.push(&api.HeadChange{Type: "1"})) + require.Nil(t, hb.push(&api.HeadChange{Type: "2"})) + require.Nil(t, hb.push(&api.HeadChange{Type: "3"})) + hb.pop() + require.Nil(t, hb.push(&api.HeadChange{Type: "3a"})) + hb.pop() + require.Nil(t, hb.push(&api.HeadChange{Type: "3b"})) + require.Nil(t, hb.push(&api.HeadChange{Type: "4"})) + require.Nil(t, hb.push(&api.HeadChange{Type: "5"})) - hc := hb.Push(&api.HeadChange{Type: "6"}) + hc := hb.push(&api.HeadChange{Type: "6"}) require.Equal(t, hc.Type, "1") - hc = hb.Push(&api.HeadChange{Type: "7"}) + hc = hb.push(&api.HeadChange{Type: "7"}) require.Equal(t, hc.Type, "2") - hc = hb.Push(&api.HeadChange{Type: "8"}) + hc = hb.push(&api.HeadChange{Type: "8"}) require.Equal(t, hc.Type, "3b") }) } diff --git a/tools/stats/metrics.go b/tools/stats/metrics.go index ab7b876bc..138e2831f 100644 --- a/tools/stats/metrics.go +++ b/tools/stats/metrics.go @@ -251,16 +251,13 @@ func RecordTipsetStatePoints(ctx context.Context, api api.FullNode, pl *PointLis return err } - err = mp.ForEach(nil, func(key string) error { + var claim power.Claim + err = mp.ForEach(&claim, func(key string) error { addr, err := address.NewFromBytes([]byte(key)) if err != nil { return err } - var claim power.Claim - keyerAddr := adt.AddrKey(addr) - mp.Get(keyerAddr, &claim) - if claim.QualityAdjPower.Int64() == 0 { return nil } @@ -311,7 +308,7 @@ func RecordTipsetMessagesPoints(ctx context.Context, api api.FullNode, pl *Point for i, msg := range msgs { // FIXME: use float so this doesn't overflow - // FIXME: this doesn't work as time points get overriden + // FIXME: this doesn't work as time points get overridden p := NewPoint("chain.message_gaspremium", msg.Message.GasPremium.Int64()) pl.AddPoint(p) p = NewPoint("chain.message_gasfeecap", msg.Message.GasFeeCap.Int64()) diff --git a/tools/stats/rpc.go b/tools/stats/rpc.go index 6b6cef283..965005f0d 100644 --- a/tools/stats/rpc.go +++ b/tools/stats/rpc.go @@ -124,7 +124,7 @@ sync_complete: func GetTips(ctx context.Context, api api.FullNode, lastHeight abi.ChainEpoch, headlag int) (<-chan *types.TipSet, error) { chmain := make(chan *types.TipSet) - hb := NewHeadBuffer(headlag) + hb := newHeadBuffer(headlag) notif, err := api.ChainNotify(ctx) if err != nil { @@ -134,7 +134,8 @@ func GetTips(ctx context.Context, api api.FullNode, lastHeight abi.ChainEpoch, h go func() { defer close(chmain) - ping := time.Tick(30 * time.Second) + ticker := time.NewTicker(30 * time.Second) + defer ticker.Stop() for { select { @@ -154,14 +155,14 @@ func GetTips(ctx context.Context, api api.FullNode, lastHeight abi.ChainEpoch, h chmain <- tipset } case store.HCApply: - if out := hb.Push(change); out != nil { + if out := hb.push(change); out != nil { chmain <- out.Val } case store.HCRevert: - hb.Pop() + hb.pop() } } - case <-ping: + case <-ticker.C: log.Info("Running health check") cctx, cancel := context.WithTimeout(ctx, 5*time.Second) From 7c1e0d21320c9e481a031f36ffa3f421a7a1c560 Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 21 Aug 2020 10:53:30 +0300 Subject: [PATCH 028/247] update go-libp2p-pubsub@master --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a8a2f2e0e..3e0aafa28 100644 --- a/go.mod +++ b/go.mod @@ -94,7 +94,7 @@ require ( github.com/libp2p/go-libp2p-noise v0.1.1 github.com/libp2p/go-libp2p-peer v0.2.0 github.com/libp2p/go-libp2p-peerstore v0.2.6 - github.com/libp2p/go-libp2p-pubsub v0.3.5-0.20200820194335-bfc96c2cd081 + github.com/libp2p/go-libp2p-pubsub v0.3.5-0.20200821075113-efd56962bced github.com/libp2p/go-libp2p-quic-transport v0.7.1 github.com/libp2p/go-libp2p-record v0.1.3 github.com/libp2p/go-libp2p-routing-helpers v0.2.3 diff --git a/go.sum b/go.sum index 1fc5c854a..aa1fa9863 100644 --- a/go.sum +++ b/go.sum @@ -885,8 +885,8 @@ github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1 github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk= github.com/libp2p/go-libp2p-pubsub v0.1.1/go.mod h1:ZwlKzRSe1eGvSIdU5bD7+8RZN/Uzw0t1Bp9R1znpR/Q= github.com/libp2p/go-libp2p-pubsub v0.3.2-0.20200527132641-c0712c6e92cf/go.mod h1:TxPOBuo1FPdsTjFnv+FGZbNbWYsp74Culx+4ViQpato= -github.com/libp2p/go-libp2p-pubsub v0.3.5-0.20200820194335-bfc96c2cd081 h1:OYGkXBqwyy8YExNj1ZNKm8ICeBJu1E40k/qr8rHqmH8= -github.com/libp2p/go-libp2p-pubsub v0.3.5-0.20200820194335-bfc96c2cd081/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= +github.com/libp2p/go-libp2p-pubsub v0.3.5-0.20200821075113-efd56962bced h1:mgcPX7FRZNpIhg2i8B91T4fO0UEpeuhRS0YX5uMAic4= +github.com/libp2p/go-libp2p-pubsub v0.3.5-0.20200821075113-efd56962bced/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= github.com/libp2p/go-libp2p-quic-transport v0.1.1/go.mod h1:wqG/jzhF3Pu2NrhJEvE+IE0NTHNXslOPn9JQzyCAxzU= github.com/libp2p/go-libp2p-quic-transport v0.5.0/go.mod h1:IEcuC5MLxvZ5KuHKjRu+dr3LjCT1Be3rcD/4d8JrX8M= github.com/libp2p/go-libp2p-quic-transport v0.7.1 h1:X6Ond9GANspXpgwJlSR9yxcMMD6SLBnGKRtwjBG5awc= From f21ce3e8ee013d8d08d9356874c4f38b718e0d8e Mon Sep 17 00:00:00 2001 From: Dan Shao Date: Fri, 21 Aug 2020 16:52:33 +0800 Subject: [PATCH 029/247] Fix import storage-fsm -> extern/storage-sealing --- extern/storage-sealing/nullreader.go | 2 +- go.mod | 1 - go.sum | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/extern/storage-sealing/nullreader.go b/extern/storage-sealing/nullreader.go index a8e6a5c31..ea6dfddb0 100644 --- a/extern/storage-sealing/nullreader.go +++ b/extern/storage-sealing/nullreader.go @@ -3,8 +3,8 @@ package sealing import ( "io" + nr "github.com/filecoin-project/lotus/extern/storage-sealing/lib/nullreader" "github.com/filecoin-project/specs-actors/actors/abi" - nr "github.com/filecoin-project/storage-fsm/lib/nullreader" ) type NullReader struct { diff --git a/go.mod b/go.mod index a8a2f2e0e..a83e6623b 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,6 @@ require ( github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0 // indirect github.com/filecoin-project/specs-actors v0.9.3 github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401 - github.com/filecoin-project/storage-fsm v0.0.0-20200805013058-9d9ea4e6331f github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 github.com/go-kit/kit v0.10.0 github.com/go-ole/go-ole v1.2.4 // indirect diff --git a/go.sum b/go.sum index 1fc5c854a..62ea2d6f3 100644 --- a/go.sum +++ b/go.sum @@ -284,8 +284,6 @@ github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea h github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k= github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401 h1:jLzN1hwO5WpKPu8ASbW8fs1FUCsOWNvoBXzQhv+8/E8= github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k= -github.com/filecoin-project/storage-fsm v0.0.0-20200805013058-9d9ea4e6331f h1:WeMFRLMtAFqUwobouSeYj3pfgYtsSUwi3ztqDzFJMZY= -github.com/filecoin-project/storage-fsm v0.0.0-20200805013058-9d9ea4e6331f/go.mod h1:1CGbd11KkHuyWPT+xwwCol1zl/jnlpiKD2L4fzKxaiI= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as= github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ= From 6ed1c9e9051c8c59ed64319f57e782b84b71127e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Fri, 21 Aug 2020 11:51:50 +0100 Subject: [PATCH 030/247] register the puppet actor conditionally. --- conformance/driver.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/conformance/driver.go b/conformance/driver.go index 5a8813801..8b1393ca9 100644 --- a/conformance/driver.go +++ b/conformance/driver.go @@ -11,10 +11,11 @@ import ( "github.com/filecoin-project/sector-storage/ffiwrapper" + "github.com/filecoin-project/test-vectors/chaos" + "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/lib/blockstore" - "github.com/filecoin-project/test-vectors/chaos" ) var ( @@ -49,10 +50,14 @@ func (d *Driver) ExecuteMessage(msg *types.Message, preroot cid.Cid, bs blocksto return nil, cid.Undef, err } - // add support for the puppet and chaos actors. invoker := vm.NewInvoker() - invoker.Register(puppet.PuppetActorCodeID, puppet.Actor{}, puppet.State{}) - if chaosOn, ok := d.vector.Selector.Unpack()["chaos_actor"]; ok && chaosOn == "true" { + + // add support for the puppet and chaos actors. + selector := d.vector.Selector.Unpack() + if puppetOn, ok := selector["puppet_actor"]; ok && puppetOn == "true" { + invoker.Register(puppet.PuppetActorCodeID, puppet.Actor{}, puppet.State{}) + } + if chaosOn, ok := selector["chaos_actor"]; ok && chaosOn == "true" { invoker.Register(chaos.ChaosActorCodeCID, chaos.Actor{}, chaos.State{}) } From a03931daabb72242ef92977f856524f9f53dd878 Mon Sep 17 00:00:00 2001 From: Will Date: Fri, 21 Aug 2020 08:41:35 -0700 Subject: [PATCH 031/247] archive more relevant coverage for conformance tests (#3176) --- .circleci/config.yml | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c7ecb135a..b5a444965 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -146,10 +146,6 @@ jobs: description: | Upload coverage report to https://codecov.io/. Requires the codecov API token to be set as an environment variable for private projects. - skip-conformance: - type: string - default: "0" - description: "Skip conformance tests (default: no)." executor: << parameters.executor >> steps: - install-deps @@ -165,7 +161,7 @@ jobs: name: go test environment: LOTUS_TEST_WINDOW_POST: << parameters.winpost-test >> - SKIP_CONFORMANCE: << parameters.skip-conformance >> + SKIP_CONFORMANCE: "1" command: | mkdir -p /tmp/test-reports/<< parameters.test-suite-name >> mkdir -p /tmp/test-artifacts @@ -198,6 +194,24 @@ jobs: <<: *test test-conformance: <<: *test + steps: + - install-deps + - prepare + - run: + command: make deps lotus + no_output_timeout: 30m + - download-params + - run: + name: go test + environment: + SKIP_CONFORMANCE: "0" + command: | + mkdir -p /tmp/test-artifacts + go test -v -coverpkg ./chain/vm/,github.com/filecoin-project/specs-actors/... -coverprofile=/tmp/conformance.out ./conformance/ + go tool cover -html=/tmp/conformance.out -o /tmp/test-artifacts/conformance-coverage.html + no_output_timeout: 30m + - store_artifacts: + path: /tmp/test-artifacts/conformance-coverage.html build-macos: description: build darwin lotus binary @@ -333,16 +347,13 @@ workflows: - test: codecov-upload: true test-suite-name: full - skip-conformance: "1" - test-window-post: go-test-flags: "-run=TestWindowedPost" - skip-conformance: "1" winpost-test: "1" test-suite-name: window-post - test-short: go-test-flags: "--timeout 10m --short" test-suite-name: short - skip-conformance: "1" filters: tags: only: @@ -350,7 +361,6 @@ workflows: - test-conformance: test-suite-name: conformance packages: "./conformance" - skip-conformance: "0" - build-debug - build-all: requires: From 2e78f2c2674688a2bdc27413dc1adbf7c02438db Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Fri, 21 Aug 2020 09:31:28 -0700 Subject: [PATCH 032/247] If sectorInfo doesnt have CommD or CommR set during commit, don't crash --- extern/storage-sealing/checks.go | 2 +- extern/storage-sealing/states_sealing.go | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/extern/storage-sealing/checks.go b/extern/storage-sealing/checks.go index af62b9548..b415c6f8e 100644 --- a/extern/storage-sealing/checks.go +++ b/extern/storage-sealing/checks.go @@ -79,7 +79,7 @@ func checkPrecommit(ctx context.Context, maddr address.Address, si SectorInfo, t return &ErrApi{xerrors.Errorf("calling StateComputeDataCommitment: %w", err)} } - if !commD.Equals(*si.CommD) { + if si.CommD == nil || !commD.Equals(*si.CommD) { return &ErrBadCommD{xerrors.Errorf("on chain CommD differs from sector: %s != %s", commD, si.CommD)} } diff --git a/extern/storage-sealing/states_sealing.go b/extern/storage-sealing/states_sealing.go index 1ac22e20f..a434d1fcb 100644 --- a/extern/storage-sealing/states_sealing.go +++ b/extern/storage-sealing/states_sealing.go @@ -308,6 +308,10 @@ func (m *Sealing) handleCommitting(ctx statemachine.Context, sector SectorInfo) log.Infof("KOMIT %d %x(%d); %x(%d); %v; r:%x; d:%x", sector.SectorNumber, sector.TicketValue, sector.TicketEpoch, sector.SeedValue, sector.SeedEpoch, sector.pieceInfos(), sector.CommR, sector.CommD) + if sector.CommD == nil || sector.CommR == nil { + return ctx.Send(SectorCommitFailed{xerrors.Errorf("sector had nil commR or commD")}) + } + cids := storage.SectorCids{ Unsealed: *sector.CommD, Sealed: *sector.CommR, From 54862be3ff76f45925dd5b504cd1288e0a3fe709 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Fri, 21 Aug 2020 10:33:36 -0700 Subject: [PATCH 033/247] check that worker referenced by task is actually still there. --- extern/sector-storage/sched.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/extern/sector-storage/sched.go b/extern/sector-storage/sched.go index 328110c64..7842003a5 100644 --- a/extern/sector-storage/sched.go +++ b/extern/sector-storage/sched.go @@ -295,7 +295,12 @@ func (sh *scheduler) trySched() { task.indexHeap = sqi for wnd, windowRequest := range sh.openWindows { - worker := sh.workers[windowRequest.worker] + worker, ok := sh.workers[windowRequest.worker] + if !ok { + log.Errorf("worker referenced by windowRequest not found (worker: %d)", windowRequest.worker) + // TODO: How to move forward here? + continue + } // TODO: allow bigger windows if !windows[wnd].allocated.canHandleRequest(needRes, windowRequest.worker, worker.info.Resources) { From 4b80bc93b09b43571558daaa8ae4cf59c7aef79f Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Wed, 29 Jul 2020 09:54:12 +0200 Subject: [PATCH 034/247] build/drand.go: add settings for incentinet. --- build/drand.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/build/drand.go b/build/drand.go index e24b802d6..4bad0e673 100644 --- a/build/drand.go +++ b/build/drand.go @@ -15,6 +15,7 @@ const ( DrandTestnet DrandDevnet DrandLocalnet + DrandIncentinet ) var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{ @@ -55,4 +56,17 @@ var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{ }, ChainInfoJSON: `{"public_key":"8cda589f88914aa728fd183f383980b35789ce81b274e5daee1f338b77d02566ef4d3fb0098af1f844f10f9c803c1827","period":25,"genesis_time":1595348225,"hash":"e73b7dc3c4f6a236378220c0dd6aa110eb16eed26c11259606e07ee122838d4f","groupHash":"567d4785122a5a3e75a9bc9911d7ea807dd85ff76b78dc4ff06b075712898607"}`, }, + DrandIncentinet: { + Servers: []string{ + "https://pl-eu.incentinet.drand.sh", + "https://pl-us.incentinet.drand.sh", + "https://pl-sin.incentinet.drand.sh", + }, + Relays: []string{ + "/dnsaddr/pl-eu.incentinet.drand.sh/", + "/dnsaddr/pl-us.incentinet.drand.sh/", + "/dnsaddr/pl-sin.incentinet.drand.sh/", + }, + ChainInfoJSON: `{"public_key":"8cad0c72c606ab27d36ee06de1d5b2db1faf92e447025ca37575ab3a8aac2eaae83192f846fc9e158bc738423753d000","period":30,"genesis_time":1595873820,"hash":"80c8b872c714f4c00fdd3daa465d5514049f457f01f85a4caf68cdcd394ba039","groupHash":"d9406aaed487f7af71851b4399448e311f2328923d454e971536c05398ce2d9b"}`, + }, } From 30b28b7f7b88f173f47ac92e11eab223854b791a Mon Sep 17 00:00:00 2001 From: Travis Person Date: Fri, 21 Aug 2020 17:44:10 +0000 Subject: [PATCH 035/247] Update drand to incentinet --- build/drand.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/drand.go b/build/drand.go index 4bad0e673..ef3f2c498 100644 --- a/build/drand.go +++ b/build/drand.go @@ -2,7 +2,7 @@ package build import "github.com/filecoin-project/lotus/node/modules/dtypes" -var DrandNetwork = DrandTestnet +var DrandNetwork = DrandIncentinet func DrandConfig() dtypes.DrandConfig { return DrandConfigs[DrandNetwork] From 438fa637dfb583699b982d95c76197af23ae02c6 Mon Sep 17 00:00:00 2001 From: hannahhoward Date: Fri, 21 Aug 2020 11:49:16 -0700 Subject: [PATCH 036/247] feat(markets): update to markets v0.5.7 --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 3e0aafa28..647d121f5 100644 --- a/go.mod +++ b/go.mod @@ -28,9 +28,9 @@ require ( github.com/filecoin-project/go-bitfield v0.2.0 github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 - github.com/filecoin-project/go-data-transfer v0.6.1 + github.com/filecoin-project/go-data-transfer v0.6.2 github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f - github.com/filecoin-project/go-fil-markets v0.5.6-0.20200814234959-80b1788108ac + github.com/filecoin-project/go-fil-markets v0.5.7 github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200817153016-2ea5cbaf5ec0 github.com/filecoin-project/go-multistore v0.0.3 github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6 diff --git a/go.sum b/go.sum index aa1fa9863..cd87fd996 100644 --- a/go.sum +++ b/go.sum @@ -240,13 +240,13 @@ github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 h1:a github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2/go.mod h1:pqTiPHobNkOVM5thSRsHYjyQfq7O5QSCMhvuu9JoDlg= github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 h1:2pMXdBnCiXjfCYx/hLqFxccPoqsSveQFxVLvNxy9bus= github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= -github.com/filecoin-project/go-data-transfer v0.6.1 h1:EA6X8fSiBRNVVwKm5pA7+njZnBbdqpRtedZagrrwHHI= -github.com/filecoin-project/go-data-transfer v0.6.1/go.mod h1:uRYBRKVBVM12CSusBtVrzDHkVw/3DKZpkxKJVP1Ydas= +github.com/filecoin-project/go-data-transfer v0.6.2 h1:IgbkwcHoyWGglzfsY7P9L1GapzoiLNKuzfZY2bxER8E= +github.com/filecoin-project/go-data-transfer v0.6.2/go.mod h1:uRYBRKVBVM12CSusBtVrzDHkVw/3DKZpkxKJVP1Ydas= github.com/filecoin-project/go-fil-commcid v0.0.0-20200208005934-2b8bd03caca5/go.mod h1:JbkIgFF/Z9BDlvrJO1FuKkaWsH673/UdFaiVS6uIHlA= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1:GxJzR3oRIMTPtpZ0b7QF8FKPK6/iPAc7trhlL5k/g+s= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= -github.com/filecoin-project/go-fil-markets v0.5.6-0.20200814234959-80b1788108ac h1:gvAyMZkAGPx6e3Si6qIhd90SQYrGHJ1vwKt42GYdN7A= -github.com/filecoin-project/go-fil-markets v0.5.6-0.20200814234959-80b1788108ac/go.mod h1:umicPCaN99ysHTiYOmwhuLxTFbOwcsI+mdw/t96vvM4= +github.com/filecoin-project/go-fil-markets v0.5.7 h1:kzyMHqez8ssxchj5s9M1hkC3CTwRGh2MeglJGfUksQU= +github.com/filecoin-project/go-fil-markets v0.5.7/go.mod h1:KnvFG3kSQ77vKYSY/QdrXET81wVCBByHXjG7AyxnbUw= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200817153016-2ea5cbaf5ec0 h1:/GT3V+3f+H5w5odb7LcCWJ1zPw8H8m9TsGQcU0cGSHo= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200817153016-2ea5cbaf5ec0/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= github.com/filecoin-project/go-multistore v0.0.3 h1:vaRBY4YiA2UZFPK57RNuewypB8u0DzzQwqsL0XarpnI= From 984e52acbc4f80a63fbea3da0b71f58bd8e4eb0c Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Fri, 21 Aug 2020 15:43:30 -0400 Subject: [PATCH 037/247] Indicate whether a sector has been marked for upgrade --- api/api_storage.go | 19 ++++++++++--------- cmd/lotus-storage-miner/sectors.go | 3 ++- extern/storage-sealing/upgrade_queue.go | 7 +++++++ node/impl/storminer.go | 3 ++- storage/sealing.go | 4 ++++ 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/api/api_storage.go b/api/api_storage.go index 64d79a1e9..65ecf12ea 100644 --- a/api/api_storage.go +++ b/api/api_storage.go @@ -120,15 +120,16 @@ type SectorLog struct { } type SectorInfo struct { - SectorID abi.SectorNumber - State SectorState - CommD *cid.Cid - CommR *cid.Cid - Proof []byte - Deals []abi.DealID - Ticket SealTicket - Seed SealSeed - Retries uint64 + SectorID abi.SectorNumber + State SectorState + CommD *cid.Cid + CommR *cid.Cid + Proof []byte + Deals []abi.DealID + Ticket SealTicket + Seed SealSeed + Retries uint64 + ToUpgrade bool LastErr string diff --git a/cmd/lotus-storage-miner/sectors.go b/cmd/lotus-storage-miner/sectors.go index 59bb97c99..08d32d408 100644 --- a/cmd/lotus-storage-miner/sectors.go +++ b/cmd/lotus-storage-miner/sectors.go @@ -192,7 +192,7 @@ var sectorsListCmd = &cli.Command{ _, inSSet := commitedIDs[s] _, inASet := activeIDs[s] - fmt.Fprintf(w, "%d: %s\tsSet: %s\tactive: %s\ttktH: %d\tseedH: %d\tdeals: %v\n", + fmt.Fprintf(w, "%d: %s\tsSet: %s\tactive: %s\ttktH: %d\tseedH: %d\tdeals: %v\t toUpgrade:%t\n", s, st.State, yesno(inSSet), @@ -200,6 +200,7 @@ var sectorsListCmd = &cli.Command{ st.Ticket.Epoch, st.Seed.Epoch, st.Deals, + st.ToUpgrade, ) } diff --git a/extern/storage-sealing/upgrade_queue.go b/extern/storage-sealing/upgrade_queue.go index e508facd0..12a94f042 100644 --- a/extern/storage-sealing/upgrade_queue.go +++ b/extern/storage-sealing/upgrade_queue.go @@ -10,6 +10,13 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin/miner" ) +func (m *Sealing) IsMarkedForUpgrade(id abi.SectorNumber) bool { + m.upgradeLk.Lock() + _, found := m.toUpgrade[id] + m.upgradeLk.Unlock() + return found +} + func (m *Sealing) MarkForUpgrade(id abi.SectorNumber) error { m.upgradeLk.Lock() defer m.upgradeLk.Unlock() diff --git a/node/impl/storminer.go b/node/impl/storminer.go index daf011203..6c1b98db1 100644 --- a/node/impl/storminer.go +++ b/node/impl/storminer.go @@ -153,7 +153,8 @@ func (sm *StorageMinerAPI) SectorsStatus(ctx context.Context, sid abi.SectorNumb Value: info.SeedValue, Epoch: info.SeedEpoch, }, - Retries: info.InvalidProofs, + Retries: info.InvalidProofs, + ToUpgrade: sm.Miner.IsMarkedForUpgrade(sid), LastErr: info.LastErr, Log: log, diff --git a/storage/sealing.go b/storage/sealing.go index 5360a1186..7d7140b98 100644 --- a/storage/sealing.go +++ b/storage/sealing.go @@ -47,3 +47,7 @@ func (m *Miner) RemoveSector(ctx context.Context, id abi.SectorNumber) error { func (m *Miner) MarkForUpgrade(id abi.SectorNumber) error { return m.sealing.MarkForUpgrade(id) } + +func (m *Miner) IsMarkedForUpgrade(id abi.SectorNumber) bool { + return m.sealing.IsMarkedForUpgrade(id) +} From dad3e967195b1bcddb845bb2c443f2f882dcda07 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Fri, 21 Aug 2020 15:55:01 -0400 Subject: [PATCH 038/247] Update create miner info --- documentation/en/join-testnet.md | 4 ++-- documentation/en/mining.md | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/documentation/en/join-testnet.md b/documentation/en/join-testnet.md index 3cbd0ac3f..6660d26d8 100644 --- a/documentation/en/join-testnet.md +++ b/documentation/en/join-testnet.md @@ -58,8 +58,8 @@ t1aswwvjsae63tcrniz6x5ykvsuotlgkvlulnqpsi ``` - Visit the [faucet](http://spacerace.faucet.glif.io/) to add funds. -- Paste the address you created. -- Press the send button. +- Paste the address you created under REQUEST. +- Press the Request button. ## Check wallet address balance diff --git a/documentation/en/mining.md b/documentation/en/mining.md index d286266f1..f851ebe45 100644 --- a/documentation/en/mining.md +++ b/documentation/en/mining.md @@ -29,8 +29,9 @@ lotus wallet new bls With your wallet address: - Visit the [faucet](http://spacerace.faucet.glif.io/) -- Click "Create Miner" -- DO NOT REFRESH THE PAGE. THIS OPERATION CAN TAKE SOME TIME. +- Paste the address you created under REQUEST. +- Press the Request button. +- Run `/lotus-miner init --owner= --worker=` The task will be complete when you see: From 161cb32078984740df4f982834686b02e6f8666f Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 21 Aug 2020 20:17:30 +0300 Subject: [PATCH 039/247] recover from errors in head change --- chain/messagepool/messagepool.go | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index d55b45e14..90d856258 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -12,6 +12,7 @@ import ( "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/hashicorp/go-multierror" lru "github.com/hashicorp/golang-lru" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" @@ -744,30 +745,42 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet) } } + var merr error + for _, ts := range revert { pts, err := mp.api.LoadTipSet(ts.Parents()) if err != nil { - return err - } - - msgs, err := mp.MessagesForBlocks(ts.Blocks()) - if err != nil { - return err + log.Errorf("error loading reverted tipset parent: %s", err) + merr = multierror.Append(merr, err) + continue } mp.curTs = pts + msgs, err := mp.MessagesForBlocks(ts.Blocks()) + if err != nil { + log.Errorf("error retrieving messages for reverted block: %s", err) + merr = multierror.Append(merr, err) + continue + } + for _, msg := range msgs { add(msg) } } for _, ts := range apply { + mp.curTs = ts + for _, b := range ts.Blocks() { bmsgs, smsgs, err := mp.api.MessagesForBlock(b) if err != nil { - return xerrors.Errorf("failed to get messages for apply block %s(height %d) (msgroot = %s): %w", b.Cid(), b.Height, b.Messages, err) + xerr := xerrors.Errorf("failed to get messages for apply block %s(height %d) (msgroot = %s): %w", b.Cid(), b.Height, b.Messages, err) + log.Errorf("error retrieving messages for block: %s", xerr) + merr = multierror.Append(merr, xerr) + continue } + for _, msg := range smsgs { rm(msg.Message.From, msg.Message.Nonce) maybeRepub(msg.Cid()) @@ -778,8 +791,6 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet) maybeRepub(msg.Cid()) } } - - mp.curTs = ts } if repubTrigger { @@ -862,7 +873,7 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet) } } - return nil + return merr } type statBucket struct { From 30272837564b5a79d71ecc1c5e1efb2a355adcc5 Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 21 Aug 2020 20:28:45 +0300 Subject: [PATCH 040/247] add MpoolClear api --- api/api_full.go | 3 +++ api/apistruct/struct.go | 8 +++++++- chain/messagepool/messagepool.go | 8 ++++++++ node/impl/full/mpool.go | 5 +++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/api/api_full.go b/api/api_full.go index 71e3987df..7cc88fa80 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -184,6 +184,9 @@ type FullNode interface { MpoolGetNonce(context.Context, address.Address) (uint64, error) MpoolSub(context.Context) (<-chan MpoolUpdate, error) + // MpoolClear clears all pending messages from the mpool + MpoolClear(context.Context) error + // MpoolGetConfig returns (a copy of) the current mpool config MpoolGetConfig(context.Context) (*types.MpoolConfig, error) // MpoolSetConfig sets the mpool config to (a copy of) the supplied config diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index 5f027543e..219aea495 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -106,7 +106,9 @@ type FullNodeStruct struct { MpoolSelect func(context.Context, types.TipSetKey, float64) ([]*types.SignedMessage, error) `perm:"read"` - MpoolPending func(context.Context, types.TipSetKey) ([]*types.SignedMessage, error) `perm:"read"` + MpoolPending func(context.Context, types.TipSetKey) ([]*types.SignedMessage, error) `perm:"read"` + MpoolClear func(context.Context) error `perm:"write"` + MpoolPush func(context.Context, *types.SignedMessage) (cid.Cid, error) `perm:"write"` MpoolPushMessage func(context.Context, *types.Message, *api.MessageSendSpec) (*types.SignedMessage, error) `perm:"sign"` MpoolGetNonce func(context.Context, address.Address) (uint64, error) `perm:"read"` @@ -494,6 +496,10 @@ func (c *FullNodeStruct) MpoolPending(ctx context.Context, tsk types.TipSetKey) return c.Internal.MpoolPending(ctx, tsk) } +func (c *FullNodeStruct) MpoolClear(ctx context.Context) error { + return c.Internal.MpoolClear(ctx) +} + func (c *FullNodeStruct) MpoolPush(ctx context.Context, smsg *types.SignedMessage) (cid.Cid, error) { return c.Internal.MpoolPush(ctx, smsg) } diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 90d856258..79590ae86 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -973,3 +973,11 @@ func (mp *MessagePool) loadLocal() error { return nil } + +func (mp *MessagePool) Clear() { + mp.lk.Lock() + defer mp.lk.Unlock() + + mp.pending = make(map[address.Address]*msgSet) + mp.republished = nil +} diff --git a/node/impl/full/mpool.go b/node/impl/full/mpool.go index bde7d4f81..bb4ce2b62 100644 --- a/node/impl/full/mpool.go +++ b/node/impl/full/mpool.go @@ -105,6 +105,11 @@ func (a *MpoolAPI) MpoolPending(ctx context.Context, tsk types.TipSetKey) ([]*ty } } +func (a *MpoolAPI) MpoolClear(ctx context.Context) error { + a.Mpool.Clear() + return nil +} + func (a *MpoolAPI) MpoolPush(ctx context.Context, smsg *types.SignedMessage) (cid.Cid, error) { return a.Mpool.Push(smsg) } From 0c875774ceaca7c4173b10c97dc59a4217f38e35 Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 21 Aug 2020 20:31:25 +0300 Subject: [PATCH 041/247] add mpool clear cli command --- cli/mpool.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/cli/mpool.go b/cli/mpool.go index 62ab06dae..3ec77a647 100644 --- a/cli/mpool.go +++ b/cli/mpool.go @@ -20,6 +20,7 @@ var mpoolCmd = &cli.Command{ Usage: "Manage message pool", Subcommands: []*cli.Command{ mpoolPending, + mpoolClear, mpoolSub, mpoolStat, mpoolReplaceCmd, @@ -83,6 +84,22 @@ var mpoolPending = &cli.Command{ }, } +var mpoolClear = &cli.Command{ + Name: "clear", + Usage: "Clear all pending messages from the mpool (USE WITH CARE)", + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := ReqContext(cctx) + + return api.MpoolClear(ctx) + }, +} + var mpoolSub = &cli.Command{ Name: "sub", Usage: "Subscribe to mpool changes", From 9fc674feb4896de696334c21269cecd259f25221 Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 21 Aug 2020 20:34:44 +0300 Subject: [PATCH 042/247] update mpool documentation --- documentation/en/mpool.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/documentation/en/mpool.md b/documentation/en/mpool.md index 0425b04e0..ebca03fcb 100644 --- a/documentation/en/mpool.md +++ b/documentation/en/mpool.md @@ -20,6 +20,7 @@ The full node API defines the following methods for interacting with the mpool: MpoolSub(context.Context) (<-chan MpoolUpdate, error) MpoolGetConfig(context.Context) (*types.MpoolConfig, error) MpoolSetConfig(context.Context, *types.MpoolConfig) error + MpoolClear(context.Context) error ``` ### MpoolPending @@ -61,6 +62,12 @@ Returns (a copy of) the current mpool configuration. Sets the mpool configuration to (a copy of) the supplied configuration object. +### MpoolClear + +Unconditionally clears all pending messages from the mpool. +This should be used with extreme care and only in the case of errors during head changes that +would leave the mpool in an inconsistent state. + ## Command Line Interfae @@ -75,6 +82,7 @@ lotus mpool stat [--local] lotus mpool replace [--gas-feecap ] [--gas-premium ] [--gas-limit ] [from] [nonce] lotus mpool find [--from

] [--to
] [--method ] lotus mpool config [] +lotus mpool clear ``` ### lotus mpool pending @@ -98,6 +106,12 @@ Searches for messages in the mpool. ### lotus mpool config Gets or sets the current mpool configuration. +### lotus mpool clear +Unconditionally clears all pending messages from the mpool. + +*Warning*: this command should only be used in the case of head change errors leaving the mpool in an +inconsistent state. + ## Configuration The mpool a few parameters that can be configured by the user, either through the API From e33d398c3397be1f959ef3fd36352aac138f9e60 Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 21 Aug 2020 20:51:03 +0300 Subject: [PATCH 043/247] remove pending local messages from the datastore when clearing the mpool --- chain/messagepool/messagepool.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 79590ae86..817641ebe 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -978,6 +978,22 @@ func (mp *MessagePool) Clear() { mp.lk.Lock() defer mp.lk.Unlock() + // remove local messages from the datastore + for a := range mp.localAddrs { + mset, ok := mp.pending[a] + if !ok { + continue + } + + for _, m := range mset.msgs { + err := mp.localMsgs.Delete(datastore.NewKey(string(m.Cid().Bytes()))) + if err != nil { + log.Warnf("error deleting local message: %s", err) + } + } + } + + // clear the maps mp.pending = make(map[address.Address]*msgSet) mp.republished = nil } From 087955e92716171aec1b8dc8c7b1d1e917e619df Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 21 Aug 2020 20:59:40 +0300 Subject: [PATCH 044/247] add localonly option to MpoolClear --- api/api_full.go | 2 +- api/apistruct/struct.go | 6 +++--- chain/messagepool/messagepool.go | 9 +++++++-- cli/mpool.go | 11 +++++++++-- documentation/en/mpool.md | 11 +++++++---- node/impl/full/mpool.go | 4 ++-- 6 files changed, 29 insertions(+), 14 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index 7cc88fa80..9a8643146 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -185,7 +185,7 @@ type FullNode interface { MpoolSub(context.Context) (<-chan MpoolUpdate, error) // MpoolClear clears all pending messages from the mpool - MpoolClear(context.Context) error + MpoolClear(context.Context, bool) error // MpoolGetConfig returns (a copy of) the current mpool config MpoolGetConfig(context.Context) (*types.MpoolConfig, error) diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index 219aea495..05f22139a 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -107,7 +107,7 @@ type FullNodeStruct struct { MpoolSelect func(context.Context, types.TipSetKey, float64) ([]*types.SignedMessage, error) `perm:"read"` MpoolPending func(context.Context, types.TipSetKey) ([]*types.SignedMessage, error) `perm:"read"` - MpoolClear func(context.Context) error `perm:"write"` + MpoolClear func(context.Context, bool) error `perm:"write"` MpoolPush func(context.Context, *types.SignedMessage) (cid.Cid, error) `perm:"write"` MpoolPushMessage func(context.Context, *types.Message, *api.MessageSendSpec) (*types.SignedMessage, error) `perm:"sign"` @@ -496,8 +496,8 @@ func (c *FullNodeStruct) MpoolPending(ctx context.Context, tsk types.TipSetKey) return c.Internal.MpoolPending(ctx, tsk) } -func (c *FullNodeStruct) MpoolClear(ctx context.Context) error { - return c.Internal.MpoolClear(ctx) +func (c *FullNodeStruct) MpoolClear(ctx context.Context, localonly bool) error { + return c.Internal.MpoolClear(ctx, localonly) } func (c *FullNodeStruct) MpoolPush(ctx context.Context, smsg *types.SignedMessage) (cid.Cid, error) { diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 817641ebe..684aa80aa 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -974,7 +974,7 @@ func (mp *MessagePool) loadLocal() error { return nil } -func (mp *MessagePool) Clear() { +func (mp *MessagePool) Clear(localonly bool) { mp.lk.Lock() defer mp.lk.Unlock() @@ -991,9 +991,14 @@ func (mp *MessagePool) Clear() { log.Warnf("error deleting local message: %s", err) } } + + delete(mp.pending, a) } // clear the maps - mp.pending = make(map[address.Address]*msgSet) mp.republished = nil + if !localonly { + mp.pending = make(map[address.Address]*msgSet) + } + } diff --git a/cli/mpool.go b/cli/mpool.go index 3ec77a647..e6f0bacc7 100644 --- a/cli/mpool.go +++ b/cli/mpool.go @@ -87,6 +87,12 @@ var mpoolPending = &cli.Command{ var mpoolClear = &cli.Command{ Name: "clear", Usage: "Clear all pending messages from the mpool (USE WITH CARE)", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "local", + Usage: "clear local messages only", + }, + }, Action: func(cctx *cli.Context) error { api, closer, err := GetFullNodeAPI(cctx) if err != nil { @@ -94,9 +100,10 @@ var mpoolClear = &cli.Command{ } defer closer() - ctx := ReqContext(cctx) + local := cctx.Bool("local") - return api.MpoolClear(ctx) + ctx := ReqContext(cctx) + return api.MpoolClear(ctx, local) }, } diff --git a/documentation/en/mpool.md b/documentation/en/mpool.md index ebca03fcb..d26120d8e 100644 --- a/documentation/en/mpool.md +++ b/documentation/en/mpool.md @@ -20,7 +20,7 @@ The full node API defines the following methods for interacting with the mpool: MpoolSub(context.Context) (<-chan MpoolUpdate, error) MpoolGetConfig(context.Context) (*types.MpoolConfig, error) MpoolSetConfig(context.Context, *types.MpoolConfig) error - MpoolClear(context.Context) error + MpoolClear(context.Context, localonly bool) error ``` ### MpoolPending @@ -64,7 +64,8 @@ Sets the mpool configuration to (a copy of) the supplied configuration object. ### MpoolClear -Unconditionally clears all pending messages from the mpool. +Clears pending messages from the mpool; if `localonly` is `true` then only local messages are cleared. + This should be used with extreme care and only in the case of errors during head changes that would leave the mpool in an inconsistent state. @@ -82,7 +83,7 @@ lotus mpool stat [--local] lotus mpool replace [--gas-feecap ] [--gas-premium ] [--gas-limit ] [from] [nonce] lotus mpool find [--from
] [--to
] [--method ] lotus mpool config [] -lotus mpool clear +lotus mpool clear [--local] ``` ### lotus mpool pending @@ -107,7 +108,9 @@ Searches for messages in the mpool. Gets or sets the current mpool configuration. ### lotus mpool clear -Unconditionally clears all pending messages from the mpool. +Unconditionally clears pending messages from the mpool. +If the `--local` flag is passed, then only local messages are cleared; otherwise all messages +are cleared. *Warning*: this command should only be used in the case of head change errors leaving the mpool in an inconsistent state. diff --git a/node/impl/full/mpool.go b/node/impl/full/mpool.go index bb4ce2b62..388eaa9d0 100644 --- a/node/impl/full/mpool.go +++ b/node/impl/full/mpool.go @@ -105,8 +105,8 @@ func (a *MpoolAPI) MpoolPending(ctx context.Context, tsk types.TipSetKey) ([]*ty } } -func (a *MpoolAPI) MpoolClear(ctx context.Context) error { - a.Mpool.Clear() +func (a *MpoolAPI) MpoolClear(ctx context.Context, localonly bool) error { + a.Mpool.Clear(localonly) return nil } From 3debf005a8e9a1076389e0c8ec9a52b3d27d5bc1 Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 21 Aug 2020 22:20:31 +0300 Subject: [PATCH 045/247] add --really-do-it flag to mpool clear command --- cli/mpool.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cli/mpool.go b/cli/mpool.go index e6f0bacc7..50a4485d2 100644 --- a/cli/mpool.go +++ b/cli/mpool.go @@ -92,6 +92,10 @@ var mpoolClear = &cli.Command{ Name: "local", Usage: "clear local messages only", }, + &cli.BoolFlag{ + Name: "really-do-it", + Usage: "must be specified for the action to take effect", + }, }, Action: func(cctx *cli.Context) error { api, closer, err := GetFullNodeAPI(cctx) @@ -100,6 +104,11 @@ var mpoolClear = &cli.Command{ } defer closer() + really := cctx.Bool("really-do-it") + if !really { + return fmt.Errorf("--really-do-it must be specified for this action to have an effect; you have been warned.") + } + local := cctx.Bool("local") ctx := ReqContext(cctx) From 817358f1bb8786da4204ee7afcc8ed403ae59a55 Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 21 Aug 2020 23:24:53 +0300 Subject: [PATCH 046/247] better semantics for mpool clear local argument local messages should be kept unless the parameter is true --- api/api_full.go | 2 +- api/apistruct/struct.go | 4 +-- chain/messagepool/messagepool.go | 44 +++++++++++++++++++------------- cli/mpool.go | 2 +- documentation/en/mpool.md | 10 +++----- node/impl/full/mpool.go | 4 +-- 6 files changed, 36 insertions(+), 30 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index 9a8643146..2d8a4e515 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -184,7 +184,7 @@ type FullNode interface { MpoolGetNonce(context.Context, address.Address) (uint64, error) MpoolSub(context.Context) (<-chan MpoolUpdate, error) - // MpoolClear clears all pending messages from the mpool + // MpoolClear clears pending messages from the mpool MpoolClear(context.Context, bool) error // MpoolGetConfig returns (a copy of) the current mpool config diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index 05f22139a..0b8ba00e4 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -496,8 +496,8 @@ func (c *FullNodeStruct) MpoolPending(ctx context.Context, tsk types.TipSetKey) return c.Internal.MpoolPending(ctx, tsk) } -func (c *FullNodeStruct) MpoolClear(ctx context.Context, localonly bool) error { - return c.Internal.MpoolClear(ctx, localonly) +func (c *FullNodeStruct) MpoolClear(ctx context.Context, local bool) error { + return c.Internal.MpoolClear(ctx, local) } func (c *FullNodeStruct) MpoolPush(ctx context.Context, smsg *types.SignedMessage) (cid.Cid, error) { diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 684aa80aa..644a9104f 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -974,31 +974,39 @@ func (mp *MessagePool) loadLocal() error { return nil } -func (mp *MessagePool) Clear(localonly bool) { +func (mp *MessagePool) Clear(local bool) { mp.lk.Lock() defer mp.lk.Unlock() - // remove local messages from the datastore - for a := range mp.localAddrs { - mset, ok := mp.pending[a] - if !ok { - continue - } + // remove everything if local is true, including removing local messages from + // the datastore + if local { + for a := range mp.localAddrs { + mset, ok := mp.pending[a] + if !ok { + continue + } - for _, m := range mset.msgs { - err := mp.localMsgs.Delete(datastore.NewKey(string(m.Cid().Bytes()))) - if err != nil { - log.Warnf("error deleting local message: %s", err) + for _, m := range mset.msgs { + err := mp.localMsgs.Delete(datastore.NewKey(string(m.Cid().Bytes()))) + if err != nil { + log.Warnf("error deleting local message: %s", err) + } } } + mp.pending = make(map[address.Address]*msgSet) + mp.republished = nil + + return + } + + // remove everything except the local messages + for a := range mp.pending { + _, isLocal := mp.localAddrs[a] + if isLocal { + continue + } delete(mp.pending, a) } - - // clear the maps - mp.republished = nil - if !localonly { - mp.pending = make(map[address.Address]*msgSet) - } - } diff --git a/cli/mpool.go b/cli/mpool.go index 50a4485d2..4562ef398 100644 --- a/cli/mpool.go +++ b/cli/mpool.go @@ -90,7 +90,7 @@ var mpoolClear = &cli.Command{ Flags: []cli.Flag{ &cli.BoolFlag{ Name: "local", - Usage: "clear local messages only", + Usage: "also clear local messages", }, &cli.BoolFlag{ Name: "really-do-it", diff --git a/documentation/en/mpool.md b/documentation/en/mpool.md index d26120d8e..bbb7f2440 100644 --- a/documentation/en/mpool.md +++ b/documentation/en/mpool.md @@ -20,7 +20,7 @@ The full node API defines the following methods for interacting with the mpool: MpoolSub(context.Context) (<-chan MpoolUpdate, error) MpoolGetConfig(context.Context) (*types.MpoolConfig, error) MpoolSetConfig(context.Context, *types.MpoolConfig) error - MpoolClear(context.Context, localonly bool) error + MpoolClear(context.Context, local bool) error ``` ### MpoolPending @@ -64,7 +64,7 @@ Sets the mpool configuration to (a copy of) the supplied configuration object. ### MpoolClear -Clears pending messages from the mpool; if `localonly` is `true` then only local messages are cleared. +Clears pending messages from the mpool; if `local` is `true` then local messages are also cleared and removed from the datastore. This should be used with extreme care and only in the case of errors during head changes that would leave the mpool in an inconsistent state. @@ -109,11 +109,9 @@ Gets or sets the current mpool configuration. ### lotus mpool clear Unconditionally clears pending messages from the mpool. -If the `--local` flag is passed, then only local messages are cleared; otherwise all messages -are cleared. +If the `--local` flag is passed, then local messages are also cleared; otherwise local messages are retained. -*Warning*: this command should only be used in the case of head change errors leaving the mpool in an -inconsistent state. +*Warning*: this command should only be used in the case of head change errors leaving the mpool in an state. ## Configuration diff --git a/node/impl/full/mpool.go b/node/impl/full/mpool.go index 388eaa9d0..fe2b054dd 100644 --- a/node/impl/full/mpool.go +++ b/node/impl/full/mpool.go @@ -105,8 +105,8 @@ func (a *MpoolAPI) MpoolPending(ctx context.Context, tsk types.TipSetKey) ([]*ty } } -func (a *MpoolAPI) MpoolClear(ctx context.Context, localonly bool) error { - a.Mpool.Clear(localonly) +func (a *MpoolAPI) MpoolClear(ctx context.Context, local bool) error { + a.Mpool.Clear(local) return nil } From 04bd91b2f3bebc6ea9300fb49018b4fed9c29b46 Mon Sep 17 00:00:00 2001 From: MollyM Date: Fri, 21 Aug 2020 14:32:56 -0700 Subject: [PATCH 047/247] fix date --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 112494db1..0b7c6ff2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Lotus changelog -## 0.5.0 / 2020-08-2020 +## 0.5.0 / 2020-08-20 This version of Lotus will be used for the incentivized testnet Space Race competition, and can be considered mainnet-ready code. It includes some protocol @@ -145,4 +145,4 @@ We are grateful for every contribution! We are very excited to release **lotus** 0.1.0. This is our testnet release. To install lotus and join the testnet, please visit [lotu.sh](lotu.sh). Please file bug reports as [issues](https://github.com/filecoin-project/lotus/issues). -A huge thank you to all contributors for this testnet release! \ No newline at end of file +A huge thank you to all contributors for this testnet release! From 25875b4cd8d22a244788dfa84b449d93e395a0ae Mon Sep 17 00:00:00 2001 From: MollyM Date: Fri, 21 Aug 2020 14:35:12 -0700 Subject: [PATCH 048/247] change hierarchy --- CHANGELOG.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b7c6ff2f..ece1f18a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,12 @@ # Lotus changelog -## 0.5.0 / 2020-08-20 +# 0.5.0 / 2020-08-20 This version of Lotus will be used for the incentivized testnet Space Race competition, and can be considered mainnet-ready code. It includes some protocol changes, upgrades of core dependencies, and various bugfixes and UX/performance improvements. -# Highlights +## Highlights Among the highlights included in this release are: @@ -16,7 +16,7 @@ and the packing of multiple deals into a single sector. - Renamed features: We renamed some of the binaries, environment variables, and default paths associated with a Lotus node. -## Gas changes +### Gas changes We made some significant changes to the mechanics of gas in this release. @@ -73,7 +73,7 @@ data can be quickly served in a retrieval deal, since it will not need to be uns Miners can now pack multiple deals into a single sector, so long as all the deals fit into the sector capacity. This should increase the packing efficiency of miners. -## Renamed features +### Renamed features To improve the user experience, we updated several names to mainatin standard prefixing, and to better reflect the meaning of the features being referenced. @@ -83,7 +83,7 @@ path for miner data is now `~/.lotusminer`, and the environment variable that sets the path for miner data is now `$LOTUS_MINER_PATH`. A full list of renamed features can be found [here](https://github.com/filecoin-project/lotus/issues/2304). -# Changelog +## Changelog #### Downstream upgrades - Upgrades markets to v0.5.6 (https://github.com/filecoin-project/lotus/pull/3058) @@ -114,7 +114,7 @@ features can be found [here](https://github.com/filecoin-project/lotus/issues/23 - Miners can toggle auto-acceptance of deals (https://github.com/filecoin-project/lotus/pull/1994) - Miners can maintain a blocklist of piece CIDs (https://github.com/filecoin-project/lotus/pull/2069) -# Contributors +## Contributors The following contributors had 10 or more commits go into this release. We are grateful for every contribution! @@ -141,7 +141,7 @@ We are grateful for every contribution! | Stebalien | 11 | +1204/-980 | | RobQuistNL | 10 | +69/-74 | -## 0.1.0 / 2019-12-11 +# 0.1.0 / 2019-12-11 We are very excited to release **lotus** 0.1.0. This is our testnet release. To install lotus and join the testnet, please visit [lotu.sh](lotu.sh). Please file bug reports as [issues](https://github.com/filecoin-project/lotus/issues). From 88016c17e4b96ca68ea8a0534b9098fe7eda5642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Sat, 22 Aug 2020 19:15:08 +0200 Subject: [PATCH 049/247] miner info: Fix avail calc, print aggregate deal info --- cmd/lotus-storage-miner/info.go | 47 ++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/cmd/lotus-storage-miner/info.go b/cmd/lotus-storage-miner/info.go index 79487cc2e..22981e1da 100644 --- a/cmd/lotus-storage-miner/info.go +++ b/cmd/lotus-storage-miner/info.go @@ -11,14 +11,22 @@ import ( "github.com/urfave/cli/v2" "golang.org/x/xerrors" + cbor "github.com/ipfs/go-ipld-cbor" + + "github.com/filecoin-project/go-fil-markets/storagemarket" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" + "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/builtin/power" + "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/apibstore" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/lib/blockstore" + "github.com/filecoin-project/lotus/lib/bufbstore" ) var infoCmd = &cli.Command{ @@ -47,6 +55,11 @@ func infoCmdAct(cctx *cli.Context) error { ctx := lcli.ReqContext(cctx) + head, err := api.ChainHead(ctx) + if err != nil { + return xerrors.Errorf("getting chain head: %w", err) + } + maddr, err := getActorAddress(ctx, nodeApi, cctx.String("actor")) if err != nil { return err @@ -141,11 +154,43 @@ func infoCmdAct(cctx *cli.Context) error { fmt.Println() + deals, err := nodeApi.MarketListIncompleteDeals(ctx) + if err != nil { + return err + } + + var nactiveDeals, nVerifDeals, ndeals uint64 + var activeDealBytes, activeVerifDealBytes, dealBytes abi.PaddedPieceSize + for _, deal := range deals { + ndeals++ + dealBytes += deal.Proposal.PieceSize + + if deal.State == storagemarket.StorageDealActive{ + nactiveDeals++ + activeDealBytes += deal.Proposal.PieceSize + + if deal.Proposal.VerifiedDeal { + nVerifDeals++ + activeVerifDealBytes += deal.Proposal.PieceSize + } + } + } + + fmt.Printf("Deals: %d, %s\n", ndeals, types.SizeStr(types.NewInt(uint64(dealBytes)))) + fmt.Printf("\tActive: %d, %s (Verified: %d, %s)\n", nactiveDeals, types.SizeStr(types.NewInt(uint64(activeDealBytes))), nVerifDeals, types.SizeStr(types.NewInt(uint64(activeVerifDealBytes)))) + fmt.Println() + + tbs := bufbstore.NewTieredBstore(apibstore.NewAPIBlockstore(api), blockstore.NewTemporary()) + _, err = mas.UnlockVestedFunds(adt.WrapStore(ctx, cbor.NewCborStore(tbs)), head.Height()) + if err != nil { + return xerrors.Errorf("calculating vested funds: %w", err) + } + fmt.Printf("Miner Balance: %s\n", color.YellowString("%s", types.FIL(mact.Balance))) fmt.Printf("\tPreCommit: %s\n", types.FIL(mas.PreCommitDeposits)) fmt.Printf("\tPledge: %s\n", types.FIL(mas.InitialPledgeRequirement)) fmt.Printf("\tLocked: %s\n", types.FIL(mas.LockedFunds)) - color.Green("\tAvailable: %s", types.FIL(types.BigSub(mact.Balance, types.BigAdd(mas.LockedFunds, mas.PreCommitDeposits)))) + color.Green("\tAvailable: %s", types.FIL(mas.GetAvailableBalance(mact.Balance))) wb, err := api.WalletBalance(ctx, mi.Worker) if err != nil { return xerrors.Errorf("getting worker balance: %w", err) From 12af420d7e67d99e2fbf4d080b0d3e236c9108ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Sat, 22 Aug 2020 19:16:37 +0200 Subject: [PATCH 050/247] mod tidy --- cmd/lotus-storage-miner/info.go | 2 +- go.sum | 11 ----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/cmd/lotus-storage-miner/info.go b/cmd/lotus-storage-miner/info.go index 22981e1da..3118e6afa 100644 --- a/cmd/lotus-storage-miner/info.go +++ b/cmd/lotus-storage-miner/info.go @@ -165,7 +165,7 @@ func infoCmdAct(cctx *cli.Context) error { ndeals++ dealBytes += deal.Proposal.PieceSize - if deal.State == storagemarket.StorageDealActive{ + if deal.State == storagemarket.StorageDealActive { nactiveDeals++ activeDealBytes += deal.Proposal.PieceSize diff --git a/go.sum b/go.sum index 6d352d9c0..16b627ca5 100644 --- a/go.sum +++ b/go.sum @@ -230,8 +230,6 @@ github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20200731171407-e559a0579161 github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20200731171407-e559a0579161/go.mod h1:vgmwKBkx+ca5OIeEvstiQgzAZnb7R6QaqE1oEDSqa6g= github.com/filecoin-project/go-bitfield v0.0.0-20200416002808-b3ee67ec9060/go.mod h1:iodsLxOFZnqKtjj2zkgqzoGNrv6vUqj69AT/J8DKXEw= github.com/filecoin-project/go-bitfield v0.0.1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= -github.com/filecoin-project/go-bitfield v0.0.3/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= -github.com/filecoin-project/go-bitfield v0.0.4-0.20200703174658-f4a5758051a1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= github.com/filecoin-project/go-bitfield v0.1.2 h1:TjLregCoyP1/5lm7WCM0axyV1myIHwbjGa21skuu5tk= github.com/filecoin-project/go-bitfield v0.1.2/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= github.com/filecoin-project/go-bitfield v0.2.0 h1:gCtLcjskIPtdg4NfN7gQZSQF9yrBQ7mkT0qCJxzGI2Q= @@ -242,7 +240,6 @@ github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 h1:2pMX github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= github.com/filecoin-project/go-data-transfer v0.6.2 h1:IgbkwcHoyWGglzfsY7P9L1GapzoiLNKuzfZY2bxER8E= github.com/filecoin-project/go-data-transfer v0.6.2/go.mod h1:uRYBRKVBVM12CSusBtVrzDHkVw/3DKZpkxKJVP1Ydas= -github.com/filecoin-project/go-fil-commcid v0.0.0-20200208005934-2b8bd03caca5/go.mod h1:JbkIgFF/Z9BDlvrJO1FuKkaWsH673/UdFaiVS6uIHlA= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1:GxJzR3oRIMTPtpZ0b7QF8FKPK6/iPAc7trhlL5k/g+s= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= github.com/filecoin-project/go-fil-markets v0.5.7 h1:kzyMHqez8ssxchj5s9M1hkC3CTwRGh2MeglJGfUksQU= @@ -253,11 +250,9 @@ github.com/filecoin-project/go-multistore v0.0.3 h1:vaRBY4YiA2UZFPK57RNuewypB8u0 github.com/filecoin-project/go-multistore v0.0.3/go.mod h1:kaNqCC4IhU4B1uyr7YWFHd23TL4KM32aChS0jNkyUvQ= github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6 h1:92PET+sx1Hb4W/8CgFwGuxaKbttwY+UNspYZTvXY0vs= github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6/go.mod h1:0HgYnrkeSU4lu1p+LEOeDpFsNBssa0OGGriWdA4hvaE= -github.com/filecoin-project/go-paramfetch v0.0.1/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= github.com/filecoin-project/go-paramfetch v0.0.2-0.20200218225740-47c639bab663/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261 h1:A256QonvzRaknIIAuWhe/M2dpV2otzs3NBhi5TWa/UA= github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= -github.com/filecoin-project/go-statemachine v0.0.0-20200226041606-2074af6d51d9/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v0.0.0-20200714194326-a77c3ae20989/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370 h1:Jbburj7Ih2iaJ/o5Q9A+EAeTabME6YII7FLi9SKUf5c= github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= @@ -265,14 +260,12 @@ github.com/filecoin-project/go-statestore v0.1.0 h1:t56reH59843TwXHkMcwyuayStBIi github.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZOinUJB4WARkRfNl10O7kTnI= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b h1:fkRZSPrYpk42PV3/lIXiL0LHetxde7vyYYvSsttQtfg= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8= -github.com/filecoin-project/sector-storage v0.0.0-20200712023225-1d67dcfa3c15/go.mod h1:salgVdX7qeXFo/xaiEQE29J4pPkjn71T0kt0n+VDBzo= github.com/filecoin-project/sector-storage v0.0.0-20200730050024-3ee28c3b6d9a/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0 h1:E1fZ27fhKK05bhZItfTwqr1i05vXnEZJznQFEYwEEUU= github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= github.com/filecoin-project/specs-actors v0.0.0-20200210130641-2d1fbd8672cf/go.mod h1:xtDZUB6pe4Pksa/bAJbJ693OilaC5Wbot9jMhLm3cZA= github.com/filecoin-project/specs-actors v0.3.0/go.mod h1:nQYnFbQ7Y0bHZyq6HDEuVlCPR+U3z5Q3wMOQ+2aiV+Y= github.com/filecoin-project/specs-actors v0.6.1/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY= -github.com/filecoin-project/specs-actors v0.7.3-0.20200716231407-60a2ae96d2e6/go.mod h1:JOMUa7EijvpOO4ofD1yeHNmqohkmmnhTvz/IpB6so4c= github.com/filecoin-project/specs-actors v0.8.2/go.mod h1:Q3ACV5kBLvqPaYbthc/J1lGMJ5OwogmD9pzdtPRMdCw= github.com/filecoin-project/specs-actors v0.8.7-0.20200811203034-272d022c1923 h1:+H4IG4OjTThljPkMH1ZpynxCulNdx4amEeHoP2GdQJI= github.com/filecoin-project/specs-actors v0.8.7-0.20200811203034-272d022c1923/go.mod h1:hukRu6vKQrrS7Nt+fC/ql4PqWLSfmAWNshD/VDtARZU= @@ -535,7 +528,6 @@ github.com/ipfs/go-graphsync v0.1.0/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CE github.com/ipfs/go-graphsync v0.1.1 h1:bFDAYS0Z48yd8ROPI6f/zIVmJxaDLA6m8cVuJPKC5fE= github.com/ipfs/go-graphsync v0.1.1/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= github.com/ipfs/go-hamt-ipld v0.0.15-0.20200131012125-dd88a59d3f2e/go.mod h1:9aQJu/i/TaRDW6jqB5U217dLIDopn50wxLdHXM2CTfE= -github.com/ipfs/go-hamt-ipld v0.0.15-0.20200204200533-99b8553ef242/go.mod h1:kq3Pi+UP3oHhAdKexE+kHHYRKMoFNuGero0R7q3hWGg= github.com/ipfs/go-hamt-ipld v0.1.1 h1:0IQdvwnAAUKmDE+PMJa5y1QiwOPHpI9+eAbQEEEYthk= github.com/ipfs/go-hamt-ipld v0.1.1/go.mod h1:1EZCr2v0jlCnhpa+aZ0JZYp8Tt2w16+JJOAVz17YcDk= github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= @@ -1510,7 +1502,6 @@ golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1667,7 +1658,6 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1729,7 +1719,6 @@ golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200108195415-316d2f248479/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= From 27e3f8ee29033abdf043d7aba1fb36f113dbdeaf Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Sat, 22 Aug 2020 18:53:44 -0700 Subject: [PATCH 051/247] fix setup of burnt funds actor state --- chain/gen/genesis/genesis.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index 40f006522..95d23a5b7 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -118,11 +118,6 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge return nil, nil, xerrors.Errorf("making new state tree: %w", err) } - emptyobject, err := cst.Put(context.TODO(), []struct{}{}) - if err != nil { - return nil, nil, xerrors.Errorf("failed putting empty object: %w", err) - } - // Create system actor sysact, err := SetupSystemActor(bs) @@ -191,11 +186,18 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge return nil, nil, xerrors.Errorf("set market actor: %w", err) } + burntRoot, err := cst.Put(ctx, &account.State{ + Address: builtin.BurntFundsActorAddr, + }) + if err != nil { + return nil, nil, xerrors.Errorf("failed to setup burnt funds actor state: %w", err) + } + // Setup burnt-funds err = state.SetActor(builtin.BurntFundsActorAddr, &types.Actor{ Code: builtin.AccountActorCodeID, Balance: types.NewInt(0), - Head: emptyobject, + Head: burntRoot, }) if err != nil { return nil, nil, xerrors.Errorf("set burnt funds account actor: %w", err) From da8dbc8ffebce362cbbeb6d5f009e9c0fa06b0db Mon Sep 17 00:00:00 2001 From: Mike Greenberg Date: Sun, 23 Aug 2020 01:59:15 -0400 Subject: [PATCH 052/247] fix(chainwatch): Make processor failures independent of each other --- cmd/lotus-chainwatch/processor/processor.go | 59 +++++++++++++-------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/cmd/lotus-chainwatch/processor/processor.go b/cmd/lotus-chainwatch/processor/processor.go index 2f70f1cb3..f231099b6 100644 --- a/cmd/lotus-chainwatch/processor/processor.go +++ b/cmd/lotus-chainwatch/processor/processor.go @@ -8,7 +8,6 @@ import ( "sync" "time" - "golang.org/x/sync/errgroup" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" @@ -144,60 +143,74 @@ func (p *Processor) Start(ctx context.Context) { "AccountChanges", len(actorChanges[builtin.AccountActorCodeID]), "nullRounds", len(nullRounds)) - grp, ctx := errgroup.WithContext(ctx) + grp := sync.WaitGroup{} - grp.Go(func() error { + grp.Add(1) + go func() error { + defer grp.Done() if err := p.HandleMarketChanges(ctx, actorChanges[builtin.StorageMarketActorCodeID]); err != nil { - return xerrors.Errorf("Failed to handle market changes: %w", err) + log.Errorf("Failed to handle market changes: %w", err) + return nil } log.Info("Processed Market Changes") return nil - }) + }() - grp.Go(func() error { + grp.Add(1) + go func() error { + defer grp.Done() if err := p.HandleMinerChanges(ctx, actorChanges[builtin.StorageMinerActorCodeID]); err != nil { - return xerrors.Errorf("Failed to handle miner changes: %w", err) + log.Errorf("Failed to handle miner changes: %w", err) + return nil } log.Info("Processed Miner Changes") return nil - }) + }() - grp.Go(func() error { + grp.Add(1) + go func() error { + defer grp.Done() if err := p.HandleRewardChanges(ctx, actorChanges[builtin.RewardActorCodeID], nullRounds); err != nil { - return xerrors.Errorf("Failed to handle reward changes: %w", err) + log.Errorf("Failed to handle reward changes: %w", err) + return nil } log.Info("Processed Reward Changes") return nil - }) + }() - grp.Go(func() error { + grp.Add(1) + go func() error { + defer grp.Done() if err := p.HandlePowerChanges(ctx, actorChanges[builtin.StoragePowerActorCodeID]); err != nil { return xerrors.Errorf("Failed to handle power actor changes: %w", err) } log.Info("Processes Power Changes") return nil - }) + }() - grp.Go(func() error { + grp.Add(1) + go func() error { + defer grp.Done() if err := p.HandleMessageChanges(ctx, toProcess); err != nil { - return xerrors.Errorf("Failed to handle message changes: %w", err) + log.Errorf("Failed to handle message changes: %w", err) + return nil } log.Info("Processed Message Changes") return nil - }) + }() - grp.Go(func() error { + grp.Add(1) + go func() error { + defer grp.Done() if err := p.HandleCommonActorsChanges(ctx, actorChanges); err != nil { - return xerrors.Errorf("Failed to handle common actor changes: %w", err) + log.Errorf("Failed to handle common actor changes: %w", err) + return nil } log.Info("Processed CommonActor Changes") return nil - }) + }() - if err := grp.Wait(); err != nil { - log.Errorw("Failed to handle actor changes...retrying", "error", err) - continue - } + grp.Wait() if err := p.markBlocksProcessed(ctx, toProcess); err != nil { log.Fatalw("Failed to mark blocks as processed", "error", err) From 7e0ba4aa324623764743fbd76091505f4c877696 Mon Sep 17 00:00:00 2001 From: Mike Greenberg Date: Sun, 23 Aug 2020 13:01:10 -0400 Subject: [PATCH 053/247] fix(chainwatch): Reduce default max-batch to 50 --- cmd/lotus-chainwatch/run.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/lotus-chainwatch/run.go b/cmd/lotus-chainwatch/run.go index 3442ec714..8bdcfcfe3 100644 --- a/cmd/lotus-chainwatch/run.go +++ b/cmd/lotus-chainwatch/run.go @@ -24,7 +24,7 @@ var runCmd = &cli.Command{ Flags: []cli.Flag{ &cli.IntFlag{ Name: "max-batch", - Value: 1000, + Value: 50, }, }, Action: func(cctx *cli.Context) error { From 80f8f71a965d371f09c6262b0d10fb692a1bf8db Mon Sep 17 00:00:00 2001 From: Mike Greenberg Date: Sun, 23 Aug 2020 16:51:12 -0400 Subject: [PATCH 054/247] fix(lint): Cleanup unneeded error returns; go mod tidy --- cmd/lotus-chainwatch/processor/processor.go | 31 +++++++++------------ go.sum | 11 -------- 2 files changed, 13 insertions(+), 29 deletions(-) diff --git a/cmd/lotus-chainwatch/processor/processor.go b/cmd/lotus-chainwatch/processor/processor.go index f231099b6..9b12a2cf7 100644 --- a/cmd/lotus-chainwatch/processor/processor.go +++ b/cmd/lotus-chainwatch/processor/processor.go @@ -146,68 +146,63 @@ func (p *Processor) Start(ctx context.Context) { grp := sync.WaitGroup{} grp.Add(1) - go func() error { + go func() { defer grp.Done() if err := p.HandleMarketChanges(ctx, actorChanges[builtin.StorageMarketActorCodeID]); err != nil { log.Errorf("Failed to handle market changes: %w", err) - return nil + return } log.Info("Processed Market Changes") - return nil }() grp.Add(1) - go func() error { + go func() { defer grp.Done() if err := p.HandleMinerChanges(ctx, actorChanges[builtin.StorageMinerActorCodeID]); err != nil { log.Errorf("Failed to handle miner changes: %w", err) - return nil + return } log.Info("Processed Miner Changes") - return nil }() grp.Add(1) - go func() error { + go func() { defer grp.Done() if err := p.HandleRewardChanges(ctx, actorChanges[builtin.RewardActorCodeID], nullRounds); err != nil { log.Errorf("Failed to handle reward changes: %w", err) - return nil + return } log.Info("Processed Reward Changes") - return nil }() grp.Add(1) - go func() error { + go func() { defer grp.Done() if err := p.HandlePowerChanges(ctx, actorChanges[builtin.StoragePowerActorCodeID]); err != nil { - return xerrors.Errorf("Failed to handle power actor changes: %w", err) + log.Errorf("Failed to handle power actor changes: %w", err) + return } log.Info("Processes Power Changes") - return nil }() grp.Add(1) - go func() error { + go func() { defer grp.Done() if err := p.HandleMessageChanges(ctx, toProcess); err != nil { log.Errorf("Failed to handle message changes: %w", err) - return nil + return } log.Info("Processed Message Changes") - return nil }() grp.Add(1) - go func() error { + go func() { defer grp.Done() if err := p.HandleCommonActorsChanges(ctx, actorChanges); err != nil { log.Errorf("Failed to handle common actor changes: %w", err) - return nil + return } log.Info("Processed CommonActor Changes") - return nil }() grp.Wait() diff --git a/go.sum b/go.sum index 6d352d9c0..16b627ca5 100644 --- a/go.sum +++ b/go.sum @@ -230,8 +230,6 @@ github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20200731171407-e559a0579161 github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20200731171407-e559a0579161/go.mod h1:vgmwKBkx+ca5OIeEvstiQgzAZnb7R6QaqE1oEDSqa6g= github.com/filecoin-project/go-bitfield v0.0.0-20200416002808-b3ee67ec9060/go.mod h1:iodsLxOFZnqKtjj2zkgqzoGNrv6vUqj69AT/J8DKXEw= github.com/filecoin-project/go-bitfield v0.0.1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= -github.com/filecoin-project/go-bitfield v0.0.3/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= -github.com/filecoin-project/go-bitfield v0.0.4-0.20200703174658-f4a5758051a1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= github.com/filecoin-project/go-bitfield v0.1.2 h1:TjLregCoyP1/5lm7WCM0axyV1myIHwbjGa21skuu5tk= github.com/filecoin-project/go-bitfield v0.1.2/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= github.com/filecoin-project/go-bitfield v0.2.0 h1:gCtLcjskIPtdg4NfN7gQZSQF9yrBQ7mkT0qCJxzGI2Q= @@ -242,7 +240,6 @@ github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 h1:2pMX github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= github.com/filecoin-project/go-data-transfer v0.6.2 h1:IgbkwcHoyWGglzfsY7P9L1GapzoiLNKuzfZY2bxER8E= github.com/filecoin-project/go-data-transfer v0.6.2/go.mod h1:uRYBRKVBVM12CSusBtVrzDHkVw/3DKZpkxKJVP1Ydas= -github.com/filecoin-project/go-fil-commcid v0.0.0-20200208005934-2b8bd03caca5/go.mod h1:JbkIgFF/Z9BDlvrJO1FuKkaWsH673/UdFaiVS6uIHlA= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1:GxJzR3oRIMTPtpZ0b7QF8FKPK6/iPAc7trhlL5k/g+s= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= github.com/filecoin-project/go-fil-markets v0.5.7 h1:kzyMHqez8ssxchj5s9M1hkC3CTwRGh2MeglJGfUksQU= @@ -253,11 +250,9 @@ github.com/filecoin-project/go-multistore v0.0.3 h1:vaRBY4YiA2UZFPK57RNuewypB8u0 github.com/filecoin-project/go-multistore v0.0.3/go.mod h1:kaNqCC4IhU4B1uyr7YWFHd23TL4KM32aChS0jNkyUvQ= github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6 h1:92PET+sx1Hb4W/8CgFwGuxaKbttwY+UNspYZTvXY0vs= github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6/go.mod h1:0HgYnrkeSU4lu1p+LEOeDpFsNBssa0OGGriWdA4hvaE= -github.com/filecoin-project/go-paramfetch v0.0.1/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= github.com/filecoin-project/go-paramfetch v0.0.2-0.20200218225740-47c639bab663/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261 h1:A256QonvzRaknIIAuWhe/M2dpV2otzs3NBhi5TWa/UA= github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= -github.com/filecoin-project/go-statemachine v0.0.0-20200226041606-2074af6d51d9/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v0.0.0-20200714194326-a77c3ae20989/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370 h1:Jbburj7Ih2iaJ/o5Q9A+EAeTabME6YII7FLi9SKUf5c= github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= @@ -265,14 +260,12 @@ github.com/filecoin-project/go-statestore v0.1.0 h1:t56reH59843TwXHkMcwyuayStBIi github.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZOinUJB4WARkRfNl10O7kTnI= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b h1:fkRZSPrYpk42PV3/lIXiL0LHetxde7vyYYvSsttQtfg= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8= -github.com/filecoin-project/sector-storage v0.0.0-20200712023225-1d67dcfa3c15/go.mod h1:salgVdX7qeXFo/xaiEQE29J4pPkjn71T0kt0n+VDBzo= github.com/filecoin-project/sector-storage v0.0.0-20200730050024-3ee28c3b6d9a/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0 h1:E1fZ27fhKK05bhZItfTwqr1i05vXnEZJznQFEYwEEUU= github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= github.com/filecoin-project/specs-actors v0.0.0-20200210130641-2d1fbd8672cf/go.mod h1:xtDZUB6pe4Pksa/bAJbJ693OilaC5Wbot9jMhLm3cZA= github.com/filecoin-project/specs-actors v0.3.0/go.mod h1:nQYnFbQ7Y0bHZyq6HDEuVlCPR+U3z5Q3wMOQ+2aiV+Y= github.com/filecoin-project/specs-actors v0.6.1/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY= -github.com/filecoin-project/specs-actors v0.7.3-0.20200716231407-60a2ae96d2e6/go.mod h1:JOMUa7EijvpOO4ofD1yeHNmqohkmmnhTvz/IpB6so4c= github.com/filecoin-project/specs-actors v0.8.2/go.mod h1:Q3ACV5kBLvqPaYbthc/J1lGMJ5OwogmD9pzdtPRMdCw= github.com/filecoin-project/specs-actors v0.8.7-0.20200811203034-272d022c1923 h1:+H4IG4OjTThljPkMH1ZpynxCulNdx4amEeHoP2GdQJI= github.com/filecoin-project/specs-actors v0.8.7-0.20200811203034-272d022c1923/go.mod h1:hukRu6vKQrrS7Nt+fC/ql4PqWLSfmAWNshD/VDtARZU= @@ -535,7 +528,6 @@ github.com/ipfs/go-graphsync v0.1.0/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CE github.com/ipfs/go-graphsync v0.1.1 h1:bFDAYS0Z48yd8ROPI6f/zIVmJxaDLA6m8cVuJPKC5fE= github.com/ipfs/go-graphsync v0.1.1/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= github.com/ipfs/go-hamt-ipld v0.0.15-0.20200131012125-dd88a59d3f2e/go.mod h1:9aQJu/i/TaRDW6jqB5U217dLIDopn50wxLdHXM2CTfE= -github.com/ipfs/go-hamt-ipld v0.0.15-0.20200204200533-99b8553ef242/go.mod h1:kq3Pi+UP3oHhAdKexE+kHHYRKMoFNuGero0R7q3hWGg= github.com/ipfs/go-hamt-ipld v0.1.1 h1:0IQdvwnAAUKmDE+PMJa5y1QiwOPHpI9+eAbQEEEYthk= github.com/ipfs/go-hamt-ipld v0.1.1/go.mod h1:1EZCr2v0jlCnhpa+aZ0JZYp8Tt2w16+JJOAVz17YcDk= github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= @@ -1510,7 +1502,6 @@ golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1667,7 +1658,6 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1729,7 +1719,6 @@ golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200108195415-316d2f248479/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= From 119f6ff2e66225eb19d39ad518df35d946a3e0f4 Mon Sep 17 00:00:00 2001 From: WC <34792731+GFZRZK@users.noreply.github.com> Date: Mon, 24 Aug 2020 14:56:44 +0800 Subject: [PATCH 055/247] Bugfix: fix some typo and correct recoveries datasource Bugfix: fix some typo and correct recoveries data source --- cmd/lotus-storage-miner/proving.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/lotus-storage-miner/proving.go b/cmd/lotus-storage-miner/proving.go index 85379a748..502edb57b 100644 --- a/cmd/lotus-storage-miner/proving.go +++ b/cmd/lotus-storage-miner/proving.go @@ -183,13 +183,13 @@ var provingInfoCmd = &cli.Command{ fc, err := partition.Faults.Count() if err != nil { - return xerrors.Errorf("count partition sectors: %w", err) + return xerrors.Errorf("count partition faults: %w", err) } faults += fc - rc, err := partition.Faults.Count() + rc, err := partition.Recoveries.Count() if err != nil { - return xerrors.Errorf("count partition sectors: %w", err) + return xerrors.Errorf("count partition recoveries: %w", err) } recovering += rc } From db4896577c253f8fe01f0430c145ec6746df153d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Mon, 24 Aug 2020 12:11:18 +0200 Subject: [PATCH 056/247] docgen: Add missing examples --- api/docgen/docgen.go | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/api/docgen/docgen.go b/api/docgen/docgen.go index f9e614677..5c74ef23b 100644 --- a/api/docgen/docgen.go +++ b/api/docgen/docgen.go @@ -12,22 +12,29 @@ import ( "time" "unicode" + "github.com/ipfs/go-cid" + "github.com/ipfs/go-filestore" + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + pubsub "github.com/libp2p/go-libp2p-pubsub" + "github.com/multiformats/go-multiaddr" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-bitfield" + datatransfer "github.com/filecoin-project/go-data-transfer" + "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/go-jsonrpc/auth" + "github.com/filecoin-project/go-multistore" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/apistruct" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/modules/dtypes" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" - "github.com/ipfs/go-cid" - "github.com/ipfs/go-filestore" - "github.com/libp2p/go-libp2p-core/network" - "github.com/libp2p/go-libp2p-core/peer" - "github.com/multiformats/go-multiaddr" ) var ExampleValues = map[reflect.Type]interface{}{ @@ -71,6 +78,7 @@ func init() { panic(err) } addExample(pid) + addExample(&pid) addExample(bitfield.NewFromSet([]uint64{5})) addExample(abi.RegisteredSealProof_StackedDrg32GiBV1) @@ -98,6 +106,12 @@ func init() { addExample(build.APIVersion) addExample(api.PCHInbound) addExample(time.Minute) + addExample(datatransfer.TransferID(3)) + addExample(datatransfer.Ongoing) + addExample(multistore.StoreID(50)) + addExample(retrievalmarket.ClientEventDealAccepted) + addExample(retrievalmarket.DealStatusNew) + addExample(network.ReachabilityPublic) addExample(&types.ExecutionTrace{ Msg: exampleValue(reflect.TypeOf(&types.Message{}), nil).(*types.Message), MsgRct: exampleValue(reflect.TypeOf(&types.MessageReceipt{}), nil).(*types.MessageReceipt), @@ -111,6 +125,14 @@ func init() { addExample(map[string]api.MarketBalance{ "t026363": exampleValue(reflect.TypeOf(api.MarketBalance{}), nil).(api.MarketBalance), }) + addExample(map[string]*pubsub.TopicScoreSnapshot{ + "/blocks": { + TimeInMesh: time.Minute, + FirstMessageDeliveries: 122, + MeshMessageDeliveries: 1234, + InvalidMessageDeliveries: 3, + }, + }) maddr, err := multiaddr.NewMultiaddr("/ip4/52.36.61.156/tcp/1347/p2p/12D3KooWFETiESTf1v4PGUvtnxMAcEFMzLZbJGg4tjWfGEimYior") if err != nil { From b5f4a91002f698c12ccc595a279262f8395e49c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Mon, 24 Aug 2020 12:20:23 +0200 Subject: [PATCH 057/247] Check docsgen in CI --- .circleci/config.yml | 22 ++++++++++++++++++++++ Makefile | 3 +++ documentation/en/api-functions.md | 1 + 3 files changed, 26 insertions(+) create mode 100644 documentation/en/api-functions.md diff --git a/.circleci/config.yml b/.circleci/config.yml index 0b2329954..8ee3bca33 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -252,6 +252,26 @@ jobs: - run: command: "! go fmt ./... 2>&1 | read" + cbor-gen-check: + executor: golang + steps: + - install-deps + - prepare + - run: go install golang.org/x/tools/cmd/goimports + - run: go install github.com/hannahhoward/cbor-gen-for + - run: go generate ./... + - run: git --no-pager diff + - run: git --no-pager diff --quiet + + docs-check: + executor: golang + steps: + - install-deps + - prepare + - run: make docsgen + - run: git --no-pager diff + - run: git --no-pager diff --quiet + lint: &lint description: | Run golangci-lint. @@ -319,6 +339,8 @@ workflows: - lint-all - mod-tidy-check - gofmt + - cbor-gen-check + - docs-check - test: codecov-upload: true test-suite-name: full diff --git a/Makefile b/Makefile index e8c3a2220..31140589a 100644 --- a/Makefile +++ b/Makefile @@ -279,5 +279,8 @@ method-gen: gen: type-gen method-gen +docsgen: + go run ./api/docgen > documentation/en/api-functions.md + print-%: @echo $*=$($*) diff --git a/documentation/en/api-functions.md b/documentation/en/api-functions.md new file mode 100644 index 000000000..1dc6372f7 --- /dev/null +++ b/documentation/en/api-functions.md @@ -0,0 +1 @@ +# docs \ No newline at end of file From ce8b36941914b6114d6e88be20774b1ccff63a4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Mon, 24 Aug 2020 12:25:49 +0200 Subject: [PATCH 058/247] docs: Generate API docs --- documentation/en/api-functions.md | 4175 ++++++++++++++++++++++++++++- 1 file changed, 4174 insertions(+), 1 deletion(-) diff --git a/documentation/en/api-functions.md b/documentation/en/api-functions.md index 1dc6372f7..89eb2b944 100644 --- a/documentation/en/api-functions.md +++ b/documentation/en/api-functions.md @@ -1 +1,4174 @@ -# docs \ No newline at end of file +# Groups +* [](#) + * [Closing](#Closing) + * [Shutdown](#Shutdown) + * [Version](#Version) +* [Auth](#Auth) + * [AuthNew](#AuthNew) + * [AuthVerify](#AuthVerify) +* [Beacon](#Beacon) + * [BeaconGetEntry](#BeaconGetEntry) +* [Chain](#Chain) + * [ChainExport](#ChainExport) + * [ChainGetBlock](#ChainGetBlock) + * [ChainGetBlockMessages](#ChainGetBlockMessages) + * [ChainGetGenesis](#ChainGetGenesis) + * [ChainGetMessage](#ChainGetMessage) + * [ChainGetNode](#ChainGetNode) + * [ChainGetParentMessages](#ChainGetParentMessages) + * [ChainGetParentReceipts](#ChainGetParentReceipts) + * [ChainGetPath](#ChainGetPath) + * [ChainGetRandomnessFromBeacon](#ChainGetRandomnessFromBeacon) + * [ChainGetRandomnessFromTickets](#ChainGetRandomnessFromTickets) + * [ChainGetTipSet](#ChainGetTipSet) + * [ChainGetTipSetByHeight](#ChainGetTipSetByHeight) + * [ChainHasObj](#ChainHasObj) + * [ChainHead](#ChainHead) + * [ChainNotify](#ChainNotify) + * [ChainReadObj](#ChainReadObj) + * [ChainSetHead](#ChainSetHead) + * [ChainStatObj](#ChainStatObj) + * [ChainTipSetWeight](#ChainTipSetWeight) +* [Client](#Client) + * [ClientCalcCommP](#ClientCalcCommP) + * [ClientDataTransferUpdates](#ClientDataTransferUpdates) + * [ClientDealSize](#ClientDealSize) + * [ClientFindData](#ClientFindData) + * [ClientGenCar](#ClientGenCar) + * [ClientGetDealInfo](#ClientGetDealInfo) + * [ClientHasLocal](#ClientHasLocal) + * [ClientImport](#ClientImport) + * [ClientListDataTransfers](#ClientListDataTransfers) + * [ClientListDeals](#ClientListDeals) + * [ClientListImports](#ClientListImports) + * [ClientMinerQueryOffer](#ClientMinerQueryOffer) + * [ClientQueryAsk](#ClientQueryAsk) + * [ClientRemoveImport](#ClientRemoveImport) + * [ClientRetrieve](#ClientRetrieve) + * [ClientRetrieveWithEvents](#ClientRetrieveWithEvents) + * [ClientStartDeal](#ClientStartDeal) +* [Gas](#Gas) + * [GasEstimateFeeCap](#GasEstimateFeeCap) + * [GasEstimateGasLimit](#GasEstimateGasLimit) + * [GasEstimateGasPremium](#GasEstimateGasPremium) + * [GasEstimateMessageGas](#GasEstimateMessageGas) +* [I](#I) + * [ID](#ID) +* [Log](#Log) + * [LogList](#LogList) + * [LogSetLevel](#LogSetLevel) +* [Market](#Market) + * [MarketEnsureAvailable](#MarketEnsureAvailable) +* [Miner](#Miner) + * [MinerCreateBlock](#MinerCreateBlock) + * [MinerGetBaseInfo](#MinerGetBaseInfo) +* [Mpool](#Mpool) + * [MpoolClear](#MpoolClear) + * [MpoolGetConfig](#MpoolGetConfig) + * [MpoolGetNonce](#MpoolGetNonce) + * [MpoolPending](#MpoolPending) + * [MpoolPush](#MpoolPush) + * [MpoolPushMessage](#MpoolPushMessage) + * [MpoolSelect](#MpoolSelect) + * [MpoolSetConfig](#MpoolSetConfig) + * [MpoolSub](#MpoolSub) +* [Msig](#Msig) + * [MsigApprove](#MsigApprove) + * [MsigCancel](#MsigCancel) + * [MsigCreate](#MsigCreate) + * [MsigGetAvailableBalance](#MsigGetAvailableBalance) + * [MsigPropose](#MsigPropose) + * [MsigSwapApprove](#MsigSwapApprove) + * [MsigSwapCancel](#MsigSwapCancel) + * [MsigSwapPropose](#MsigSwapPropose) +* [Net](#Net) + * [NetAddrsListen](#NetAddrsListen) + * [NetAutoNatStatus](#NetAutoNatStatus) + * [NetConnect](#NetConnect) + * [NetConnectedness](#NetConnectedness) + * [NetDisconnect](#NetDisconnect) + * [NetFindPeer](#NetFindPeer) + * [NetPeers](#NetPeers) + * [NetPubsubScores](#NetPubsubScores) +* [Paych](#Paych) + * [PaychAllocateLane](#PaychAllocateLane) + * [PaychCollect](#PaychCollect) + * [PaychGet](#PaychGet) + * [PaychGetWaitReady](#PaychGetWaitReady) + * [PaychList](#PaychList) + * [PaychNewPayment](#PaychNewPayment) + * [PaychSettle](#PaychSettle) + * [PaychStatus](#PaychStatus) + * [PaychVoucherAdd](#PaychVoucherAdd) + * [PaychVoucherCheckSpendable](#PaychVoucherCheckSpendable) + * [PaychVoucherCheckValid](#PaychVoucherCheckValid) + * [PaychVoucherCreate](#PaychVoucherCreate) + * [PaychVoucherList](#PaychVoucherList) + * [PaychVoucherSubmit](#PaychVoucherSubmit) +* [State](#State) + * [StateAccountKey](#StateAccountKey) + * [StateAllMinerFaults](#StateAllMinerFaults) + * [StateCall](#StateCall) + * [StateChangedActors](#StateChangedActors) + * [StateCirculatingSupply](#StateCirculatingSupply) + * [StateCompute](#StateCompute) + * [StateDealProviderCollateralBounds](#StateDealProviderCollateralBounds) + * [StateGetActor](#StateGetActor) + * [StateGetReceipt](#StateGetReceipt) + * [StateListActors](#StateListActors) + * [StateListMessages](#StateListMessages) + * [StateListMiners](#StateListMiners) + * [StateLookupID](#StateLookupID) + * [StateMarketBalance](#StateMarketBalance) + * [StateMarketDeals](#StateMarketDeals) + * [StateMarketParticipants](#StateMarketParticipants) + * [StateMarketStorageDeal](#StateMarketStorageDeal) + * [StateMinerActiveSectors](#StateMinerActiveSectors) + * [StateMinerAvailableBalance](#StateMinerAvailableBalance) + * [StateMinerDeadlines](#StateMinerDeadlines) + * [StateMinerFaults](#StateMinerFaults) + * [StateMinerInfo](#StateMinerInfo) + * [StateMinerInitialPledgeCollateral](#StateMinerInitialPledgeCollateral) + * [StateMinerPartitions](#StateMinerPartitions) + * [StateMinerPower](#StateMinerPower) + * [StateMinerPreCommitDepositForPower](#StateMinerPreCommitDepositForPower) + * [StateMinerProvingDeadline](#StateMinerProvingDeadline) + * [StateMinerRecoveries](#StateMinerRecoveries) + * [StateMinerSectorCount](#StateMinerSectorCount) + * [StateMinerSectors](#StateMinerSectors) + * [StateNetworkName](#StateNetworkName) + * [StateReadState](#StateReadState) + * [StateReplay](#StateReplay) + * [StateSearchMsg](#StateSearchMsg) + * [StateSectorExpiration](#StateSectorExpiration) + * [StateSectorGetInfo](#StateSectorGetInfo) + * [StateSectorPartition](#StateSectorPartition) + * [StateSectorPreCommitInfo](#StateSectorPreCommitInfo) + * [StateVerifiedClientStatus](#StateVerifiedClientStatus) + * [StateWaitMsg](#StateWaitMsg) +* [Sync](#Sync) + * [SyncCheckBad](#SyncCheckBad) + * [SyncIncomingBlocks](#SyncIncomingBlocks) + * [SyncMarkBad](#SyncMarkBad) + * [SyncState](#SyncState) + * [SyncSubmitBlock](#SyncSubmitBlock) +* [Wallet](#Wallet) + * [WalletBalance](#WalletBalance) + * [WalletDefaultAddress](#WalletDefaultAddress) + * [WalletDelete](#WalletDelete) + * [WalletExport](#WalletExport) + * [WalletHas](#WalletHas) + * [WalletImport](#WalletImport) + * [WalletList](#WalletList) + * [WalletNew](#WalletNew) + * [WalletSetDefault](#WalletSetDefault) + * [WalletSign](#WalletSign) + * [WalletSignMessage](#WalletSignMessage) + * [WalletVerify](#WalletVerify) +## + + +### Closing + + +Perms: read + +Inputs: `null` + +Response: `{}` + +### Shutdown + + +Perms: admin + +Inputs: `null` + +Response: `{}` + +### Version + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "Version": "string value", + "APIVersion": 2816, + "BlockDelay": 42 +} +``` + +## Auth + + +### AuthNew + + +Perms: admin + +Inputs: +```json +[ + null +] +``` + +Response: `"Ynl0ZSBhcnJheQ=="` + +### AuthVerify + + +Perms: read + +Inputs: +```json +[ + "string value" +] +``` + +Response: `null` + +## Beacon +The Beacon method group contains methods for interacting with the random beacon (DRAND) + + +### BeaconGetEntry +BeaconGetEntry returns the beacon entry for the given filecoin epoch. If +the entry has not yet been produced, the call will block until the entry +becomes available + + +Perms: read + +Inputs: +```json +[ + 10101 +] +``` + +Response: +```json +{ + "Round": 42, + "Data": "Ynl0ZSBhcnJheQ==" +} +``` + +## Chain +The Chain method group contains methods for interacting with the +blockchain, but that do not require any form of state computation. + + +### ChainExport +ChainExport returns a stream of bytes with CAR dump of chain data. + + +Perms: read + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `"Ynl0ZSBhcnJheQ=="` + +### ChainGetBlock +ChainGetBlock returns the block specified by the given CID. + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: +```json +{ + "Miner": "t01234", + "Ticket": { + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "ElectionProof": { + "WinCount": 9, + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "BeaconEntries": null, + "WinPoStProof": null, + "Parents": null, + "ParentWeight": "0", + "Height": 10101, + "ParentStateRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "ParentMessageReceipts": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Messages": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "BLSAggregate": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Timestamp": 42, + "BlockSig": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "ForkSignaling": 42, + "ParentBaseFee": "0" +} +``` + +### ChainGetBlockMessages +ChainGetBlockMessages returns messages stored in the specified block. + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: +```json +{ + "BlsMessages": null, + "SecpkMessages": null, + "Cids": null +} +``` + +### ChainGetGenesis +ChainGetGenesis returns the genesis tipset. + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "Cids": null, + "Blocks": null, + "Height": 0 +} +``` + +### ChainGetMessage +ChainGetMessage reads a message referenced by the specified CID from the +chain blockstore. + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: +```json +{ + "Version": 42, + "To": "t01234", + "From": "t01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==" +} +``` + +### ChainGetNode +There are not yet any comments for this method. + +Perms: read + +Inputs: +```json +[ + "string value" +] +``` + +Response: +```json +{ + "Cid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Obj": {} +} +``` + +### ChainGetParentMessages +ChainGetParentMessages returns messages stored in parent tipset of the +specified block. + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: `null` + +### ChainGetParentReceipts +ChainGetParentReceipts returns receipts for messages in parent tipset of +the specified block. + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: `null` + +### ChainGetPath +ChainGetPath returns a set of revert/apply operations needed to get from +one tipset to another, for example: +``` + to + ^ +from tAA + ^ ^ +tBA tAB + ^---*--^ + ^ + tRR +``` +Would return `[revert(tBA), apply(tAB), apply(tAA)]` + + +Perms: read + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ], + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `null` + +### ChainGetRandomnessFromBeacon +ChainGetRandomnessFromBeacon is used to sample the beacon for randomness. + + +Perms: read + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ], + 2, + 10101, + "Ynl0ZSBhcnJheQ==" +] +``` + +Response: `null` + +### ChainGetRandomnessFromTickets +ChainGetRandomnessFromTickets is used to sample the chain for randomness. + + +Perms: read + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ], + 2, + 10101, + "Ynl0ZSBhcnJheQ==" +] +``` + +Response: `null` + +### ChainGetTipSet +ChainGetTipSet returns the tipset specified by the given TipSetKey. + + +Perms: read + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "Cids": null, + "Blocks": null, + "Height": 0 +} +``` + +### ChainGetTipSetByHeight +ChainGetTipSetByHeight looks back for a tipset at the specified epoch. +If there are no blocks at the specified epoch, a tipset at an earlier epoch +will be returned. + + +Perms: read + +Inputs: +```json +[ + 10101, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "Cids": null, + "Blocks": null, + "Height": 0 +} +``` + +### ChainHasObj +ChainHasObj checks if a given CID exists in the chain blockstore. + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: `true` + +### ChainHead +ChainHead returns the current head of the chain. + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "Cids": null, + "Blocks": null, + "Height": 0 +} +``` + +### ChainNotify +ChainNotify returns channel with chain head updates. +First message is guaranteed to be of len == 1, and type == 'current'. + + +Perms: read + +Inputs: `null` + +Response: `null` + +### ChainReadObj +ChainReadObj reads ipld nodes referenced by the specified CID from chain +blockstore and returns raw bytes. + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: `"Ynl0ZSBhcnJheQ=="` + +### ChainSetHead +ChainSetHead forcefully sets current chain head. Use with caution. + + +Perms: admin + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `{}` + +### ChainStatObj +ChainStatObj returns statistics about the graph referenced by 'obj'. +If 'base' is also specified, then the returned stat will be a diff +between the two objects. + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: +```json +{ + "Size": 42, + "Links": 42 +} +``` + +### ChainTipSetWeight +ChainTipSetWeight computes weight for the specified tipset. + + +Perms: read + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `"0"` + +## Client +The Client methods all have to do with interacting with the storage and +retrieval markets as a client + + +### ClientCalcCommP +ClientCalcCommP calculates the CommP for a specified file + + +Perms: read + +Inputs: +```json +[ + "string value" +] +``` + +Response: +```json +{ + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Size": 1024 +} +``` + +### ClientDataTransferUpdates +There are not yet any comments for this method. + +Perms: write + +Inputs: `null` + +Response: +```json +{ + "TransferID": 3, + "Status": 1, + "BaseCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "IsInitiator": true, + "IsSender": true, + "Voucher": "string value", + "Message": "string value", + "OtherPeer": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Transferred": 42 +} +``` + +### ClientDealSize +ClientDealSize calculates real deal data size + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: +```json +{ + "PayloadSize": 9, + "PieceSize": 1032 +} +``` + +### ClientFindData +ClientFindData identifies peers that have a certain file, and returns QueryOffers (one per peer). + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + null +] +``` + +Response: `null` + +### ClientGenCar +ClientGenCar generates a CAR file for the specified file. + + +Perms: write + +Inputs: +```json +[ + { + "Path": "string value", + "IsCAR": true + }, + "string value" +] +``` + +Response: `{}` + +### ClientGetDealInfo +ClientGetDealInfo returns the latest information about a given deal. + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: +```json +{ + "ProposalCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "State": 42, + "Message": "string value", + "Provider": "t01234", + "DataRef": { + "TransferType": "string value", + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceCid": null, + "PieceSize": 1024 + }, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Size": 42, + "PricePerEpoch": "0", + "Duration": 42, + "DealID": 5432, + "CreationTime": "0001-01-01T00:00:00Z" +} +``` + +### ClientHasLocal +ClientHasLocal indicates whether a certain CID is locally stored. + + +Perms: write + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: `true` + +### ClientImport +ClientImport imports file under the specified path into filestore. + + +Perms: admin + +Inputs: +```json +[ + { + "Path": "string value", + "IsCAR": true + } +] +``` + +Response: +```json +{ + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "ImportID": 50 +} +``` + +### ClientListDataTransfers +ClientListTransfers returns the status of all ongoing transfers of data + + +Perms: write + +Inputs: `null` + +Response: `null` + +### ClientListDeals +ClientListDeals returns information about the deals made by the local client. + + +Perms: write + +Inputs: `null` + +Response: `null` + +### ClientListImports +ClientListImports lists imported files and their root CIDs + + +Perms: write + +Inputs: `null` + +Response: `null` + +### ClientMinerQueryOffer +ClientMinerQueryOffer returns a QueryOffer for the specific miner and file. + + +Perms: read + +Inputs: +```json +[ + "t01234", + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + null +] +``` + +Response: +```json +{ + "Err": "string value", + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Piece": null, + "Size": 42, + "MinPrice": "0", + "UnsealPrice": "0", + "PaymentInterval": 42, + "PaymentIntervalIncrease": 42, + "Miner": "t01234", + "MinerPeer": { + "Address": "t01234", + "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "PieceCID": null + } +} +``` + +### ClientQueryAsk +ClientQueryAsk returns a signed StorageAsk from the specified miner. + + +Perms: read + +Inputs: +```json +[ + "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "t01234" +] +``` + +Response: +```json +{ + "Ask": { + "Price": "0", + "VerifiedPrice": "0", + "MinPieceSize": 1032, + "MaxPieceSize": 1032, + "Miner": "t01234", + "Timestamp": 10101, + "Expiry": 10101, + "SeqNo": 42 + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } +} +``` + +### ClientRemoveImport +ClientRemoveImport removes file import + + +Perms: admin + +Inputs: +```json +[ + 50 +] +``` + +Response: `{}` + +### ClientRetrieve +ClientRetrieve initiates the retrieval of a file, as specified in the order. + + +Perms: admin + +Inputs: +```json +[ + { + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Piece": null, + "Size": 42, + "Total": "0", + "UnsealPrice": "0", + "PaymentInterval": 42, + "PaymentIntervalIncrease": 42, + "Client": "t01234", + "Miner": "t01234", + "MinerPeer": { + "Address": "t01234", + "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "PieceCID": null + } + }, + { + "Path": "string value", + "IsCAR": true + } +] +``` + +Response: `{}` + +### ClientRetrieveWithEvents +ClientRetrieveWithEvents initiates the retrieval of a file, as specified in the order, and provides a channel +of status updates. + + +Perms: admin + +Inputs: +```json +[ + { + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Piece": null, + "Size": 42, + "Total": "0", + "UnsealPrice": "0", + "PaymentInterval": 42, + "PaymentIntervalIncrease": 42, + "Client": "t01234", + "Miner": "t01234", + "MinerPeer": { + "Address": "t01234", + "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "PieceCID": null + } + }, + { + "Path": "string value", + "IsCAR": true + } +] +``` + +Response: +```json +{ + "Event": 5, + "Status": 0, + "BytesReceived": 42, + "FundsSpent": "0", + "Err": "string value" +} +``` + +### ClientStartDeal +ClientStartDeal proposes a deal with a miner. + + +Perms: admin + +Inputs: +```json +[ + { + "Data": { + "TransferType": "string value", + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceCid": null, + "PieceSize": 1024 + }, + "Wallet": "t01234", + "Miner": "t01234", + "EpochPrice": "0", + "MinBlocksDuration": 42, + "ProviderCollateral": "0", + "DealStartEpoch": 10101, + "FastRetrieval": true, + "VerifiedDeal": true + } +] +``` + +Response: `null` + +## Gas + + +### GasEstimateFeeCap +GasEstimateFeeCap estimates gas fee cap + + +Perms: read + +Inputs: +```json +[ + { + "Version": 42, + "To": "t01234", + "From": "t01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==" + }, + 9, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `"0"` + +### GasEstimateGasLimit +GasEstimateGasLimit estimates gas used by the message and returns it. +It fails if message fails to execute. + + +Perms: read + +Inputs: +```json +[ + { + "Version": 42, + "To": "t01234", + "From": "t01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==" + }, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `9` + +### GasEstimateGasPremium +GasEstimateGasPremium estimates what gas price should be used for a +message to have high likelihood of inclusion in `nblocksincl` epochs. + + +Perms: read + +Inputs: +```json +[ + 42, + "t01234", + 9, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `"0"` + +### GasEstimateMessageGas +GasEstimateMessageGas estimates gas values for unset message gas fields + + +Perms: read + +Inputs: +```json +[ + { + "Version": 42, + "To": "t01234", + "From": "t01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==" + }, + { + "MaxFee": "0" + }, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "Version": 42, + "To": "t01234", + "From": "t01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==" +} +``` + +## I + + +### ID + + +Perms: read + +Inputs: `null` + +Response: `"12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf"` + +## Log + + +### LogList + + +Perms: write + +Inputs: `null` + +Response: `null` + +### LogSetLevel + + +Perms: write + +Inputs: +```json +[ + "string value", + "string value" +] +``` + +Response: `{}` + +## Market + + +### MarketEnsureAvailable +MarketFreeBalance + + +Perms: sign + +Inputs: +```json +[ + "t01234", + "t01234", + "0" +] +``` + +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` + +## Miner + + +### MinerCreateBlock +There are not yet any comments for this method. + +Perms: write + +Inputs: +```json +[ + { + "Miner": "t01234", + "Parents": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ], + "Ticket": { + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "Eproof": { + "WinCount": 9, + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "BeaconValues": null, + "Messages": null, + "Epoch": 10101, + "Timestamp": 42, + "WinningPoStProof": null + } +] +``` + +Response: +```json +{ + "Header": { + "Miner": "t01234", + "Ticket": { + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "ElectionProof": { + "WinCount": 9, + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "BeaconEntries": null, + "WinPoStProof": null, + "Parents": null, + "ParentWeight": "0", + "Height": 10101, + "ParentStateRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "ParentMessageReceipts": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Messages": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "BLSAggregate": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Timestamp": 42, + "BlockSig": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "ForkSignaling": 42, + "ParentBaseFee": "0" + }, + "BlsMessages": null, + "SecpkMessages": null +} +``` + +### MinerGetBaseInfo +There are not yet any comments for this method. + +Perms: read + +Inputs: +```json +[ + "t01234", + 10101, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "MinerPower": "0", + "NetworkPower": "0", + "Sectors": null, + "WorkerKey": "t01234", + "SectorSize": 34359738368, + "PrevBeaconEntry": { + "Round": 42, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "BeaconEntries": null, + "HasMinPower": true +} +``` + +## Mpool +The Mpool methods are for interacting with the message pool. The message pool +manages all incoming and outgoing 'messages' going over the network. + + +### MpoolClear +MpoolClear clears pending messages from the mpool + + +Perms: write + +Inputs: +```json +[ + true +] +``` + +Response: `{}` + +### MpoolGetConfig +MpoolGetConfig returns (a copy of) the current mpool config + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "PriorityAddrs": null, + "SizeLimitHigh": 123, + "SizeLimitLow": 123, + "ReplaceByFeeRatio": 12.3, + "PruneCooldown": 60000000000, + "GasLimitOverestimation": 12.3 +} +``` + +### MpoolGetNonce +MpoolGetNonce gets next nonce for the specified sender. +Note that this method may not be atomic. Use MpoolPushMessage instead. + + +Perms: read + +Inputs: +```json +[ + "t01234" +] +``` + +Response: `42` + +### MpoolPending +MpoolPending returns pending mempool messages. + + +Perms: read + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `null` + +### MpoolPush +MpoolPush pushes a signed message to mempool. + + +Perms: write + +Inputs: +```json +[ + { + "Message": { + "Version": 42, + "To": "t01234", + "From": "t01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==" + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } + } +] +``` + +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` + +### MpoolPushMessage +MpoolPushMessage atomically assigns a nonce, signs, and pushes a message +to mempool. +maxFee is only used when GasFeeCap/GasPremium fields aren't specified + +When maxFee is set to 0, MpoolPushMessage will guess appropriate fee +based on current chain conditions + + +Perms: sign + +Inputs: +```json +[ + { + "Version": 42, + "To": "t01234", + "From": "t01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==" + }, + { + "MaxFee": "0" + } +] +``` + +Response: +```json +{ + "Message": { + "Version": 42, + "To": "t01234", + "From": "t01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==" + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } +} +``` + +### MpoolSelect +MpoolSelect returns a list of pending messages for inclusion in the next block + + +Perms: read + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ], + 12.3 +] +``` + +Response: `null` + +### MpoolSetConfig +MpoolSetConfig sets the mpool config to (a copy of) the supplied config + + +Perms: write + +Inputs: +```json +[ + { + "PriorityAddrs": null, + "SizeLimitHigh": 123, + "SizeLimitLow": 123, + "ReplaceByFeeRatio": 12.3, + "PruneCooldown": 60000000000, + "GasLimitOverestimation": 12.3 + } +] +``` + +Response: `{}` + +### MpoolSub +There are not yet any comments for this method. + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "Type": 0, + "Message": { + "Message": { + "Version": 42, + "To": "t01234", + "From": "t01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==" + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } + } +} +``` + +## Msig +The Msig methods are used to interact with multisig wallets on the +filecoin network + + +### MsigApprove +MsigApprove approves a previously-proposed multisig message +It takes the following params: , , , , , +, , + + +Perms: sign + +Inputs: +```json +[ + "t01234", + 42, + "t01234", + "t01234", + "0", + "t01234", + 42, + "Ynl0ZSBhcnJheQ==" +] +``` + +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` + +### MsigCancel +MsigCancel cancels a previously-proposed multisig message +It takes the following params: , , , , +, , + + +Perms: sign + +Inputs: +```json +[ + "t01234", + 42, + "t01234", + "0", + "t01234", + 42, + "Ynl0ZSBhcnJheQ==" +] +``` + +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` + +### MsigCreate +MsigCreate creates a multisig wallet +It takes the following params: , , +, , + + +Perms: sign + +Inputs: +```json +[ + 42, + null, + 10101, + "0", + "t01234", + "0" +] +``` + +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` + +### MsigGetAvailableBalance +MsigGetAvailableBalance returns the portion of a multisig's balance that can be withdrawn or spent + + +Perms: read + +Inputs: +```json +[ + "t01234", + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `"0"` + +### MsigPropose +MsigPropose proposes a multisig message +It takes the following params: , , , +, , + + +Perms: sign + +Inputs: +```json +[ + "t01234", + "t01234", + "0", + "t01234", + 42, + "Ynl0ZSBhcnJheQ==" +] +``` + +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` + +### MsigSwapApprove +MsigSwapApprove approves a previously proposed SwapSigner +It takes the following params: , , , +, + + +Perms: sign + +Inputs: +```json +[ + "t01234", + "t01234", + 42, + "t01234", + "t01234", + "t01234" +] +``` + +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` + +### MsigSwapCancel +MsigSwapCancel cancels a previously proposed SwapSigner message +It takes the following params: , , , + + + +Perms: sign + +Inputs: +```json +[ + "t01234", + "t01234", + 42, + "t01234", + "t01234" +] +``` + +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` + +### MsigSwapPropose +MsigSwapPropose proposes swapping 2 signers in the multisig +It takes the following params: , , + + + +Perms: sign + +Inputs: +```json +[ + "t01234", + "t01234", + "t01234", + "t01234" +] +``` + +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` + +## Net + + +### NetAddrsListen + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "Addrs": null, + "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf" +} +``` + +### NetAutoNatStatus + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "Reachability": 1, + "PublicAddr": "string value" +} +``` + +### NetConnect + + +Perms: write + +Inputs: +```json +[ + { + "Addrs": null, + "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf" + } +] +``` + +Response: `{}` + +### NetConnectedness + + +Perms: read + +Inputs: +```json +[ + "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf" +] +``` + +Response: `1` + +### NetDisconnect + + +Perms: write + +Inputs: +```json +[ + "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf" +] +``` + +Response: `{}` + +### NetFindPeer + + +Perms: read + +Inputs: +```json +[ + "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf" +] +``` + +Response: +```json +{ + "Addrs": null, + "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf" +} +``` + +### NetPeers + + +Perms: read + +Inputs: `null` + +Response: `null` + +### NetPubsubScores + + +Perms: read + +Inputs: `null` + +Response: `null` + +## Paych +The Paych methods are for interacting with and managing payment channels + + +### PaychAllocateLane +There are not yet any comments for this method. + +Perms: sign + +Inputs: +```json +[ + "t01234" +] +``` + +Response: `42` + +### PaychCollect +There are not yet any comments for this method. + +Perms: sign + +Inputs: +```json +[ + "t01234" +] +``` + +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` + +### PaychGet +There are not yet any comments for this method. + +Perms: sign + +Inputs: +```json +[ + "t01234", + "t01234", + "0" +] +``` + +Response: +```json +{ + "Channel": "t01234", + "WaitSentinel": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +} +``` + +### PaychGetWaitReady +There are not yet any comments for this method. + +Perms: sign + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: `"t01234"` + +### PaychList +There are not yet any comments for this method. + +Perms: read + +Inputs: `null` + +Response: `null` + +### PaychNewPayment +There are not yet any comments for this method. + +Perms: sign + +Inputs: +```json +[ + "t01234", + "t01234", + null +] +``` + +Response: +```json +{ + "Channel": "t01234", + "WaitSentinel": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Vouchers": null +} +``` + +### PaychSettle +There are not yet any comments for this method. + +Perms: sign + +Inputs: +```json +[ + "t01234" +] +``` + +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` + +### PaychStatus +There are not yet any comments for this method. + +Perms: read + +Inputs: +```json +[ + "t01234" +] +``` + +Response: +```json +{ + "ControlAddr": "t01234", + "Direction": 1 +} +``` + +### PaychVoucherAdd +There are not yet any comments for this method. + +Perms: write + +Inputs: +```json +[ + "t01234", + { + "ChannelAddr": "t01234", + "TimeLockMin": 10101, + "TimeLockMax": 10101, + "SecretPreimage": "Ynl0ZSBhcnJheQ==", + "Extra": { + "Actor": "t01234", + "Method": 1, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Lane": 42, + "Nonce": 42, + "Amount": "0", + "MinSettleHeight": 10101, + "Merges": null, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } + }, + "Ynl0ZSBhcnJheQ==", + "0" +] +``` + +Response: `"0"` + +### PaychVoucherCheckSpendable +There are not yet any comments for this method. + +Perms: read + +Inputs: +```json +[ + "t01234", + { + "ChannelAddr": "t01234", + "TimeLockMin": 10101, + "TimeLockMax": 10101, + "SecretPreimage": "Ynl0ZSBhcnJheQ==", + "Extra": { + "Actor": "t01234", + "Method": 1, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Lane": 42, + "Nonce": 42, + "Amount": "0", + "MinSettleHeight": 10101, + "Merges": null, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } + }, + "Ynl0ZSBhcnJheQ==", + "Ynl0ZSBhcnJheQ==" +] +``` + +Response: `true` + +### PaychVoucherCheckValid +There are not yet any comments for this method. + +Perms: read + +Inputs: +```json +[ + "t01234", + { + "ChannelAddr": "t01234", + "TimeLockMin": 10101, + "TimeLockMax": 10101, + "SecretPreimage": "Ynl0ZSBhcnJheQ==", + "Extra": { + "Actor": "t01234", + "Method": 1, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Lane": 42, + "Nonce": 42, + "Amount": "0", + "MinSettleHeight": 10101, + "Merges": null, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } + } +] +``` + +Response: `{}` + +### PaychVoucherCreate +There are not yet any comments for this method. + +Perms: sign + +Inputs: +```json +[ + "t01234", + "0", + 42 +] +``` + +Response: +```json +{ + "ChannelAddr": "t01234", + "TimeLockMin": 10101, + "TimeLockMax": 10101, + "SecretPreimage": "Ynl0ZSBhcnJheQ==", + "Extra": { + "Actor": "t01234", + "Method": 1, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Lane": 42, + "Nonce": 42, + "Amount": "0", + "MinSettleHeight": 10101, + "Merges": null, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } +} +``` + +### PaychVoucherList +There are not yet any comments for this method. + +Perms: write + +Inputs: +```json +[ + "t01234" +] +``` + +Response: `null` + +### PaychVoucherSubmit +There are not yet any comments for this method. + +Perms: sign + +Inputs: +```json +[ + "t01234", + { + "ChannelAddr": "t01234", + "TimeLockMin": 10101, + "TimeLockMax": 10101, + "SecretPreimage": "Ynl0ZSBhcnJheQ==", + "Extra": { + "Actor": "t01234", + "Method": 1, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Lane": 42, + "Nonce": 42, + "Amount": "0", + "MinSettleHeight": 10101, + "Merges": null, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } + } +] +``` + +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` + +## State +The State methods are used to query, inspect, and interact with chain state. +All methods take a TipSetKey as a parameter. The state looked up is the state at that tipset. +A nil TipSetKey can be provided as a param, this will cause the heaviest tipset in the chain to be used. + + +### StateAccountKey +StateAccountKey returns the public key address of the given ID address + + +Perms: read + +Inputs: +```json +[ + "t01234", + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `"t01234"` + +### StateAllMinerFaults +StateAllMinerFaults returns all non-expired Faults that occur within lookback epochs of the given tipset + + +Perms: read + +Inputs: +```json +[ + 10101, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `null` + +### StateCall +StateCall runs the given message and returns its result without any persisted changes. + + +Perms: read + +Inputs: +```json +[ + { + "Version": 42, + "To": "t01234", + "From": "t01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==" + }, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "Msg": { + "Version": 42, + "To": "t01234", + "From": "t01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==" + }, + "MsgRct": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "GasUsed": 9 + }, + "ExecutionTrace": { + "Msg": { + "Version": 42, + "To": "t01234", + "From": "t01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==" + }, + "MsgRct": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "GasUsed": 9 + }, + "Error": "string value", + "Duration": 60000000000, + "GasCharges": null, + "Subcalls": null + }, + "Error": "string value", + "Duration": 60000000000 +} +``` + +### StateChangedActors +StateChangedActors returns all the actors whose states change between the two given state CIDs +TODO: Should this take tipset keys instead? + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: +```json +{ + "t01236": { + "Code": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Head": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Nonce": 42, + "Balance": "0" + } +} +``` + +### StateCirculatingSupply +StateCirculatingSupply returns the circulating supply of Filecoin at the given tipset + + +Perms: read + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "FilVested": "0", + "FilMined": "0", + "FilBurnt": "0", + "FilLocked": "0", + "FilCirculating": "0" +} +``` + +### StateCompute +StateCompute is a flexible command that applies the given messages on the given tipset. +The messages are run as though the VM were at the provided height. + + +Perms: read + +Inputs: +```json +[ + 10101, + null, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Trace": null +} +``` + +### StateDealProviderCollateralBounds +StateDealProviderCollateralBounds returns the min and max collateral a storage provider +can issue. It takes the deal size and verified status as parameters. + + +Perms: read + +Inputs: +```json +[ + 1032, + true, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "Min": "0", + "Max": "0" +} +``` + +### StateGetActor +StateGetActor returns the indicated actor's nonce and balance. + + +Perms: read + +Inputs: +```json +[ + "t01234", + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "Code": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Head": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Nonce": 42, + "Balance": "0" +} +``` + +### StateGetReceipt +StateGetReceipt returns the message receipt for the given message + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "GasUsed": 9 +} +``` + +### StateListActors +StateListActors returns the addresses of every actor in the state + + +Perms: read + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `null` + +### StateListMessages +StateListMessages looks back and returns all messages with a matching to or from address, stopping at the given height. + + +Perms: read + +Inputs: +```json +[ + { + "Version": 42, + "To": "t01234", + "From": "t01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==" + }, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ], + 10101 +] +``` + +Response: `null` + +### StateListMiners +StateListMiners returns the addresses of every miner that has claimed power in the Power Actor + + +Perms: read + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `null` + +### StateLookupID +StateLookupID retrieves the ID address of the given address + + +Perms: read + +Inputs: +```json +[ + "t01234", + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `"t01234"` + +### StateMarketBalance +StateMarketBalance looks up the Escrow and Locked balances of the given address in the Storage Market + + +Perms: read + +Inputs: +```json +[ + "t01234", + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "Escrow": "0", + "Locked": "0" +} +``` + +### StateMarketDeals +StateMarketDeals returns information about every deal in the Storage Market + + +Perms: read + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "t026363": { + "Proposal": { + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1032, + "VerifiedDeal": true, + "Client": "t01234", + "Provider": "t01234", + "Label": "string value", + "StartEpoch": 10101, + "EndEpoch": 10101, + "StoragePricePerEpoch": "0", + "ProviderCollateral": "0", + "ClientCollateral": "0" + }, + "State": { + "SectorStartEpoch": 10101, + "LastUpdatedEpoch": 10101, + "SlashEpoch": 10101 + } + } +} +``` + +### StateMarketParticipants +StateMarketParticipants returns the Escrow and Locked balances of every participant in the Storage Market + + +Perms: read + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "t026363": { + "Escrow": "0", + "Locked": "0" + } +} +``` + +### StateMarketStorageDeal +StateMarketStorageDeal returns information about the indicated deal + + +Perms: read + +Inputs: +```json +[ + 5432, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "Proposal": { + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1032, + "VerifiedDeal": true, + "Client": "t01234", + "Provider": "t01234", + "Label": "string value", + "StartEpoch": 10101, + "EndEpoch": 10101, + "StoragePricePerEpoch": "0", + "ProviderCollateral": "0", + "ClientCollateral": "0" + }, + "State": { + "SectorStartEpoch": 10101, + "LastUpdatedEpoch": 10101, + "SlashEpoch": 10101 + } +} +``` + +### StateMinerActiveSectors +StateMinerActiveSectors returns info about sectors that a given miner is actively proving. + + +Perms: read + +Inputs: +```json +[ + "t01234", + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `null` + +### StateMinerAvailableBalance +StateMinerAvailableBalance returns the portion of a miner's balance that can be withdrawn or spent + + +Perms: read + +Inputs: +```json +[ + "t01234", + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `"0"` + +### StateMinerDeadlines +StateMinerDeadlines returns all the proving deadlines for the given miner + + +Perms: read + +Inputs: +```json +[ + "t01234", + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `null` + +### StateMinerFaults +StateMinerFaults returns a bitfield indicating the faulty sectors of the given miner + + +Perms: read + +Inputs: +```json +[ + "t01234", + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +[ + 5, + 1 +] +``` + +### StateMinerInfo +StateMinerInfo returns info about the indicated miner + + +Perms: read + +Inputs: +```json +[ + "t01234", + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "Owner": "t01234", + "Worker": "t01234", + "NewWorker": "t01234", + "ControlAddresses": null, + "WorkerChangeEpoch": 10101, + "PeerId": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Multiaddrs": null, + "SealProofType": 3, + "SectorSize": 34359738368, + "WindowPoStPartitionSectors": 42 +} +``` + +### StateMinerInitialPledgeCollateral +StateMinerInitialPledgeCollateral returns the initial pledge collateral for the specified miner's sector + + +Perms: read + +Inputs: +```json +[ + "t01234", + { + "SealProof": 3, + "SectorNumber": 9, + "SealedCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "SealRandEpoch": 10101, + "DealIDs": null, + "Expiration": 10101, + "ReplaceCapacity": true, + "ReplaceSectorDeadline": 42, + "ReplaceSectorPartition": 42, + "ReplaceSectorNumber": 9 + }, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `"0"` + +### StateMinerPartitions +StateMinerPartitions loads miner partitions for the specified miner/deadline + + +Perms: read + +Inputs: +```json +[ + "t01234", + 42, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `null` + +### StateMinerPower +StateMinerPower returns the power of the indicated miner + + +Perms: read + +Inputs: +```json +[ + "t01234", + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "MinerPower": { + "RawBytePower": "0", + "QualityAdjPower": "0" + }, + "TotalPower": { + "RawBytePower": "0", + "QualityAdjPower": "0" + } +} +``` + +### StateMinerPreCommitDepositForPower +StateMinerInitialPledgeCollateral returns the precommit deposit for the specified miner's sector + + +Perms: read + +Inputs: +```json +[ + "t01234", + { + "SealProof": 3, + "SectorNumber": 9, + "SealedCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "SealRandEpoch": 10101, + "DealIDs": null, + "Expiration": 10101, + "ReplaceCapacity": true, + "ReplaceSectorDeadline": 42, + "ReplaceSectorPartition": 42, + "ReplaceSectorNumber": 9 + }, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `"0"` + +### StateMinerProvingDeadline +StateMinerProvingDeadline calculates the deadline at some epoch for a proving period +and returns the deadline-related calculations. + + +Perms: read + +Inputs: +```json +[ + "t01234", + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "CurrentEpoch": 10101, + "PeriodStart": 10101, + "Index": 42, + "Open": 10101, + "Close": 10101, + "Challenge": 10101, + "FaultCutoff": 10101 +} +``` + +### StateMinerRecoveries +StateMinerRecoveries returns a bitfield indicating the recovering sectors of the given miner + + +Perms: read + +Inputs: +```json +[ + "t01234", + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +[ + 5, + 1 +] +``` + +### StateMinerSectorCount +StateMinerSectorCount returns the number of sectors in a miner's sector set and proving set + + +Perms: read + +Inputs: +```json +[ + "t01234", + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "Sectors": 42, + "Active": 42 +} +``` + +### StateMinerSectors +StateMinerSectors returns info about the given miner's sectors. If the filter bitfield is nil, all sectors are included. +If the filterOut boolean is set to true, any sectors in the filter are excluded. +If false, only those sectors in the filter are included. + + +Perms: read + +Inputs: +```json +[ + "t01234", + [ + 0 + ], + true, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `null` + +### StateNetworkName +StateNetworkName returns the name of the network the node is synced to + + +Perms: read + +Inputs: `null` + +Response: `"lotus"` + +### StateReadState +StateReadState returns the indicated actor's state. + + +Perms: read + +Inputs: +```json +[ + "t01234", + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "Balance": "0", + "State": {} +} +``` + +### StateReplay +StateReplay returns the result of executing the indicated message, assuming it was executed in the indicated tipset. + + +Perms: read + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ], + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: +```json +{ + "Msg": { + "Version": 42, + "To": "t01234", + "From": "t01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==" + }, + "MsgRct": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "GasUsed": 9 + }, + "ExecutionTrace": { + "Msg": { + "Version": 42, + "To": "t01234", + "From": "t01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==" + }, + "MsgRct": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "GasUsed": 9 + }, + "Error": "string value", + "Duration": 60000000000, + "GasCharges": null, + "Subcalls": null + }, + "Error": "string value", + "Duration": 60000000000 +} +``` + +### StateSearchMsg +StateSearchMsg searches for a message in the chain, and returns its receipt and the tipset where it was executed + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: +```json +{ + "Message": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Receipt": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "GasUsed": 9 + }, + "ReturnDec": {}, + "TipSet": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ], + "Height": 10101 +} +``` + +### StateSectorExpiration +StateSectorExpiration returns epoch at which given sector will expire + + +Perms: read + +Inputs: +```json +[ + "t01234", + 9, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "OnTime": 10101, + "Early": 10101 +} +``` + +### StateSectorGetInfo +StateSectorGetInfo returns the on-chain info for the specified miner's sector +NOTE: returned info.Expiration may not be accurate in some cases, use StateSectorExpiration to get accurate +expiration epoch + + +Perms: read + +Inputs: +```json +[ + "t01234", + 9, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "SectorNumber": 9, + "SealProof": 3, + "SealedCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "DealIDs": null, + "Activation": 10101, + "Expiration": 10101, + "DealWeight": "0", + "VerifiedDealWeight": "0", + "InitialPledge": "0", + "ExpectedDayReward": "0", + "ExpectedStoragePledge": "0" +} +``` + +### StateSectorPartition +StateSectorPartition finds deadline/partition with the specified sector + + +Perms: read + +Inputs: +```json +[ + "t01234", + 9, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "Deadline": 42, + "Partition": 42 +} +``` + +### StateSectorPreCommitInfo +StateSectorPreCommitInfo returns the PreCommit info for the specified miner's sector + + +Perms: read + +Inputs: +```json +[ + "t01234", + 9, + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: +```json +{ + "Info": { + "SealProof": 3, + "SectorNumber": 9, + "SealedCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "SealRandEpoch": 10101, + "DealIDs": null, + "Expiration": 10101, + "ReplaceCapacity": true, + "ReplaceSectorDeadline": 42, + "ReplaceSectorPartition": 42, + "ReplaceSectorNumber": 9 + }, + "PreCommitDeposit": "0", + "PreCommitEpoch": 10101, + "DealWeight": "0", + "VerifiedDealWeight": "0" +} +``` + +### StateVerifiedClientStatus +StateVerifiedClientStatus returns the data cap for the given address. +Returns nil if there is no entry in the data cap table for the +address. + + +Perms: read + +Inputs: +```json +[ + "t01234", + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `"0"` + +### StateWaitMsg +StateWaitMsg looks back in the chain for a message. If not found, it blocks until the +message arrives on chain, and gets to the indicated confidence depth. + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + 42 +] +``` + +Response: +```json +{ + "Message": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Receipt": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "GasUsed": 9 + }, + "ReturnDec": {}, + "TipSet": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ], + "Height": 10101 +} +``` + +## Sync +The Sync method group contains methods for interacting with and +observing the lotus sync service. + + +### SyncCheckBad +SyncCheckBad checks if a block was marked as bad, and if it was, returns +the reason. + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: `"string value"` + +### SyncIncomingBlocks +SyncIncomingBlocks returns a channel streaming incoming, potentially not +yet synced block headers. + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "Miner": "t01234", + "Ticket": { + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "ElectionProof": { + "WinCount": 9, + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "BeaconEntries": null, + "WinPoStProof": null, + "Parents": null, + "ParentWeight": "0", + "Height": 10101, + "ParentStateRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "ParentMessageReceipts": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Messages": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "BLSAggregate": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Timestamp": 42, + "BlockSig": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "ForkSignaling": 42, + "ParentBaseFee": "0" +} +``` + +### SyncMarkBad +SyncMarkBad marks a blocks as bad, meaning that it won't ever by synced. +Use with extreme caution. + + +Perms: admin + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: `{}` + +### SyncState +SyncState returns the current status of the lotus sync system. + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "ActiveSyncs": null +} +``` + +### SyncSubmitBlock +SyncSubmitBlock can be used to submit a newly created block to the. +network through this node + + +Perms: write + +Inputs: +```json +[ + { + "Header": { + "Miner": "t01234", + "Ticket": { + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "ElectionProof": { + "WinCount": 9, + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "BeaconEntries": null, + "WinPoStProof": null, + "Parents": null, + "ParentWeight": "0", + "Height": 10101, + "ParentStateRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "ParentMessageReceipts": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Messages": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "BLSAggregate": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Timestamp": 42, + "BlockSig": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "ForkSignaling": 42, + "ParentBaseFee": "0" + }, + "BlsMessages": null, + "SecpkMessages": null + } +] +``` + +Response: `{}` + +## Wallet + + +### WalletBalance +WalletBalance returns the balance of the given address at the current head of the chain. + + +Perms: read + +Inputs: +```json +[ + "t01234" +] +``` + +Response: `"0"` + +### WalletDefaultAddress +WalletDefaultAddress returns the address marked as default in the wallet. + + +Perms: write + +Inputs: `null` + +Response: `"t01234"` + +### WalletDelete +WalletDelete deletes an address from the wallet. + + +Perms: write + +Inputs: +```json +[ + "t01234" +] +``` + +Response: `{}` + +### WalletExport +WalletExport returns the private key of an address in the wallet. + + +Perms: admin + +Inputs: +```json +[ + "t01234" +] +``` + +Response: +```json +{ + "Type": "string value", + "PrivateKey": "Ynl0ZSBhcnJheQ==" +} +``` + +### WalletHas +WalletHas indicates whether the given address is in the wallet. + + +Perms: write + +Inputs: +```json +[ + "t01234" +] +``` + +Response: `true` + +### WalletImport +WalletImport receives a KeyInfo, which includes a private key, and imports it into the wallet. + + +Perms: admin + +Inputs: +```json +[ + { + "Type": "string value", + "PrivateKey": "Ynl0ZSBhcnJheQ==" + } +] +``` + +Response: `"t01234"` + +### WalletList +WalletList lists all the addresses in the wallet. + + +Perms: write + +Inputs: `null` + +Response: `null` + +### WalletNew +WalletNew creates a new address in the wallet with the given sigType. + + +Perms: write + +Inputs: +```json +[ + 2 +] +``` + +Response: `"t01234"` + +### WalletSetDefault +WalletSetDefault marks the given address as as the default one. + + +Perms: admin + +Inputs: +```json +[ + "t01234" +] +``` + +Response: `{}` + +### WalletSign +WalletSign signs the given bytes using the given address. + + +Perms: sign + +Inputs: +```json +[ + "t01234", + "Ynl0ZSBhcnJheQ==" +] +``` + +Response: +```json +{ + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" +} +``` + +### WalletSignMessage +WalletSignMessage signs the given message using the given address. + + +Perms: sign + +Inputs: +```json +[ + "t01234", + { + "Version": 42, + "To": "t01234", + "From": "t01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==" + } +] +``` + +Response: +```json +{ + "Message": { + "Version": 42, + "To": "t01234", + "From": "t01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==" + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } +} +``` + +### WalletVerify +WalletVerify takes an address, a signature, and some bytes, and indicates whether the signature is valid. +The address does not have to be in the wallet. + + +Perms: read + +Inputs: +```json +[ + "t01234", + "Ynl0ZSBhcnJheQ==", + { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } +] +``` + +Response: `true` + From 4e74e6690386bfe48eed54544b41f295a3b4477c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Mon, 24 Aug 2020 12:28:22 +0200 Subject: [PATCH 059/247] ci: Fix cbor check --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8ee3bca33..87df413b7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -257,6 +257,7 @@ jobs: steps: - install-deps - prepare + - run: make deps - run: go install golang.org/x/tools/cmd/goimports - run: go install github.com/hannahhoward/cbor-gen-for - run: go generate ./... From b87c89ad16e3ae61d5969f7ef43628a3f649e04f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Mon, 24 Aug 2020 12:51:55 +0200 Subject: [PATCH 060/247] mod tidy, fix lint --- chain/gen/genesis/miners.go | 4 ++-- chain/validation/keymanager.go | 2 +- cli/mpool.go | 2 +- go.sum | 11 ----------- 4 files changed, 4 insertions(+), 15 deletions(-) diff --git a/chain/gen/genesis/miners.go b/chain/gen/genesis/miners.go index 770581238..1c3f717ad 100644 --- a/chain/gen/genesis/miners.go +++ b/chain/gen/genesis/miners.go @@ -330,13 +330,13 @@ type fakeRand struct{} func (fr *fakeRand) GetChainRandomness(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) { out := make([]byte, 32) - _, _ = rand.New(rand.NewSource(int64(randEpoch * 1000))).Read(out) + _, _ = rand.New(rand.NewSource(int64(randEpoch * 1000))).Read(out) //nolint return out, nil } func (fr *fakeRand) GetBeaconRandomness(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) { out := make([]byte, 32) - _, _ = rand.New(rand.NewSource(int64(randEpoch))).Read(out) + _, _ = rand.New(rand.NewSource(int64(randEpoch))).Read(out) //nolint return out, nil } diff --git a/chain/validation/keymanager.go b/chain/validation/keymanager.go index 95fbf2142..e93f169bf 100644 --- a/chain/validation/keymanager.go +++ b/chain/validation/keymanager.go @@ -70,7 +70,7 @@ func (k *KeyManager) Sign(addr address.Address, data []byte) (acrypto.Signature, } func (k *KeyManager) newSecp256k1Key() *wallet.Key { - randSrc := rand.New(rand.NewSource(k.secpSeed)) + randSrc := rand.New(rand.NewSource(k.secpSeed)) // nolint prv, err := crypto.GenerateKeyFromSeed(randSrc) if err != nil { panic(err) diff --git a/cli/mpool.go b/cli/mpool.go index 948d0b695..5f8ccd8f7 100644 --- a/cli/mpool.go +++ b/cli/mpool.go @@ -106,7 +106,7 @@ var mpoolClear = &cli.Command{ really := cctx.Bool("really-do-it") if !really { - return fmt.Errorf("--really-do-it must be specified for this action to have an effect; you have been warned.") + return fmt.Errorf("the --really-do-it flag must be specified for this action to have an effect; you have been warned") } local := cctx.Bool("local") diff --git a/go.sum b/go.sum index 6d352d9c0..16b627ca5 100644 --- a/go.sum +++ b/go.sum @@ -230,8 +230,6 @@ github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20200731171407-e559a0579161 github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20200731171407-e559a0579161/go.mod h1:vgmwKBkx+ca5OIeEvstiQgzAZnb7R6QaqE1oEDSqa6g= github.com/filecoin-project/go-bitfield v0.0.0-20200416002808-b3ee67ec9060/go.mod h1:iodsLxOFZnqKtjj2zkgqzoGNrv6vUqj69AT/J8DKXEw= github.com/filecoin-project/go-bitfield v0.0.1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= -github.com/filecoin-project/go-bitfield v0.0.3/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= -github.com/filecoin-project/go-bitfield v0.0.4-0.20200703174658-f4a5758051a1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= github.com/filecoin-project/go-bitfield v0.1.2 h1:TjLregCoyP1/5lm7WCM0axyV1myIHwbjGa21skuu5tk= github.com/filecoin-project/go-bitfield v0.1.2/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= github.com/filecoin-project/go-bitfield v0.2.0 h1:gCtLcjskIPtdg4NfN7gQZSQF9yrBQ7mkT0qCJxzGI2Q= @@ -242,7 +240,6 @@ github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 h1:2pMX github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= github.com/filecoin-project/go-data-transfer v0.6.2 h1:IgbkwcHoyWGglzfsY7P9L1GapzoiLNKuzfZY2bxER8E= github.com/filecoin-project/go-data-transfer v0.6.2/go.mod h1:uRYBRKVBVM12CSusBtVrzDHkVw/3DKZpkxKJVP1Ydas= -github.com/filecoin-project/go-fil-commcid v0.0.0-20200208005934-2b8bd03caca5/go.mod h1:JbkIgFF/Z9BDlvrJO1FuKkaWsH673/UdFaiVS6uIHlA= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1:GxJzR3oRIMTPtpZ0b7QF8FKPK6/iPAc7trhlL5k/g+s= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= github.com/filecoin-project/go-fil-markets v0.5.7 h1:kzyMHqez8ssxchj5s9M1hkC3CTwRGh2MeglJGfUksQU= @@ -253,11 +250,9 @@ github.com/filecoin-project/go-multistore v0.0.3 h1:vaRBY4YiA2UZFPK57RNuewypB8u0 github.com/filecoin-project/go-multistore v0.0.3/go.mod h1:kaNqCC4IhU4B1uyr7YWFHd23TL4KM32aChS0jNkyUvQ= github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6 h1:92PET+sx1Hb4W/8CgFwGuxaKbttwY+UNspYZTvXY0vs= github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6/go.mod h1:0HgYnrkeSU4lu1p+LEOeDpFsNBssa0OGGriWdA4hvaE= -github.com/filecoin-project/go-paramfetch v0.0.1/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= github.com/filecoin-project/go-paramfetch v0.0.2-0.20200218225740-47c639bab663/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261 h1:A256QonvzRaknIIAuWhe/M2dpV2otzs3NBhi5TWa/UA= github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= -github.com/filecoin-project/go-statemachine v0.0.0-20200226041606-2074af6d51d9/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v0.0.0-20200714194326-a77c3ae20989/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370 h1:Jbburj7Ih2iaJ/o5Q9A+EAeTabME6YII7FLi9SKUf5c= github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= @@ -265,14 +260,12 @@ github.com/filecoin-project/go-statestore v0.1.0 h1:t56reH59843TwXHkMcwyuayStBIi github.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZOinUJB4WARkRfNl10O7kTnI= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b h1:fkRZSPrYpk42PV3/lIXiL0LHetxde7vyYYvSsttQtfg= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8= -github.com/filecoin-project/sector-storage v0.0.0-20200712023225-1d67dcfa3c15/go.mod h1:salgVdX7qeXFo/xaiEQE29J4pPkjn71T0kt0n+VDBzo= github.com/filecoin-project/sector-storage v0.0.0-20200730050024-3ee28c3b6d9a/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0 h1:E1fZ27fhKK05bhZItfTwqr1i05vXnEZJznQFEYwEEUU= github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= github.com/filecoin-project/specs-actors v0.0.0-20200210130641-2d1fbd8672cf/go.mod h1:xtDZUB6pe4Pksa/bAJbJ693OilaC5Wbot9jMhLm3cZA= github.com/filecoin-project/specs-actors v0.3.0/go.mod h1:nQYnFbQ7Y0bHZyq6HDEuVlCPR+U3z5Q3wMOQ+2aiV+Y= github.com/filecoin-project/specs-actors v0.6.1/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY= -github.com/filecoin-project/specs-actors v0.7.3-0.20200716231407-60a2ae96d2e6/go.mod h1:JOMUa7EijvpOO4ofD1yeHNmqohkmmnhTvz/IpB6so4c= github.com/filecoin-project/specs-actors v0.8.2/go.mod h1:Q3ACV5kBLvqPaYbthc/J1lGMJ5OwogmD9pzdtPRMdCw= github.com/filecoin-project/specs-actors v0.8.7-0.20200811203034-272d022c1923 h1:+H4IG4OjTThljPkMH1ZpynxCulNdx4amEeHoP2GdQJI= github.com/filecoin-project/specs-actors v0.8.7-0.20200811203034-272d022c1923/go.mod h1:hukRu6vKQrrS7Nt+fC/ql4PqWLSfmAWNshD/VDtARZU= @@ -535,7 +528,6 @@ github.com/ipfs/go-graphsync v0.1.0/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CE github.com/ipfs/go-graphsync v0.1.1 h1:bFDAYS0Z48yd8ROPI6f/zIVmJxaDLA6m8cVuJPKC5fE= github.com/ipfs/go-graphsync v0.1.1/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= github.com/ipfs/go-hamt-ipld v0.0.15-0.20200131012125-dd88a59d3f2e/go.mod h1:9aQJu/i/TaRDW6jqB5U217dLIDopn50wxLdHXM2CTfE= -github.com/ipfs/go-hamt-ipld v0.0.15-0.20200204200533-99b8553ef242/go.mod h1:kq3Pi+UP3oHhAdKexE+kHHYRKMoFNuGero0R7q3hWGg= github.com/ipfs/go-hamt-ipld v0.1.1 h1:0IQdvwnAAUKmDE+PMJa5y1QiwOPHpI9+eAbQEEEYthk= github.com/ipfs/go-hamt-ipld v0.1.1/go.mod h1:1EZCr2v0jlCnhpa+aZ0JZYp8Tt2w16+JJOAVz17YcDk= github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= @@ -1510,7 +1502,6 @@ golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1667,7 +1658,6 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1729,7 +1719,6 @@ golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200108195415-316d2f248479/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= From fc34b8647005f3926292727fd172c80ae32551de Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 24 Aug 2020 18:01:52 +0300 Subject: [PATCH 061/247] use DNS addr for tracer --- node/config/def.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/config/def.go b/node/config/def.go index d10810998..9fee8895a 100644 --- a/node/config/def.go +++ b/node/config/def.go @@ -126,7 +126,7 @@ func defCommon() Common { Pubsub: Pubsub{ Bootstrapper: false, DirectPeers: nil, - RemoteTracer: "/ip4/147.75.67.199/tcp/4001/p2p/QmTd6UvR47vUidRNZ1ZKXHrAFhqTJAD27rKL9XYghEKgKX", + RemoteTracer: "/dns4/pubsub-tracer.filecoin.io/tcp/4001/p2p/QmTd6UvR47vUidRNZ1ZKXHrAFhqTJAD27rKL9XYghEKgKX", }, } From da90caedf0c051715689a82092897afe36a093ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Mon, 24 Aug 2020 18:13:52 +0200 Subject: [PATCH 062/247] docs: rename file --- Makefile | 2 +- documentation/en/{api-functions.md => api-methods.md} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename documentation/en/{api-functions.md => api-methods.md} (100%) diff --git a/Makefile b/Makefile index 31140589a..4f6ece417 100644 --- a/Makefile +++ b/Makefile @@ -280,7 +280,7 @@ method-gen: gen: type-gen method-gen docsgen: - go run ./api/docgen > documentation/en/api-functions.md + go run ./api/docgen > documentation/en/api-methods.md print-%: @echo $*=$($*) diff --git a/documentation/en/api-functions.md b/documentation/en/api-methods.md similarity index 100% rename from documentation/en/api-functions.md rename to documentation/en/api-methods.md From 33ada25ba84fcf5304ac66b2337f36c8d3ab2478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Mon, 24 Aug 2020 18:18:32 +0200 Subject: [PATCH 063/247] docs: Add api-methods to library.json --- documentation/en/.library.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/documentation/en/.library.json b/documentation/en/.library.json index 457ce80b8..3fab0df9b 100644 --- a/documentation/en/.library.json +++ b/documentation/en/.library.json @@ -175,6 +175,12 @@ "github": "en/api-scripting-support.md", "value": null }, + { + "title": "API Methods", + "slug": "en+api-methods", + "github": "en/api-methods.md", + "value": null + }, { "title": "API Troubleshooting", "slug": "en+api-troubleshooting", From d9796cd25c6ff3bcb054d85950d4ae27f586e1ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Mon, 24 Aug 2020 19:13:36 +0200 Subject: [PATCH 064/247] sectorstorage: Make trySched less very slow --- extern/sector-storage/sched.go | 127 ++++++++++++++++------------ extern/sector-storage/sched_test.go | 83 ++++++++++++++++-- 2 files changed, 149 insertions(+), 61 deletions(-) diff --git a/extern/sector-storage/sched.go b/extern/sector-storage/sched.go index 7842003a5..7a4b6f9ef 100644 --- a/extern/sector-storage/sched.go +++ b/extern/sector-storage/sched.go @@ -287,72 +287,93 @@ func (sh *scheduler) trySched() { sh.workersLk.RLock() defer sh.workersLk.RUnlock() + if len(sh.openWindows) == 0 { + // nothing to schedule on + return + } // Step 1 - for sqi := 0; sqi < sh.schedQueue.Len(); sqi++ { - task := (*sh.schedQueue)[sqi] - needRes := ResourceTable[task.taskType][sh.spt] + concurrency := len(sh.openWindows) + throttle := make(chan struct{}, concurrency) - task.indexHeap = sqi - for wnd, windowRequest := range sh.openWindows { - worker, ok := sh.workers[windowRequest.worker] - if !ok { - log.Errorf("worker referenced by windowRequest not found (worker: %d)", windowRequest.worker) - // TODO: How to move forward here? - continue + var wg sync.WaitGroup + wg.Add(sh.schedQueue.Len()) + + for i := 0; i < sh.schedQueue.Len(); i++ { + throttle <- struct{}{} + + go func(sqi int) { + defer wg.Done() + defer func() { + <-throttle + }() + + task := (*sh.schedQueue)[sqi] + needRes := ResourceTable[task.taskType][sh.spt] + + task.indexHeap = sqi + for wnd, windowRequest := range sh.openWindows { + worker, ok := sh.workers[windowRequest.worker] + if !ok { + log.Errorf("worker referenced by windowRequest not found (worker: %d)", windowRequest.worker) + // TODO: How to move forward here? + continue + } + + // TODO: allow bigger windows + if !windows[wnd].allocated.canHandleRequest(needRes, windowRequest.worker, worker.info.Resources) { + continue + } + + rpcCtx, cancel := context.WithTimeout(task.ctx, SelectorTimeout) + ok, err := task.sel.Ok(rpcCtx, task.taskType, sh.spt, worker) + cancel() + if err != nil { + log.Errorf("trySched(1) req.sel.Ok error: %+v", err) + continue + } + + if !ok { + continue + } + + acceptableWindows[sqi] = append(acceptableWindows[sqi], wnd) } - // TODO: allow bigger windows - if !windows[wnd].allocated.canHandleRequest(needRes, windowRequest.worker, worker.info.Resources) { - continue + if len(acceptableWindows[sqi]) == 0 { + return } - rpcCtx, cancel := context.WithTimeout(task.ctx, SelectorTimeout) - ok, err := task.sel.Ok(rpcCtx, task.taskType, sh.spt, worker) - cancel() - if err != nil { - log.Errorf("trySched(1) req.sel.Ok error: %+v", err) - continue - } + // Pick best worker (shuffle in case some workers are equally as good) + rand.Shuffle(len(acceptableWindows[sqi]), func(i, j int) { + acceptableWindows[sqi][i], acceptableWindows[sqi][j] = acceptableWindows[sqi][j], acceptableWindows[sqi][i] // nolint:scopelint + }) + sort.SliceStable(acceptableWindows[sqi], func(i, j int) bool { + wii := sh.openWindows[acceptableWindows[sqi][i]].worker // nolint:scopelint + wji := sh.openWindows[acceptableWindows[sqi][j]].worker // nolint:scopelint - if !ok { - continue - } + if wii == wji { + // for the same worker prefer older windows + return acceptableWindows[sqi][i] < acceptableWindows[sqi][j] // nolint:scopelint + } - acceptableWindows[sqi] = append(acceptableWindows[sqi], wnd) - } + wi := sh.workers[wii] + wj := sh.workers[wji] - if len(acceptableWindows[sqi]) == 0 { - continue - } + rpcCtx, cancel := context.WithTimeout(task.ctx, SelectorTimeout) + defer cancel() - // Pick best worker (shuffle in case some workers are equally as good) - rand.Shuffle(len(acceptableWindows[sqi]), func(i, j int) { - acceptableWindows[sqi][i], acceptableWindows[sqi][j] = acceptableWindows[sqi][j], acceptableWindows[sqi][i] // nolint:scopelint - }) - sort.SliceStable(acceptableWindows[sqi], func(i, j int) bool { - wii := sh.openWindows[acceptableWindows[sqi][i]].worker // nolint:scopelint - wji := sh.openWindows[acceptableWindows[sqi][j]].worker // nolint:scopelint - - if wii == wji { - // for the same worker prefer older windows - return acceptableWindows[sqi][i] < acceptableWindows[sqi][j] // nolint:scopelint - } - - wi := sh.workers[wii] - wj := sh.workers[wji] - - rpcCtx, cancel := context.WithTimeout(task.ctx, SelectorTimeout) - defer cancel() - - r, err := task.sel.Cmp(rpcCtx, task.taskType, wi, wj) - if err != nil { - log.Error("selecting best worker: %s", err) - } - return r - }) + r, err := task.sel.Cmp(rpcCtx, task.taskType, wi, wj) + if err != nil { + log.Error("selecting best worker: %s", err) + } + return r + }) + }(i) } + wg.Wait() + log.Debugf("SCHED windows: %+v", windows) log.Debugf("SCHED Acceptable win: %+v", acceptableWindows) diff --git a/extern/sector-storage/sched_test.go b/extern/sector-storage/sched_test.go index 5c9bc44ee..fcfe891e7 100644 --- a/extern/sector-storage/sched_test.go +++ b/extern/sector-storage/sched_test.go @@ -10,6 +10,7 @@ import ( "time" "github.com/ipfs/go-cid" + logging "github.com/ipfs/go-log/v2" "github.com/stretchr/testify/require" "github.com/filecoin-project/specs-actors/actors/abi" @@ -100,16 +101,18 @@ func (s *schedTestWorker) Paths(ctx context.Context) ([]stores.StoragePath, erro return s.paths, nil } +var decentWorkerResources = storiface.WorkerResources{ + MemPhysical: 128 << 30, + MemSwap: 200 << 30, + MemReserved: 2 << 30, + CPUs: 32, + GPUs: []string{"a GPU"}, +} + func (s *schedTestWorker) Info(ctx context.Context) (storiface.WorkerInfo, error) { return storiface.WorkerInfo{ - Hostname: s.name, - Resources: storiface.WorkerResources{ - MemPhysical: 128 << 30, - MemSwap: 200 << 30, - MemReserved: 2 << 30, - CPUs: 32, - GPUs: []string{"a GPU"}, - }, + Hostname: s.name, + Resources: decentWorkerResources, }, nil } @@ -451,3 +454,67 @@ func TestSched(t *testing.T) { })) } } + +type slowishSelector bool + +func (s slowishSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi.RegisteredSealProof, a *workerHandle) (bool, error) { + time.Sleep(200 * time.Microsecond) + return bool(s), nil +} + +func (s slowishSelector) Cmp(ctx context.Context, task sealtasks.TaskType, a, b *workerHandle) (bool, error) { + time.Sleep(100 * time.Microsecond) + return true, nil +} + +var _ WorkerSelector = slowishSelector(true) + +func BenchmarkTrySched(b *testing.B) { + spt := abi.RegisteredSealProof_StackedDrg32GiBV1 + logging.SetAllLoggers(logging.LevelInfo) + defer logging.SetAllLoggers(logging.LevelDebug) + ctx := context.Background() + + test := func(windows, queue int) func(b *testing.B) { + return func(b *testing.B) { + for i := 0; i < b.N; i++ { + b.StopTimer() + + sched := newScheduler(spt) + sched.workers[0] = &workerHandle{ + w: nil, + info: storiface.WorkerInfo{ + Hostname: "t", + Resources: decentWorkerResources, + }, + preparing: &activeResources{}, + active: &activeResources{}, + } + + for i := 0; i < windows; i++ { + sched.openWindows = append(sched.openWindows, &schedWindowRequest{ + worker: 0, + done: make(chan *schedWindow, 1000), + }) + } + + for i := 0; i < queue; i++ { + sched.schedQueue.Push(&workerRequest{ + taskType: sealtasks.TTCommit2, + sel: slowishSelector(true), + ctx: ctx, + }) + } + + b.StartTimer() + + sched.trySched() + } + } + } + + b.Run("1w-1q", test(1, 1)) + b.Run("500w-1q", test(500, 1)) + b.Run("1w-500q", test(1, 500)) + b.Run("200w-400q", test(200, 400)) +} From 1447a66515443bb2b8ce90c9cb0b5e18b315ef19 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Mon, 24 Aug 2020 11:33:49 -0700 Subject: [PATCH 065/247] randomize ticket in genesis creation --- chain/gen/genesis/genesis.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index 40f006522..ba43104b0 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -2,6 +2,7 @@ package genesis import ( "context" + "crypto/rand" "encoding/json" "fmt" @@ -510,8 +511,10 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys vm.SyscallB log.Infof("Empty Genesis root: %s", emptyroot) + tickBuf := make([]byte, 32) + _, _ = rand.Read(tickBuf) genesisticket := &types.Ticket{ - VRFProof: []byte("vrf proof0000000vrf proof0000000"), + VRFProof: tickBuf, } filecoinGenesisCid, err := cid.Decode("bafyreiaqpwbbyjo4a42saasj36kkrpv4tsherf2e7bvezkert2a7dhonoi") From 3736d1ce4527664169a4a686452b1ea6b8beebcc Mon Sep 17 00:00:00 2001 From: Travis Person Date: Mon, 24 Aug 2020 19:51:48 +0000 Subject: [PATCH 066/247] Testnet spacerace genesis --- build/genesis/devnet.car | Bin 0 -> 1104195 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 build/genesis/devnet.car diff --git a/build/genesis/devnet.car b/build/genesis/devnet.car new file mode 100644 index 0000000000000000000000000000000000000000..f1b3f342a6ca53e3398a3826a0368fb34dd8d0aa GIT binary patch literal 1104195 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%0DnXIMQ#TkSm7SP$l!CwIUBdF4Ak04G9lE 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 literal 0 HcmV?d00001 From 6b8191121c25f120562348ef0c5f7cecfb29d910 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Thu, 20 Aug 2020 18:10:11 -0700 Subject: [PATCH 067/247] add lotus-shed command to verify some stuff about the genesis car --- cmd/lotus-shed/genesis-verify.go | 52 ++++++++++++++++++++++++++++++++ cmd/lotus-shed/main.go | 1 + 2 files changed, 53 insertions(+) create mode 100644 cmd/lotus-shed/genesis-verify.go diff --git a/cmd/lotus-shed/genesis-verify.go b/cmd/lotus-shed/genesis-verify.go new file mode 100644 index 000000000..2663986d9 --- /dev/null +++ b/cmd/lotus-shed/genesis-verify.go @@ -0,0 +1,52 @@ +package main + +import ( + "context" + "fmt" + "os" + + "github.com/ipfs/go-datastore" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/lib/blockstore" +) + +var genesisVerifyCmd = &cli.Command{ + Name: "verify-genesis", + Description: "verify some basic attributes of a genesis car file", + Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + return fmt.Errorf("must pass genesis car file") + } + bs := blockstore.NewBlockstore(datastore.NewMapDatastore()) + + cs := store.NewChainStore(bs, datastore.NewMapDatastore(), nil) + + cf := cctx.Args().Get(0) + f, err := os.Open(cf) + if err != nil { + return xerrors.Errorf("opening the car file: %w", err) + } + + ts, err := cs.Import(f) + if err != nil { + return err + } + + fmt.Println("File loaded, now verifying state tree balances...") + + sm := stmgr.NewStateManager(cs) + + total, err := stmgr.CheckTotalFIL(context.TODO(), sm, ts) + if err != nil { + return err + } + + fmt.Printf("Total FIL: %s\n", types.FIL(total)) + return nil + }, +} diff --git a/cmd/lotus-shed/main.go b/cmd/lotus-shed/main.go index 30e7ff32d..5438a31ef 100644 --- a/cmd/lotus-shed/main.go +++ b/cmd/lotus-shed/main.go @@ -30,6 +30,7 @@ func main() { verifRegCmd, miscCmd, mpoolCmd, + genesisVerifyCmd, } app := &cli.App{ From 4f6dc0748d65a6f7f3f5bb0079afc1b0541fff0a Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Fri, 21 Aug 2020 20:58:39 -0700 Subject: [PATCH 068/247] print out genesis block accounts --- cmd/lotus-shed/genesis-verify.go | 112 ++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/cmd/lotus-shed/genesis-verify.go b/cmd/lotus-shed/genesis-verify.go index 2663986d9..92915102a 100644 --- a/cmd/lotus-shed/genesis-verify.go +++ b/cmd/lotus-shed/genesis-verify.go @@ -4,17 +4,42 @@ import ( "context" "fmt" "os" + "sort" + "github.com/fatih/color" "github.com/ipfs/go-datastore" + cbor "github.com/ipfs/go-ipld-cbor" "github.com/urfave/cli/v2" "golang.org/x/xerrors" + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/lib/blockstore" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin" + saacc "github.com/filecoin-project/specs-actors/actors/builtin/account" + saminer "github.com/filecoin-project/specs-actors/actors/builtin/miner" + samsig "github.com/filecoin-project/specs-actors/actors/builtin/multisig" ) +type addrInfo struct { + Key address.Address + Balance types.FIL +} + +type msigInfo struct { + Signers []address.Address + Balance types.FIL + Threshold uint64 +} + +type minerInfo struct { +} + var genesisVerifyCmd = &cli.Command{ Name: "verify-genesis", Description: "verify some basic attributes of a genesis car file", @@ -46,7 +71,92 @@ var genesisVerifyCmd = &cli.Command{ return err } - fmt.Printf("Total FIL: %s\n", types.FIL(total)) + expFIL := big.Mul(big.NewInt(int64(build.FilBase)), big.NewInt(int64(build.FilecoinPrecision))) + fmt.Printf("Total FIL: %s", types.FIL(total)) + if !expFIL.Equals(total) { + color.Red(" INCORRECT!") + } + fmt.Println() + + cst := cbor.NewCborStore(bs) + + stree, err := state.LoadStateTree(cst, ts.ParentState()) + if err != nil { + return err + } + + var accAddrs, msigAddrs []address.Address + kaccounts := make(map[address.Address]addrInfo) + kmultisigs := make(map[address.Address]msigInfo) + kminers := make(map[address.Address]minerInfo) + + ctx := context.TODO() + + if err := stree.ForEach(func(addr address.Address, act *types.Actor) error { + switch act.Code { + case builtin.StorageMinerActorCodeID: + var st saminer.State + if err := cst.Get(ctx, act.Head, &st); err != nil { + return err + } + + kminers[addr] = minerInfo{} + case builtin.MultisigActorCodeID: + var st samsig.State + if err := cst.Get(ctx, act.Head, &st); err != nil { + return xerrors.Errorf("multisig actor: %w", err) + } + + kmultisigs[addr] = msigInfo{ + Balance: types.FIL(act.Balance), + Signers: st.Signers, + Threshold: st.NumApprovalsThreshold, + } + msigAddrs = append(msigAddrs, addr) + case builtin.AccountActorCodeID: + var st saacc.State + if err := cst.Get(ctx, act.Head, &st); err != nil { + log.Warn(xerrors.Errorf("account actor %s: %w", addr, err)) + return nil + } + + kaccounts[addr] = addrInfo{ + Key: st.Address, + Balance: types.FIL(act.Balance.Copy()), + } + accAddrs = append(accAddrs, addr) + } + return nil + }); err != nil { + return err + } + + sort.Slice(accAddrs, func(i, j int) bool { + return accAddrs[i].String() < accAddrs[j].String() + }) + + sort.Slice(msigAddrs, func(i, j int) bool { + return msigAddrs[i].String() < msigAddrs[j].String() + }) + + fmt.Println("Account Actors:") + for _, acc := range accAddrs { + a := kaccounts[acc] + fmt.Printf("%s\t%s\t%s\n", acc, a.Key, a.Balance) + } + + fmt.Println("Multisig Actors:") + for _, acc := range msigAddrs { + m := kmultisigs[acc] + fmt.Printf("%s\t%s\t%d\t[", acc, m.Balance, m.Threshold) + for i, s := range m.Signers { + fmt.Print(s) + if i != len(m.Signers)-1 { + fmt.Print(",") + } + } + fmt.Printf("]\n") + } return nil }, } From aa2cad1a666da6da80b23e7449df454cfe33e530 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Mon, 24 Aug 2020 08:41:43 -0700 Subject: [PATCH 069/247] small usability tweak, fix lint --- cli/mpool.go | 2 +- cmd/lotus-shed/genesis-verify.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/cli/mpool.go b/cli/mpool.go index 5f8ccd8f7..d508c93fe 100644 --- a/cli/mpool.go +++ b/cli/mpool.go @@ -106,7 +106,7 @@ var mpoolClear = &cli.Command{ really := cctx.Bool("really-do-it") if !really { - return fmt.Errorf("the --really-do-it flag must be specified for this action to have an effect; you have been warned") + return fmt.Errorf("--really-do-it must be specified for this action to have an effect; you have been warned") } local := cctx.Bool("local") diff --git a/cmd/lotus-shed/genesis-verify.go b/cmd/lotus-shed/genesis-verify.go index 92915102a..3d6868537 100644 --- a/cmd/lotus-shed/genesis-verify.go +++ b/cmd/lotus-shed/genesis-verify.go @@ -117,7 +117,6 @@ var genesisVerifyCmd = &cli.Command{ var st saacc.State if err := cst.Get(ctx, act.Head, &st); err != nil { log.Warn(xerrors.Errorf("account actor %s: %w", addr, err)) - return nil } kaccounts[addr] = addrInfo{ From 90337995ffd4907d65c88e2fae8d1e5a88f1be7d Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Mon, 24 Aug 2020 11:31:17 -0700 Subject: [PATCH 070/247] print out genesis cid --- cmd/lotus-shed/genesis-verify.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/lotus-shed/genesis-verify.go b/cmd/lotus-shed/genesis-verify.go index 3d6868537..4ab6458a9 100644 --- a/cmd/lotus-shed/genesis-verify.go +++ b/cmd/lotus-shed/genesis-verify.go @@ -62,8 +62,6 @@ var genesisVerifyCmd = &cli.Command{ return err } - fmt.Println("File loaded, now verifying state tree balances...") - sm := stmgr.NewStateManager(cs) total, err := stmgr.CheckTotalFIL(context.TODO(), sm, ts) @@ -71,6 +69,7 @@ var genesisVerifyCmd = &cli.Command{ return err } + fmt.Println("Genesis: ", ts.Key()) expFIL := big.Mul(big.NewInt(int64(build.FilBase)), big.NewInt(int64(build.FilecoinPrecision))) fmt.Printf("Total FIL: %s", types.FIL(total)) if !expFIL.Equals(total) { From e4e0f472f93bce8738a9926c0f6e2abd32b196d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Mon, 24 Aug 2020 23:37:23 +0200 Subject: [PATCH 071/247] build: Bump versions to 0.5.2 --- build/version.go | 4 ++-- documentation/en/api-methods.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/version.go b/build/version.go index de4102f5c..70439d4f7 100644 --- a/build/version.go +++ b/build/version.go @@ -25,7 +25,7 @@ func buildType() string { } // BuildVersion is the local build version, set by build system -const BuildVersion = "0.4.6" +const BuildVersion = "0.5.2" func UserVersion() string { return BuildVersion + buildType() + CurrentCommit @@ -53,7 +53,7 @@ func (ve Version) EqMajorMinor(v2 Version) bool { } // APIVersion is a semver version of the rpc api exposed -var APIVersion Version = newVer(0, 11, 0) +var APIVersion Version = newVer(0, 12, 0) //nolint:varcheck,deadcode const ( diff --git a/documentation/en/api-methods.md b/documentation/en/api-methods.md index 89eb2b944..bd395fc3e 100644 --- a/documentation/en/api-methods.md +++ b/documentation/en/api-methods.md @@ -197,7 +197,7 @@ Response: ```json { "Version": "string value", - "APIVersion": 2816, + "APIVersion": 3072, "BlockDelay": 42 } ``` From aacfcba40067f7c1a70e19f05b90baf422b7eafc Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 25 Aug 2020 01:01:16 +0200 Subject: [PATCH 072/247] Check ValidForBlockInclusion in mpool Signed-off-by: Jakub Sztandera --- chain/messagepool/messagepool.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 644a9104f..5816bae28 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -317,6 +317,10 @@ func (mp *MessagePool) checkMessage(m *types.SignedMessage) error { return xerrors.Errorf("mpool message too large (%dB): %w", m.Size(), ErrMessageTooBig) } + if err := m.Message.ValidForBlockInclusion(0); err != nil { + return xerrors.Errorf("message not valid for block inclusion: %d", err) + } + if m.Message.To == address.Undef { return ErrInvalidToAddr } From cf3298cd048b78e3fbac0289a3f75496a780e002 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Mon, 24 Aug 2020 17:21:03 -0700 Subject: [PATCH 073/247] more correctly handle discrepancies between mempools head and the mining base --- chain/messagepool/messagepool.go | 68 +++++++++++++++++++++++++++ chain/messagepool/selection.go | 81 ++++---------------------------- chain/store/store.go | 9 +++- 3 files changed, 84 insertions(+), 74 deletions(-) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 5816bae28..b7b012806 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -27,6 +27,7 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/lib/sigs" @@ -880,6 +881,73 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet) return merr } +func (mp *MessagePool) runHeadChange(from *types.TipSet, to *types.TipSet, rmsgs map[address.Address]map[uint64]*types.SignedMessage) error { + add := func(m *types.SignedMessage) { + s, ok := rmsgs[m.Message.From] + if !ok { + s = make(map[uint64]*types.SignedMessage) + rmsgs[m.Message.From] = s + } + s[m.Message.Nonce] = m + } + rm := func(from address.Address, nonce uint64) { + s, ok := rmsgs[from] + if !ok { + return + } + + if _, ok := s[nonce]; ok { + delete(s, nonce) + return + } + + } + + revert, apply, err := store.ReorgOps(mp.api.LoadTipSet, from, to) + if err != nil { + return xerrors.Errorf("failed to compute reorg ops for mpool pending messages: %w", err) + } + + var merr error + + for _, ts := range revert { + msgs, err := mp.MessagesForBlocks(ts.Blocks()) + if err != nil { + log.Errorf("error retrieving messages for reverted block: %s", err) + merr = multierror.Append(merr, err) + continue + } + + for _, msg := range msgs { + add(msg) + } + } + + for _, ts := range apply { + mp.curTs = ts + + for _, b := range ts.Blocks() { + bmsgs, smsgs, err := mp.api.MessagesForBlock(b) + if err != nil { + xerr := xerrors.Errorf("failed to get messages for apply block %s(height %d) (msgroot = %s): %w", b.Cid(), b.Height, b.Messages, err) + log.Errorf("error retrieving messages for block: %s", xerr) + merr = multierror.Append(merr, xerr) + continue + } + + for _, msg := range smsgs { + rm(msg.Message.From, msg.Message.Nonce) + } + + for _, msg := range bmsgs { + rm(msg.From, msg.Nonce) + } + } + } + + return merr +} + type statBucket struct { msgs map[uint64]*types.SignedMessage } diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index aeb80d53d..0cc9545cb 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -14,7 +14,6 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" abig "github.com/filecoin-project/specs-actors/actors/abi/big" - "github.com/ipfs/go-cid" ) var bigBlockGasLimit = big.NewInt(build.BlockGasLimit) @@ -528,7 +527,6 @@ func (mp *MessagePool) getPendingMessages(curTs, ts *types.TipSet) (map[address. start := time.Now() result := make(map[address.Address]map[uint64]*types.SignedMessage) - haveCids := make(map[cid.Cid]struct{}) defer func() { if dt := time.Since(start); dt > time.Millisecond { log.Infow("get pending messages done", "took", dt) @@ -554,10 +552,6 @@ func (mp *MessagePool) getPendingMessages(curTs, ts *types.TipSet) (map[address. } result[a] = msetCopy - // mark the messages as seen - for _, m := range mset.msgs { - haveCids[m.Cid()] = struct{}{} - } } } @@ -566,72 +560,11 @@ func (mp *MessagePool) getPendingMessages(curTs, ts *types.TipSet) (map[address. return result, nil } - // nope, we need to sync the tipsets - for { - if curTs.Height() == ts.Height() { - if curTs.Equals(ts) { - return result, nil - } - - // different blocks in tipsets -- we mark them as seen so that they are not included in - // in the message set we return, but *neither me (vyzo) nor why understand why* - // this code is also probably completely untested in production, so I am adding a big fat - // warning to revisit this case and sanity check this decision. - log.Warnf("mpool tipset has same height as target tipset but it's not equal; beware of dragons!") - - have, err := mp.MessagesForBlocks(ts.Blocks()) - if err != nil { - return nil, xerrors.Errorf("error retrieving messages for tipset: %w", err) - } - - for _, m := range have { - haveCids[m.Cid()] = struct{}{} - } - } - - msgs, err := mp.MessagesForBlocks(ts.Blocks()) - if err != nil { - return nil, xerrors.Errorf("error retrieving messages for tipset: %w", err) - } - - for _, m := range msgs { - if _, have := haveCids[m.Cid()]; have { - continue - } - - haveCids[m.Cid()] = struct{}{} - mset, ok := result[m.Message.From] - if !ok { - mset = make(map[uint64]*types.SignedMessage) - result[m.Message.From] = mset - } - - other, dupNonce := mset[m.Message.Nonce] - if dupNonce { - // duplicate nonce, selfishly keep the message with the highest GasPrice - // if the gas prices are the same, keep the one with the highest GasLimit - switch m.Message.GasPremium.Int.Cmp(other.Message.GasPremium.Int) { - case 0: - if m.Message.GasLimit > other.Message.GasLimit { - mset[m.Message.Nonce] = m - } - case 1: - mset[m.Message.Nonce] = m - } - } else { - mset[m.Message.Nonce] = m - } - } - - if curTs.Height() >= ts.Height() { - return result, nil - } - - ts, err = mp.api.LoadTipSet(ts.Parents()) - if err != nil { - return nil, xerrors.Errorf("error loading parent tipset: %w", err) - } + if err := mp.runHeadChange(curTs, ts, result); err != nil { + return nil, xerrors.Errorf("failed to process difference between mpool head and given head: %w", err) } + + return result, nil } func (mp *MessagePool) getGasReward(msg *types.SignedMessage, baseFee types.BigInt, ts *types.TipSet) *big.Int { @@ -671,7 +604,11 @@ func (mp *MessagePool) createMessageChains(actor address.Address, mset map[uint6 // cannot exceed the block limit; drop all messages that exceed the limit // - the total gasReward cannot exceed the actor's balance; drop all messages that exceed // the balance - a, _ := mp.api.StateGetActor(actor, ts) + a, err := mp.api.StateGetActor(actor, ts) + if err != nil { + panic(err) // TODO + } + curNonce := a.Nonce balance := a.Balance.Int gasLimit := int64(0) diff --git a/chain/store/store.go b/chain/store/store.go index 139444f67..b71e7d4df 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -483,6 +483,10 @@ func (cs *ChainStore) NearestCommonAncestor(a, b *types.TipSet) (*types.TipSet, } func (cs *ChainStore) ReorgOps(a, b *types.TipSet) ([]*types.TipSet, []*types.TipSet, error) { + return ReorgOps(cs.LoadTipSet, a, b) +} + +func ReorgOps(lts func(types.TipSetKey) (*types.TipSet, error), a, b *types.TipSet) ([]*types.TipSet, []*types.TipSet, error) { left := a right := b @@ -490,7 +494,7 @@ func (cs *ChainStore) ReorgOps(a, b *types.TipSet) ([]*types.TipSet, []*types.Ti for !left.Equals(right) { if left.Height() > right.Height() { leftChain = append(leftChain, left) - par, err := cs.LoadTipSet(left.Parents()) + par, err := lts(left.Parents()) if err != nil { return nil, nil, err } @@ -498,7 +502,7 @@ func (cs *ChainStore) ReorgOps(a, b *types.TipSet) ([]*types.TipSet, []*types.Ti left = par } else { rightChain = append(rightChain, right) - par, err := cs.LoadTipSet(right.Parents()) + par, err := lts(right.Parents()) if err != nil { log.Infof("failed to fetch right.Parents: %s", err) return nil, nil, err @@ -509,6 +513,7 @@ func (cs *ChainStore) ReorgOps(a, b *types.TipSet) ([]*types.TipSet, []*types.Ti } return leftChain, rightChain, nil + } // GetHeaviestTipSet returns the current heaviest tipset known (i.e. our head). From 05d65c3f887a351845629e99fe9808d24835f935 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Mon, 24 Aug 2020 17:40:12 -0700 Subject: [PATCH 074/247] slightly better than panicking --- chain/messagepool/selection.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 0cc9545cb..ab0326896 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -606,7 +606,8 @@ func (mp *MessagePool) createMessageChains(actor address.Address, mset map[uint6 // the balance a, err := mp.api.StateGetActor(actor, ts) if err != nil { - panic(err) // TODO + log.Errorf("failed to load actor state, not building chain for %s: %w", actor, err) + return nil } curNonce := a.Nonce From d921791c55ca1977937ecaa16b45a742c1ab27d6 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 25 Aug 2020 03:13:43 +0200 Subject: [PATCH 075/247] Add comment Signed-off-by: Jakub Sztandera --- chain/messagepool/messagepool.go | 1 + 1 file changed, 1 insertion(+) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index b7b012806..32a91ad9e 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -318,6 +318,7 @@ func (mp *MessagePool) checkMessage(m *types.SignedMessage) error { return xerrors.Errorf("mpool message too large (%dB): %w", m.Size(), ErrMessageTooBig) } + // Perform syntaxtic validation, minGas=0 as we check if correctly in select messages if err := m.Message.ValidForBlockInclusion(0); err != nil { return xerrors.Errorf("message not valid for block inclusion: %d", err) } From b2ff231c4882c1e4927ab45120d0a5a173cf9a71 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 25 Aug 2020 03:14:52 +0200 Subject: [PATCH 076/247] Fix error fmt string Signed-off-by: Jakub Sztandera --- chain/messagepool/messagepool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 32a91ad9e..6163239e3 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -320,7 +320,7 @@ func (mp *MessagePool) checkMessage(m *types.SignedMessage) error { // Perform syntaxtic validation, minGas=0 as we check if correctly in select messages if err := m.Message.ValidForBlockInclusion(0); err != nil { - return xerrors.Errorf("message not valid for block inclusion: %d", err) + return xerrors.Errorf("message not valid for block inclusion: %w", err) } if m.Message.To == address.Undef { From 33b12782e4d7c9151cdeb1333c2b5393a3a6eb35 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 25 Aug 2020 04:02:06 +0200 Subject: [PATCH 077/247] Take into account messages in current tispet by executing it Signed-off-by: Jakub Sztandera --- chain/messagepool/messagepool.go | 35 +++---------------- chain/messagepool/messagepool_test.go | 48 ++++++++++++++++++++++----- chain/messagepool/provider.go | 11 ++++-- chain/messagepool/selection.go | 2 +- chain/messagepool/selection_test.go | 14 ++++---- 5 files changed, 61 insertions(+), 49 deletions(-) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 6163239e3..b421f7739 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -505,42 +505,16 @@ func (mp *MessagePool) getNonceLocked(addr address.Address, curTs *types.TipSet) } func (mp *MessagePool) getStateNonce(addr address.Address, curTs *types.TipSet) (uint64, error) { - // TODO: this method probably should be cached - - act, err := mp.api.StateGetActor(addr, curTs) + act, err := mp.api.GetActorAfter(addr, curTs) if err != nil { return 0, err } - baseNonce := act.Nonce - - // TODO: the correct thing to do here is probably to set curTs to chain.head - // but since we have an accurate view of the world until a head change occurs, - // this should be fine - if curTs == nil { - return baseNonce, nil - } - - msgs, err := mp.api.MessagesForTipset(curTs) - if err != nil { - return 0, xerrors.Errorf("failed to check messages for tipset: %w", err) - } - - for _, m := range msgs { - msg := m.VMMessage() - if msg.From == addr { - if msg.Nonce != baseNonce { - return 0, xerrors.Errorf("tipset %s has bad nonce ordering (%d != %d)", curTs.Cids(), msg.Nonce, baseNonce) - } - baseNonce++ - } - } - - return baseNonce, nil + return act.Nonce, nil } func (mp *MessagePool) getStateBalance(addr address.Address, ts *types.TipSet) (types.BigInt, error) { - act, err := mp.api.StateGetActor(addr, ts) + act, err := mp.api.GetActorAfter(addr, ts) if err != nil { return types.EmptyInt, err } @@ -832,7 +806,8 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet) } for a, bkt := range buckets { - act, err := mp.api.StateGetActor(a, ts) + // TODO that might not be correct with GatActorAfter but it is only debug code + act, err := mp.api.GetActorAfter(a, ts) if err != nil { log.Debugf("%s, err: %s\n", a, err) continue diff --git a/chain/messagepool/messagepool_test.go b/chain/messagepool/messagepool_test.go index 35e21f817..8fae79fa2 100644 --- a/chain/messagepool/messagepool_test.go +++ b/chain/messagepool/messagepool_test.go @@ -3,6 +3,7 @@ package messagepool import ( "context" "fmt" + "sort" "testing" "github.com/filecoin-project/go-address" @@ -33,11 +34,18 @@ type testMpoolAPI struct { } func newTestMpoolAPI() *testMpoolAPI { - return &testMpoolAPI{ + tma := &testMpoolAPI{ bmsgs: make(map[cid.Cid][]*types.SignedMessage), statenonce: make(map[address.Address]uint64), balance: make(map[address.Address]types.BigInt), } + genesis := mock.MkBlock(nil, 1, 1) + tma.setBlockMessages(genesis) + return tma +} + +func (tma *testMpoolAPI) nextBlock() *types.BlockHeader { + return mock.MkBlock(tma.tipsets[len(tma.tipsets)-1], 1, 1) } func (tma *testMpoolAPI) applyBlock(t *testing.T, b *types.BlockHeader) { @@ -73,7 +81,7 @@ func (tma *testMpoolAPI) setBlockMessages(h *types.BlockHeader, msgs ...*types.S func (tma *testMpoolAPI) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) *types.TipSet { tma.cb = cb - return nil + return tma.tipsets[0] } func (tma *testMpoolAPI) PutMessage(m types.ChainMsg) (cid.Cid, error) { @@ -84,15 +92,38 @@ func (tma *testMpoolAPI) PubSubPublish(string, []byte) error { return nil } -func (tma *testMpoolAPI) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) { +func (tma *testMpoolAPI) GetActorAfter(addr address.Address, ts *types.TipSet) (*types.Actor, error) { balance, ok := tma.balance[addr] if !ok { balance = types.NewInt(1000e6) tma.balance[addr] = balance } + + msgs := make([]*types.SignedMessage, 0) + for _, b := range ts.Blocks() { + for _, m := range tma.bmsgs[b.Cid()] { + if m.Message.From == addr { + msgs = append(msgs, m) + } + } + } + + sort.Slice(msgs, func(i, j int) bool { + return msgs[i].Message.Nonce < msgs[j].Message.Nonce + }) + + nonce := tma.statenonce[addr] + + for _, m := range msgs { + if m.Message.Nonce != nonce { + break + } + nonce++ + } + return &types.Actor{ Code: builtin.StorageMarketActorCodeID, - Nonce: tma.statenonce[addr], + Nonce: nonce, Balance: balance, }, nil } @@ -178,7 +209,7 @@ func TestMessagePool(t *testing.T) { t.Fatal(err) } - a := mock.MkBlock(nil, 1, 1) + a := tma.nextBlock() sender, err := w.GenerateKey(crypto.SigTypeBLS) if err != nil { @@ -219,8 +250,8 @@ func TestRevertMessages(t *testing.T) { t.Fatal(err) } - a := mock.MkBlock(nil, 1, 1) - b := mock.MkBlock(mock.TipSet(a), 1, 1) + a := tma.nextBlock() + b := tma.nextBlock() sender, err := w.GenerateKey(crypto.SigTypeBLS) if err != nil { @@ -254,6 +285,7 @@ func TestRevertMessages(t *testing.T) { assertNonce(t, mp, sender, 4) p, _ := mp.Pending() + fmt.Printf("%+v\n", p) if len(p) != 3 { t.Fatal("expected three messages in mempool") } @@ -275,7 +307,7 @@ func TestPruningSimple(t *testing.T) { t.Fatal(err) } - a := mock.MkBlock(nil, 1, 1) + a := tma.nextBlock() tma.applyBlock(t, a) sender, err := w.GenerateKey(crypto.SigTypeBLS) diff --git a/chain/messagepool/provider.go b/chain/messagepool/provider.go index fa8b8ea83..80b9a4297 100644 --- a/chain/messagepool/provider.go +++ b/chain/messagepool/provider.go @@ -16,7 +16,7 @@ type Provider interface { SubscribeHeadChanges(func(rev, app []*types.TipSet) error) *types.TipSet PutMessage(m types.ChainMsg) (cid.Cid, error) PubSubPublish(string, []byte) error - StateGetActor(address.Address, *types.TipSet) (*types.Actor, error) + GetActorAfter(address.Address, *types.TipSet) (*types.Actor, error) StateAccountKey(context.Context, address.Address, *types.TipSet) (address.Address, error) MessagesForBlock(*types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) MessagesForTipset(*types.TipSet) ([]types.ChainMsg, error) @@ -46,9 +46,14 @@ func (mpp *mpoolProvider) PubSubPublish(k string, v []byte) error { return mpp.ps.Publish(k, v) //nolint } -func (mpp *mpoolProvider) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) { +func (mpp *mpoolProvider) GetActorAfter(addr address.Address, ts *types.TipSet) (*types.Actor, error) { var act types.Actor - return &act, mpp.sm.WithParentState(ts, mpp.sm.WithActor(addr, stmgr.GetActor(&act))) + stcid, _, err := mpp.sm.TipSetState(context.TODO(), ts) + if err != nil { + return nil, xerrors.Errorf("computing tipset state for GetActor: %w", err) + } + + return &act, mpp.sm.WithStateTree(stcid, mpp.sm.WithActor(addr, stmgr.GetActor(&act))) } func (mpp *mpoolProvider) StateAccountKey(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index ab0326896..b39eb01cb 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -604,7 +604,7 @@ func (mp *MessagePool) createMessageChains(actor address.Address, mset map[uint6 // cannot exceed the block limit; drop all messages that exceed the limit // - the total gasReward cannot exceed the actor's balance; drop all messages that exceed // the balance - a, err := mp.api.StateGetActor(actor, ts) + a, err := mp.api.GetActorAfter(actor, ts) if err != nil { log.Errorf("failed to load actor state, not building chain for %s: %w", actor, err) return nil diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index 0032db23c..f5c947954 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -464,7 +464,7 @@ func TestBasicMessageSelection(t *testing.T) { // now create another set of messages and add them to the mpool for i := 20; i < 30; i++ { - m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(2*i+1)) + m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(2*i+200)) mustAdd(t, mp, m) m = makeTestMessage(w2, a2, a1, uint64(i), gasLimit, uint64(i+1)) mustAdd(t, mp, m) @@ -480,12 +480,12 @@ func TestBasicMessageSelection(t *testing.T) { if err != nil { t.Fatal(err) } - if len(msgs) != 40 { - t.Fatalf("expected 40 messages, got %d", len(msgs)) + if len(msgs) != 20 { + t.Fatalf("expected 20 messages, got %d", len(msgs)) } - nextNonce = 10 - for i := 0; i < 20; i++ { + nextNonce = 20 + for i := 0; i < 10; i++ { if msgs[i].Message.From != a1 { t.Fatalf("expected message from actor a1") } @@ -495,8 +495,8 @@ func TestBasicMessageSelection(t *testing.T) { nextNonce++ } - nextNonce = 10 - for i := 20; i < 40; i++ { + nextNonce = 20 + for i := 10; i < 20; i++ { if msgs[i].Message.From != a2 { t.Fatalf("expected message from actor a2") } From 7f427b80011d9bf90bf92b0dd1b57d5472843492 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 25 Aug 2020 04:12:33 +0200 Subject: [PATCH 078/247] Fix harness weirdness Signed-off-by: Jakub Sztandera --- chain/messagepool/messagepool_test.go | 7 ++++--- chain/messagepool/selection_test.go | 25 ++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/chain/messagepool/messagepool_test.go b/chain/messagepool/messagepool_test.go index 8fae79fa2..8b82baffa 100644 --- a/chain/messagepool/messagepool_test.go +++ b/chain/messagepool/messagepool_test.go @@ -40,12 +40,14 @@ func newTestMpoolAPI() *testMpoolAPI { balance: make(map[address.Address]types.BigInt), } genesis := mock.MkBlock(nil, 1, 1) - tma.setBlockMessages(genesis) + tma.tipsets = append(tma.tipsets, mock.TipSet(genesis)) return tma } func (tma *testMpoolAPI) nextBlock() *types.BlockHeader { - return mock.MkBlock(tma.tipsets[len(tma.tipsets)-1], 1, 1) + newBlk := mock.MkBlock(tma.tipsets[len(tma.tipsets)-1], 1, 1) + tma.tipsets = append(tma.tipsets, mock.TipSet(newBlk)) + return newBlk } func (tma *testMpoolAPI) applyBlock(t *testing.T, b *types.BlockHeader) { @@ -76,7 +78,6 @@ func (tma *testMpoolAPI) setBalanceRaw(addr address.Address, v types.BigInt) { func (tma *testMpoolAPI) setBlockMessages(h *types.BlockHeader, msgs ...*types.SignedMessage) { tma.bmsgs[h.Cid()] = msgs - tma.tipsets = append(tma.tipsets, mock.TipSet(h)) } func (tma *testMpoolAPI) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) *types.TipSet { diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index f5c947954..2e7692213 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -79,7 +79,7 @@ func TestMessageChains(t *testing.T) { t.Fatal(err) } - block := mock.MkBlock(nil, 1, 1) + block := tma.nextBlock() ts := mock.TipSet(block) gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin.StorageMarketActorCodeID, M: 2}] @@ -317,7 +317,7 @@ func TestMessageChainSkipping(t *testing.T) { t.Fatal(err) } - block := mock.MkBlock(nil, 1, 1) + block := tma.nextBlock() ts := mock.TipSet(block) gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin.StorageMarketActorCodeID, M: 2}] @@ -387,7 +387,7 @@ func TestBasicMessageSelection(t *testing.T) { t.Fatal(err) } - block := mock.MkBlock(nil, 1, 1) + block := tma.nextBlock() ts := mock.TipSet(block) tma.applyBlock(t, block) @@ -440,12 +440,12 @@ func TestBasicMessageSelection(t *testing.T) { } // now we make a block with all the messages and advance the chain - block2 := mock.MkBlock(ts, 2, 2) + block2 := tma.nextBlock() tma.setBlockMessages(block2, msgs...) tma.applyBlock(t, block2) // we should have no pending messages in the mpool - pend, ts2 := mp.Pending() + pend, _ := mp.Pending() if len(pend) != 0 { t.Fatalf("expected no pending messages, but got %d", len(pend)) } @@ -458,7 +458,7 @@ func TestBasicMessageSelection(t *testing.T) { m = makeTestMessage(w2, a2, a1, uint64(i), gasLimit, uint64(i+1)) msgs = append(msgs, m) } - block3 := mock.MkBlock(ts2, 3, 3) + block3 := tma.nextBlock() tma.setBlockMessages(block3, msgs...) ts3 := mock.TipSet(block3) @@ -531,7 +531,7 @@ func TestMessageSelectionTrimming(t *testing.T) { t.Fatal(err) } - block := mock.MkBlock(nil, 1, 1) + block := tma.nextBlock() ts := mock.TipSet(block) tma.applyBlock(t, block) @@ -594,7 +594,7 @@ func TestPriorityMessageSelection(t *testing.T) { t.Fatal(err) } - block := mock.MkBlock(nil, 1, 1) + block := tma.nextBlock() ts := mock.TipSet(block) tma.applyBlock(t, block) @@ -676,7 +676,7 @@ func TestOptimalMessageSelection1(t *testing.T) { t.Fatal(err) } - block := mock.MkBlock(nil, 1, 1) + block := tma.nextBlock() ts := mock.TipSet(block) tma.applyBlock(t, block) @@ -743,7 +743,7 @@ func TestOptimalMessageSelection2(t *testing.T) { t.Fatal(err) } - block := mock.MkBlock(nil, 1, 1) + block := tma.nextBlock() ts := mock.TipSet(block) tma.applyBlock(t, block) @@ -821,7 +821,7 @@ func TestOptimalMessageSelection3(t *testing.T) { wallets = append(wallets, w) } - block := mock.MkBlock(nil, 1, 1) + block := tma.nextBlock() ts := mock.TipSet(block) tma.applyBlock(t, block) @@ -879,7 +879,6 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu // actors send with an randomly distributed premium dictated by the getPremium function. // a number of miners select with varying ticket quality and we compare the // capacity and rewards of greedy selection -vs- optimal selection - mp, tma := makeTestMpool() nActors := 300 @@ -902,7 +901,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu wallets = append(wallets, w) } - block := mock.MkBlock(nil, 1, 1) + block := tma.nextBlock() ts := mock.TipSet(block) tma.applyBlock(t, block) From a5c56dde107e67346b5fc930d3854d1804f98265 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Mon, 24 Aug 2020 19:35:54 -0700 Subject: [PATCH 079/247] add test to verify actor state fix works properly --- chain/messagepool/messagepool_test.go | 45 +++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/chain/messagepool/messagepool_test.go b/chain/messagepool/messagepool_test.go index 8b82baffa..cdc92630a 100644 --- a/chain/messagepool/messagepool_test.go +++ b/chain/messagepool/messagepool_test.go @@ -236,6 +236,51 @@ func TestMessagePool(t *testing.T) { assertNonce(t, mp, sender, 2) } +func TestMessagePoolMessagesInEachBlock(t *testing.T) { + tma := newTestMpoolAPI() + + w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + ds := datastore.NewMapDatastore() + + mp, err := New(tma, ds, "mptest") + if err != nil { + t.Fatal(err) + } + + a := tma.nextBlock() + + sender, err := w.GenerateKey(crypto.SigTypeBLS) + if err != nil { + t.Fatal(err) + } + target := mock.Address(1001) + + var msgs []*types.SignedMessage + for i := 0; i < 5; i++ { + m := mock.MkMessage(sender, target, uint64(i), w) + msgs = append(msgs, m) + mustAdd(t, mp, m) + } + + tma.setStateNonce(sender, 0) + + tma.setBlockMessages(a, msgs[0], msgs[1]) + tma.applyBlock(t, a) + tsa := mock.TipSet(a) + + all, _ := mp.Pending() + fmt.Println("pending: ", all) + + selm, _ := mp.SelectMessages(tsa, 1) + if len(selm) == 0 { + t.Fatal("should have returned the rest of the messages") + } +} + func TestRevertMessages(t *testing.T) { tma := newTestMpoolAPI() From 8cc8a277a1b28f3f9a5310e24cdde5734e5d8510 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 25 Aug 2020 04:37:35 +0200 Subject: [PATCH 080/247] Remove Println Signed-off-by: Jakub Sztandera --- chain/messagepool/messagepool_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/chain/messagepool/messagepool_test.go b/chain/messagepool/messagepool_test.go index cdc92630a..baf734a92 100644 --- a/chain/messagepool/messagepool_test.go +++ b/chain/messagepool/messagepool_test.go @@ -272,8 +272,7 @@ func TestMessagePoolMessagesInEachBlock(t *testing.T) { tma.applyBlock(t, a) tsa := mock.TipSet(a) - all, _ := mp.Pending() - fmt.Println("pending: ", all) + _, _ = mp.Pending() selm, _ := mp.SelectMessages(tsa, 1) if len(selm) == 0 { From ec4146642dcdfd3c67c3dcda9f8b31fe04cbba06 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Mon, 24 Aug 2020 20:25:06 -0700 Subject: [PATCH 081/247] 0.5.2 release of lotus --- CHANGELOG.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ece1f18a2..ed24229e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Lotus changelog +# 0.5.2 / 2020-08-24 + +This is a hotfix release. + +- Fix message selection to not include messages that are invalid for block + inclusion. +- Improve SelectMessage handling of the case where the message pools tipset + differs from our mining base. + +# 0.5.1 / 2020-08-24 + +The Space Race release! +This release contains the genesis car file and bootstrap peers for the space +race network. + +Additionally, we included two small fixes to genesis creation: +- Randomize ticket value in genesis generation +- Correctly set t099 (burnt funds actor) to have valid account actor state + # 0.5.0 / 2020-08-20 This version of Lotus will be used for the incentivized testnet Space Race competition, From fb033a3719baa8a2a37b186ce3f685b3445377ee Mon Sep 17 00:00:00 2001 From: Travis Person Date: Tue, 25 Aug 2020 05:10:12 +0000 Subject: [PATCH 082/247] lotus-fountain: remove make miner workflow --- cmd/lotus-fountain/main.go | 245 ---------------------------- cmd/lotus-fountain/site/_miner.html | 51 ------ cmd/lotus-fountain/site/index.html | 3 - cmd/lotus-fountain/site/wait.html | 69 -------- documentation/en/mining.md | 20 --- 5 files changed, 388 deletions(-) delete mode 100644 cmd/lotus-fountain/site/_miner.html delete mode 100644 cmd/lotus-fountain/site/wait.html diff --git a/cmd/lotus-fountain/main.go b/cmd/lotus-fountain/main.go index 021335cc3..cfb498ac9 100644 --- a/cmd/lotus-fountain/main.go +++ b/cmd/lotus-fountain/main.go @@ -1,77 +1,28 @@ package main import ( - "bytes" "context" "fmt" - "html/template" - "io" - "io/ioutil" "net" "net/http" "os" - "sort" - "strconv" "time" rice "github.com/GeertJohan/go.rice" - "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" "github.com/libp2p/go-libp2p-core/peer" "github.com/urfave/cli/v2" "golang.org/x/xerrors" - "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" ) var log = logging.Logger("main") -var supportedSectors struct { - SectorSizes []struct { - Name string - Value uint64 - Default bool - } -} - -func init() { - for supportedSector := range miner.SupportedProofTypes { - sectorSize, err := supportedSector.SectorSize() - if err != nil { - panic(err) - } - - supportedSectors.SectorSizes = append(supportedSectors.SectorSizes, struct { - Name string - Value uint64 - Default bool - }{ - Name: sectorSize.ShortString(), - Value: uint64(sectorSize), - Default: false, - }) - - } - - sort.Slice(supportedSectors.SectorSizes[:], func(i, j int) bool { - return supportedSectors.SectorSizes[i].Value < supportedSectors.SectorSizes[j].Value - }) - - supportedSectors.SectorSizes[0].Default = true -} - func main() { logging.SetLogLevel("*", "INFO") @@ -144,11 +95,6 @@ var runCmd = &cli.Command{ return xerrors.Errorf("parsing source address (provide correct --from flag!): %w", err) } - defaultMinerPeer, err := peer.Decode("12D3KooWJpBNhwgvoZ15EB1JwRTRpxgM9D2fwq6eEktrJJG74aP6") - if err != nil { - return err - } - h := &handler{ ctx: ctx, api: nodeApi, @@ -162,23 +108,10 @@ var runCmd = &cli.Command{ WalletRate: 15 * time.Minute, WalletBurst: 2, }), - minerLimiter: NewLimiter(LimiterConfig{ - TotalRate: 500 * time.Millisecond, - TotalBurst: build.BlockMessageLimit, - IPRate: 10 * time.Minute, - IPBurst: 2, - WalletRate: 1 * time.Hour, - WalletBurst: 2, - }), - defaultMinerPeer: defaultMinerPeer, } http.Handle("/", http.FileServer(rice.MustFindBox("site").HTTPBox())) - http.HandleFunc("/miner.html", h.minerhtml) http.HandleFunc("/send", h.send) - http.HandleFunc("/mkminer", h.mkminer) - http.HandleFunc("/msgwait", h.msgwait) - http.HandleFunc("/msgwaitaddr", h.msgwaitaddr) fmt.Printf("Open http://%s\n", cctx.String("front")) @@ -204,37 +137,6 @@ type handler struct { defaultMinerPeer peer.ID } -func (h *handler) minerhtml(w http.ResponseWriter, r *http.Request) { - f, err := rice.MustFindBox("site").Open("_miner.html") - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - tmpl, err := ioutil.ReadAll(f) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - var executedTmpl bytes.Buffer - - t, err := template.New("miner.html").Parse(string(tmpl)) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - } - if err := t.Execute(&executedTmpl, supportedSectors); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - if _, err := io.Copy(w, &executedTmpl); err != nil { - log.Errorf("failed to write template to string %s", err) - } - - return -} - func (h *handler) send(w http.ResponseWriter, r *http.Request) { to, err := address.NewFromString(r.FormValue("address")) if err != nil { @@ -287,150 +189,3 @@ func (h *handler) send(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(smsg.Cid().String())) } - -func (h *handler) mkminer(w http.ResponseWriter, r *http.Request) { - owner, err := address.NewFromString(r.FormValue("address")) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - if owner.Protocol() != address.BLS { - http.Error(w, - "Miner address must use BLS. A BLS address starts with the prefix 't3'."+ - "Please create a BLS address by running \"lotus wallet new bls\" while connected to a Lotus node.", - http.StatusBadRequest) - return - } - - ssize, err := strconv.ParseInt(r.FormValue("sectorSize"), 10, 64) - if err != nil { - return - } - - log.Infof("%s: create actor start", owner) - - // Limit based on wallet address - limiter := h.minerLimiter.GetWalletLimiter(owner.String()) - if !limiter.Allow() { - http.Error(w, http.StatusText(http.StatusTooManyRequests)+": wallet limit", http.StatusTooManyRequests) - return - } - - // Limit based on IP - reqIP := r.Header.Get("X-Real-IP") - if reqIP == "" { - h, _, err := net.SplitHostPort(r.RemoteAddr) - if err != nil { - log.Errorf("could not get ip from: %s, err: %s", r.RemoteAddr, err) - } - reqIP = h - } - limiter = h.minerLimiter.GetIPLimiter(reqIP) - if !limiter.Allow() { - http.Error(w, http.StatusText(http.StatusTooManyRequests)+": IP limit", http.StatusTooManyRequests) - return - } - - // General limiter owner allow throttling all messages that can make it into the mpool - if !h.minerLimiter.Allow() { - http.Error(w, http.StatusText(http.StatusTooManyRequests)+": global limit", http.StatusTooManyRequests) - return - } - - smsg, err := h.api.MpoolPushMessage(h.ctx, &types.Message{ - Value: types.BigInt(h.sendPerRequest), - From: h.from, - To: owner, - }, nil) - if err != nil { - http.Error(w, "pushfunds: "+err.Error(), http.StatusBadRequest) - return - } - log.Infof("%s: push funds %s", owner, smsg.Cid()) - - spt, err := ffiwrapper.SealProofTypeFromSectorSize(abi.SectorSize(ssize)) - if err != nil { - http.Error(w, "sealprooftype: "+err.Error(), http.StatusBadRequest) - return - } - - params, err := actors.SerializeParams(&power.CreateMinerParams{ - Owner: owner, - Worker: owner, - SealProofType: spt, - Peer: abi.PeerID(h.defaultMinerPeer), - }) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - createStorageMinerMsg := &types.Message{ - To: builtin.StoragePowerActorAddr, - From: h.from, - Value: big.Zero(), - - Method: builtin.MethodsPower.CreateMiner, - Params: params, - } - - signed, err := h.api.MpoolPushMessage(r.Context(), createStorageMinerMsg, nil) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - log.Infof("%s: create miner msg: %s", owner, signed.Cid()) - - http.Redirect(w, r, fmt.Sprintf("/wait.html?f=%s&m=%s&o=%s", signed.Cid(), smsg.Cid(), owner), http.StatusSeeOther) -} - -func (h *handler) msgwait(w http.ResponseWriter, r *http.Request) { - c, err := cid.Parse(r.FormValue("cid")) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - mw, err := h.api.StateWaitMsg(r.Context(), c, build.MessageConfidence) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - if mw.Receipt.ExitCode != 0 { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - w.WriteHeader(http.StatusOK) -} - -func (h *handler) msgwaitaddr(w http.ResponseWriter, r *http.Request) { - c, err := cid.Parse(r.FormValue("cid")) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - mw, err := h.api.StateWaitMsg(r.Context(), c, build.MessageConfidence) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - if mw.Receipt.ExitCode != 0 { - http.Error(w, xerrors.Errorf("create miner failed: exit code %d", mw.Receipt.ExitCode).Error(), http.StatusBadRequest) - return - } - w.WriteHeader(http.StatusOK) - - var ma power.CreateMinerReturn - if err := ma.UnmarshalCBOR(bytes.NewReader(mw.Receipt.Return)); err != nil { - log.Errorf("%w", err) - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - fmt.Fprintf(w, "{\"addr\": \"%s\"}", ma.IDAddress) -} diff --git a/cmd/lotus-fountain/site/_miner.html b/cmd/lotus-fountain/site/_miner.html deleted file mode 100644 index f3c723c7f..000000000 --- a/cmd/lotus-fountain/site/_miner.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - Creating Miner - Lotus Fountain - - - - - - - diff --git a/cmd/lotus-fountain/site/index.html b/cmd/lotus-fountain/site/index.html index 85226e4c0..644960225 100644 --- a/cmd/lotus-fountain/site/index.html +++ b/cmd/lotus-fountain/site/index.html @@ -13,9 +13,6 @@ -