Merge branch 'master' into feat/replace-multistore-carv2

This commit is contained in:
Raúl Kripalani
2021-07-26 22:15:36 +01:00
137 changed files with 7269 additions and 1906 deletions
+57
View File
@@ -735,6 +735,45 @@ jobs:
- packer/build: - packer/build:
template: tools/packer/lotus.pkr.hcl template: tools/packer/lotus.pkr.hcl
args: "-var ci_workspace_bins=./linux-nerpanet -var lotus_network=nerpanet -var git_tag=$CIRCLE_TAG" args: "-var ci_workspace_bins=./linux-nerpanet -var lotus_network=nerpanet -var git_tag=$CIRCLE_TAG"
publish-dockerhub:
description: publish to dockerhub
machine:
image: ubuntu-2004:202010-01
parameters:
tag:
type: string
default: latest
steps:
- checkout
- run:
name: dockerhub login
command: echo $DOCKERHUB_PASSWORD | docker login --username $DOCKERHUB_USERNAME --password-stdin
- run:
name: docker build
command: |
docker build --target lotus -t filecoin/lotus:<< parameters.tag >> -f Dockerfile.lotus .
docker build --target lotus-all-in-one -t filecoin/lotus-all-in-one:<< parameters.tag >> -f Dockerfile.lotus .
if [[ ! -z $CIRCLE_SHA1 ]]; then
docker build --target lotus -t filecoin/lotus:$CIRCLE_SHA1 -f Dockerfile.lotus .
docker build --target lotus-all-in-one -t filecoin/lotus-all-in-one:$CIRCLE_SHA1 -f Dockerfile.lotus .
fi
if [[ ! -z $CIRCLE_TAG ]]; then
docker build --target lotus -t filecoin/lotus:$CIRCLE_TAG -f Dockerfile.lotus .
docker build --target lotus-all-in-one -t filecoin/lotus-all-in-one:$CIRCLE_TAG -f Dockerfile.lotus .
fi
- run:
name: docker push
command: |
docker push filecoin/lotus:<< parameters.tag >>
docker push filecoin/lotus-all-in-one:<< parameters.tag >>
if [[ ! -z $CIRCLE_SHA1 ]]; then
docker push filecoin/lotus:$CIRCLE_SHA1
docker push filecoin/lotus-all-in-one:$CIRCLE_SHA1
fi
if [[ ! -z $CIRCLE_TAG ]]; then
docker push filecoin/lotus:$CIRCLE_TAG
docker push filecoin/lotus-all-in-one:$CIRCLE_TAG
fi
workflows: workflows:
version: 2.1 version: 2.1
@@ -781,6 +820,11 @@ workflows:
suite: itest-deals_offline suite: itest-deals_offline
target: "./itests/deals_offline_test.go" target: "./itests/deals_offline_test.go"
- test:
name: test-itest-deals_padding
suite: itest-deals_padding
target: "./itests/deals_padding_test.go"
- test: - test:
name: test-itest-deals_power name: test-itest-deals_power
suite: itest-deals_power suite: itest-deals_power
@@ -1017,6 +1061,16 @@ workflows:
tags: tags:
only: only:
- /^v\d+\.\d+\.\d+(-rc\d+)?$/ - /^v\d+\.\d+\.\d+(-rc\d+)?$/
- publish-dockerhub:
name: publish-dockerhub
tag: stable
filters:
branches:
ignore:
- /.*/
tags:
only:
- /^v\d+\.\d+\.\d+(-rc\d+)?$/
nightly: nightly:
triggers: triggers:
@@ -1030,3 +1084,6 @@ workflows:
- publish-snapcraft: - publish-snapcraft:
name: publish-snapcraft-nightly name: publish-snapcraft-nightly
channel: edge channel: edge
- publish-dockerhub:
name: publish-dockerhub-nightly
tag: nightly
+52
View File
@@ -735,6 +735,45 @@ jobs:
- packer/build: - packer/build:
template: tools/packer/lotus.pkr.hcl template: tools/packer/lotus.pkr.hcl
args: "-var ci_workspace_bins=./linux-nerpanet -var lotus_network=nerpanet -var git_tag=$CIRCLE_TAG" args: "-var ci_workspace_bins=./linux-nerpanet -var lotus_network=nerpanet -var git_tag=$CIRCLE_TAG"
publish-dockerhub:
description: publish to dockerhub
machine:
image: ubuntu-2004:202010-01
parameters:
tag:
type: string
default: latest
steps:
- checkout
- run:
name: dockerhub login
command: echo $DOCKERHUB_PASSWORD | docker login --username $DOCKERHUB_USERNAME --password-stdin
- run:
name: docker build
command: |
docker build --target lotus -t filecoin/lotus:<< parameters.tag >> -f Dockerfile.lotus .
docker build --target lotus-all-in-one -t filecoin/lotus-all-in-one:<< parameters.tag >> -f Dockerfile.lotus .
if [["[[ ! -z $CIRCLE_SHA1 ]]"]]; then
docker build --target lotus -t filecoin/lotus:$CIRCLE_SHA1 -f Dockerfile.lotus .
docker build --target lotus-all-in-one -t filecoin/lotus-all-in-one:$CIRCLE_SHA1 -f Dockerfile.lotus .
fi
if [["[[ ! -z $CIRCLE_TAG ]]"]]; then
docker build --target lotus -t filecoin/lotus:$CIRCLE_TAG -f Dockerfile.lotus .
docker build --target lotus-all-in-one -t filecoin/lotus-all-in-one:$CIRCLE_TAG -f Dockerfile.lotus .
fi
- run:
name: docker push
command: |
docker push filecoin/lotus:<< parameters.tag >>
docker push filecoin/lotus-all-in-one:<< parameters.tag >>
if [["[[ ! -z $CIRCLE_SHA1 ]]"]]; then
docker push filecoin/lotus:$CIRCLE_SHA1
docker push filecoin/lotus-all-in-one:$CIRCLE_SHA1
fi
if [["[[ ! -z $CIRCLE_TAG ]]"]]; then
docker push filecoin/lotus:$CIRCLE_TAG
docker push filecoin/lotus-all-in-one:$CIRCLE_TAG
fi
workflows: workflows:
version: 2.1 version: 2.1
@@ -887,6 +926,16 @@ workflows:
tags: tags:
only: only:
- /^v\d+\.\d+\.\d+(-rc\d+)?$/ - /^v\d+\.\d+\.\d+(-rc\d+)?$/
- publish-dockerhub:
name: publish-dockerhub
tag: stable
filters:
branches:
ignore:
- /.*/
tags:
only:
- /^v\d+\.\d+\.\d+(-rc\d+)?$/
nightly: nightly:
triggers: triggers:
@@ -900,3 +949,6 @@ workflows:
- publish-snapcraft: - publish-snapcraft:
name: publish-snapcraft-nightly name: publish-snapcraft-nightly
channel: edge channel: edge
- publish-dockerhub:
name: publish-dockerhub-nightly
tag: nightly
-33
View File
@@ -1,33 +0,0 @@
---
name: Bug Report
about: Create a report to help us improve
title: "[BUG] "
labels: hint/needs-triaging, kind/bug
assignees: ''
---
> Note: For security-related bugs/issues, please follow the [security policy](https://github.com/filecoin-project/lotus/security/policy).
**Describe the bug**
A clear and concise description of what the bug is.
(If you are not sure what the bug is, try to figure it out via a [discussion](https://github.com/filecoin-project/lotus/discussions/new) first!
**Version (run `lotus version`):**
**To Reproduce**
Steps to reproduce the behavior:
1. Run '...'
2. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Logs**
Provide daemon/miner/worker logs, and goroutines(if available) for troubleshooting.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.
+92
View File
@@ -0,0 +1,92 @@
name: "Bug Report"
description: "File a bug report to help us improve"
labels: [need/triage, kind/bug]
body:
- type: checkboxes
attributes:
label: Checklist
description: Please check off the following boxes before continuing to file a bug report!
options:
- label: This is **not** a security-related bug/issue. If it is, please follow please follow the [security policy](https://github.com/filecoin-project/lotus/security/policy).
required: true
- label: This is **not** a question or a support request. If you have any lotus related questions, please ask in the [lotus forum](https://github.com/filecoin-project/lotus/discussions).
required: true
- label: This is **not** a new feature request. If it is, please file a [feature request](https://github.com/filecoin-project/lotus/issues/new?assignees=&labels=need%2Ftriage%2Ckind%2Ffeature&template=feature_request.yml) instead.
required: true
- label: This is **not** an enhancement request. If it is, please file a [improvement suggestion](https://github.com/filecoin-project/lotus/issues/new?assignees=&labels=need%2Ftriage%2Ckind%2Fenhancement&template=enhancement.yml) instead.
required: true
- label: I **have** searched on the [issue tracker](https://github.com/filecoin-project/lotus/issues) and the [lotus forum](https://github.com/filecoin-project/lotus/discussions), and there is no existing related issue or discussion.
required: true
- label: I am running the [`Latest release`](https://github.com/filecoin-project/lotus/releases), or the most recent RC(release canadiate) for the upcoming release or the dev branch(master), or have an issue updating to any of these.
required: true
- label: I did not make any code changes to lotus.
required: false
- type: dropdown
id: component-and-area
validations:
required: true
attributes:
label: Lotus component
description: Please select the lotus component you are filing a bug for
options:
- lotus daemon - chain sync
- lotus miner - mining and block production
- lotus miner/worker - sealing
- lotus miner - proving(WindowPoSt)
- lotus miner/market - storage deal
- lotus miner/market - retrieval deal
- lotus client
- lotus JSON-RPC API
- lotus message management (mpool)
- Other
- type: textarea
id: version
attributes:
label: Lotus Version
description: Enter the output of `lotus version` and `lotus-miner version` if applicable.
placeholder: |
e.g.
Daemon:1.11.0-rc2+debug+git.0519cd371.dirty+api1.3.0
Local: lotus version 1.11.0-rc2+debug+git.0519cd371.dirty
validations:
reuiqred: true
- type: textarea
id: Description
attributes:
label: Describe the Bug
description: |
This is where you get to tell us what went wrong, when doing so, please try to provide a clear and concise description of the bug with all related information:
* What you were doding when you experienced the bug?
* Any *error* messages you saw, *where* you saw them, and what you believe may have caused them (if you have any ideas).
* What is the expected behaviour?
* For sealing issues, include the output of `lotus-miner sectors status --log <sectorId>` for the failed sector(s).
* For proving issues, include the output of `lotus-miner proving` info.
* For deal making issues, include the output of `lotus client list-deals -v` and/or `lotus-miner storage-deals|retrieval-deals|data-transfers list [-v]` commands for the deal(s) in question.
render: bash
validations:
required: true
- type: textarea
id: extraInfo
attributes:
label: Logging Information
description: |
Please provide debug logs of the problem, remember you can get set log level control for:
* lotus: use `lotus log list` to get all log systems available and set level by `lotus log set-level`. An example can be found [here](https://docs.filecoin.io/get-started/lotus/configuration-and-advanced-usage/#log-level-control).
* lotus-miner:`lotus-miner log list` to get all log systems available and set level by `lotus-miner log set-level
If you don't provide detailed logs when you raise the issue it will almost certainly be the first request I make before furthur diagnosing the problem.
render: bash
validations:
required: true
- type: textarea
id: RepoSteps
attributes:
label: Repo Steps
description: "Steps to reproduce the behavior"
value: |
1. Run '...'
2. Do '...'
3. See error '...'
...
render: bash
validations:
required: false
@@ -1,49 +0,0 @@
---
name: Deal Making Issues
about: Create a report for help with deal making failures.
title: "[Deal Making Issue]"
labels: hint/needs-triaging, area/markets
assignees: ''
---
> Note: For security-related bugs/issues, please follow the [security policy](https://github.com/filecoin-project/lotus/security/policy).
Please provide all the information requested here to help us troubleshoot "deal making failed" issues.
If the information requested is missing, we will probably have to just ask you to provide it anyway,
before we can help debug.
**Basic Information**
Including information like, Are you the client or the miner? Is this a storage deal or a retrieval deal? Is it an offline deal?
**Describe the problem**
A brief description of the problem you encountered while trying to make a deal.
**Version**
The output of `lotus --version`.
**Setup**
You miner(if applicable) and daemon setup, i.e: What hardware do you use, how much ram and etc.
**To Reproduce**
Steps to reproduce the behavior:
1. Run '...'
2. See error
**Deal status**
The output of `lotus client list-deals -v` and/or `lotus-miner storage-deals|retrieval-deals|data-transfers list [-v]` commands for the deal(s) in question.
**Lotus daemon and miner logs**
Please go through the logs of your daemon and miner(if applicable), and include screenshots of any error/warning-like messages you find.
Alternatively please upload full log files and share a link here
** Code modifications **
If you have modified parts of lotus, please describe which areas were modified,
and the scope of those modifications
+44
View File
@@ -0,0 +1,44 @@
name: Enhancement
description: Suggest an improvement to an existing lotus feature.
labels: [need/triage, kind/enhancement]
body:
- type: checkboxes
attributes:
label: Checklist
description: Please check off the following boxes before continuing to create an improvement suggestion!
options:
- label: This is **not** a new feature or an enhancement to the Filecoin protocol. If it is, please open an [FIP issue](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0001.md).
required: true
- label: This is **not** a new feature request. If it is, please file a [feature request](https://github.com/filecoin-project/lotus/issues/new?assignees=&labels=need%2Ftriage%2Ckind%2Ffeature&template=feature_request.yml) instead.
required: true
- label: This is **not** brainstorming ideas. If you have an idea you'd like to discuss, please open a new discussion on [the lotus forum](https://github.com/filecoin-project/lotus/discussions/categories/ideas) and select the category as `Ideas`.
required: true
- label: I **have** a specific, actionable, and well motivated improvement to propose.
required: true
- type: dropdown
id: component
validations:
required: true
attributes:
label: Lotus component
description: Please select the lotus component you are propoing improvement for
options:
- lotus daemon - chain sync
- lotus miner - mining and block production
- lotus miner/worker - sealing
- lotus miner - proving(WindowPoSt)
- lotus miner/market - storage deal
- lotus miner/market - retrieval deal
- lotus client
- lotus JSON-RPC API
- lotus message management (mpool)
- Other
- type: textarea
id: request
attributes:
label: Improvement Suggestion
description: A clear and concise description of what the motivation or the current problem is and what is the suggested improvement?
placeholder: Ex. Currently lotus... However, as a storage provider, I'd like...
validations:
required: true
-20
View File
@@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[Feature Request]"
labels: hint/needs-triaging
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
@@ -0,0 +1,63 @@
name: Feature request
description: Suggest an idea for lotus
labels: [need/triage, kind/feature]
body:
- type: checkboxes
attributes:
label: Checklist
description: Please check off the following boxes before continuing to create a new feature request!
options:
- label: This is **not** a new feature or an enhancement to the Filecoin protocol. If it is, please open an [FIP issue](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0001.md).
required: true
- label: This is **not** brainstorming ideas. If you have an idea you'd like to discuss, please open a new discussion on [the lotus forum](https://github.com/filecoin-project/lotus/discussions/categories/ideas) and select the category as `Ideas`.
required: true
- label: I **have** a specific, actionable, and well motivated feature request to propose.
required: true
- type: dropdown
id: component
validations:
required: true
attributes:
label: Lotus component
description: Please select the lotus component you are requesting a new feature for
options:
- lotus daemon - chain sync
- lotus miner - mining and block production
- lotus miner/worker - sealing
- lotus miner - proving(WindowPoSt)
- lotus miner/market - storage deal
- lotus miner/market - retrieval deal
- lotus client
- lotus JSON-RPC API
- lotus message management (mpool)
- Other
- type: textarea
id: request
attributes:
label: What is the motivation behind this feature request? Is your feature request related to a problem? Please describe.
description: A clear and concise description of what the motivation or the problem is.
placeholder: Ex. I'm always frustrated when [...]
validations:
required: true
- type: textarea
id: solution
attributes:
label: Describe the solution you'd like
description: A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
id: alternates
attributes:
label: Describe alternatives you've considered
description: A clear and concise description of any alternative solutions or features you've considered.
validations:
required: false
- type: textarea
id: extra
attributes:
label: Additional context
description: Add any other context, design docs or screenshots about the feature request here.
validations:
required: false
@@ -0,0 +1,91 @@
name: "M1 Bug Report For Deal Making"
description: "File a bug report around deal making for the M1 releases"
labels: [need/triage, kind/bug, M1-release]
body:
- type: checkboxes
id: checklist
attributes:
label: Checklist
description: Please check off the following boxes before continuing to file a bug report!
options:
- label: This is **not** a question or a support request. If you have any lotus related questions, please ask in the [lotus forum](https://github.com/filecoin-project/lotus/discussions).
required: true
- label: I **am** reporting a bug w.r.t one of the [M1 tags](https://github.com/filecoin-project/lotus/discussions/6852#discussioncomment-1043951). If not, choose another issue option [here](https://github.com/filecoin-project/lotus/issues/new/choose).
required: true
- label: I **am** reporting a bug around deal making. If not, create a [M1 Bug Report For Non Deal Making Issue](https://github.com/filecoin-project/lotus/issues/new?assignees=&labels=need%2Ftriage%2Ckind%2Fbug%2CM1-release&template=m1_bug_report_non_deal.yml).
required: true
- label: I have my log level set as instructed [here](https://github.com/filecoin-project/lotus/discussions/6852#discussioncomment-1043678) and have logs available for troubleshooting.
required: true
- label: The deal is coming from one of the M1 clients(communitcated in the coordination slack channel).
required: true
- label: I **have** searched on the [issue tracker](https://github.com/filecoin-project/lotus/issues) and the [lotus forum](https://github.com/filecoin-project/lotus/discussions), and there is no existing related issue or discussion.
required: true
- type: dropdown
id: lotus-componets
validations:
required: true
attributes:
label: Lotus Component
description: Please select the lotus component you are filing a bug for
options:
- lotus miner market subsystem - storage deal
- lotus miner market subsystem - retrieval deal
- lotus miner - storage deal
- lotus miner - retrieval deal
- type: textarea
id: version
attributes:
label: Lotus Tag and Version
description: Enter the lotus tag, output of `lotus version` and `lotus-miner version`.
validations:
reuiqred: true
- type: textarea
id: Description
attributes:
label: Describe the Bug
description: |
This is where you get to tell us what went wrong, when doing so, please try to provide a clear and concise description of the bug with all related information:
* What you were doding when you experienced the bug?
* Any *error* messages you saw, *where* you saw them, and what you believe may have caused them (if you have any ideas).
* What is the expected behaviour?
render: bash
validations:
required: true
- type: textarea
id: deal-status
attributes:
label: Deal Status
description: What's the status of the deal?
placeholder: |
Please share the output of `lotus-miner storage-deals|retrieval-deals list [-v]` commands for the deal(s) in question.
validations:
required: true
- type: textarea
id: data-transfer-status
attributes:
label: Data Transfer Status
description: What's the status of the data transfer?
placeholder: |
Please share the output of `lotus-miner data-transfers list -v` commands for the deal(s) in question.
validations:
required: true
- type: textarea
id: logging
attributes:
label: Logging Information
description: Please link to the whole of the miner logs on your side of the transaction. You can upload the logs to a [gist](https://gist.github.com).
validations:
required: true
- type: textarea
id: RepoSteps
attributes:
label: Repo Steps (optional)
description: "Steps to reproduce the behavior"
value: |
1. Run '...'
2. Do '...'
3. See error '...'
...
render: bash
validations:
required: false
@@ -0,0 +1,81 @@
name: "M1 Bug Report For Non Deal Making Issue"
description: "File a bug report around non deal making issue for the M1 releases"
labels: [need/triage, kind/bug, M1-release]
body:
- type: checkboxes
id: checklist
attributes:
label: Checklist
description: Please check off the following boxes before continuing to file a bug report!
options:
- label: This is **not** a question or a support request. If you have any lotus related questions, please ask in the [lotus forum](https://github.com/filecoin-project/lotus/discussions).
required: true
- label: I **am** reporting a bug w.r.t one of the [M1 tags](https://github.com/filecoin-project/lotus/discussions/6852#discussioncomment-1043951). If not, choose another issue option [here](https://github.com/filecoin-project/lotus/issues/new/choose).
required: true
- label: I am **not** reporting a bug around deal making. If yes, create a [M1 Bug Report For Deal Making](https://github.com/filecoin-project/lotus/issues/new?assignees=&labels=need%2Ftriage%2Ckind%2Fbug%2CM1-release&template=m1_bug_report_deal.yml).
required: true
- label: I **have** searched on the [issue tracker](https://github.com/filecoin-project/lotus/issues) and the [lotus forum](https://github.com/filecoin-project/lotus/discussions), and there is no existing related issue or discussion.
required: true
- type: dropdown
id: component-and-area
validations:
required: true
attributes:
label: Lotus component
description: Please select the lotus component you are filing a bug for
options:
- lotus daemon - chain sync **with** splitstore enabled
- lotus daemon - chain sync **without** splitstore enabled
- lotus miner - mining and block production
- lotus miner/worker - sealing
- lotus miner - proving(WindowPoSt)
- lotus client
- lotus JSON-RPC API
- lotus message management (mpool)
- Other
- type: textarea
id: version
attributes:
label: Lotus Tag and Version
description: Enter the lotus tag, output of `lotus version` and `lotus-miner version`.
validations:
reuiqred: true
- type: textarea
id: Description
attributes:
label: Describe the Bug
description: |
This is where you get to tell us what went wrong, when doing so, please try to provide a clear and concise description of the bug with all related information:
* What you were doding when you experienced the bug?
* Any *error* messages you saw, *where* you saw them, and what you believe may have caused them (if you have any ideas).
* What is the expected behaviour?
* For sealing issues, include the output of `lotus-miner sectors status --log <sectorId>` for the failed sector(s).
* For proving issues, include the output of `lotus-miner proving` info.
render: bash
validations:
required: true
- type: textarea
id: extraInfo
attributes:
label: Logging Information
description: |
Please provide debug logs of the problem, remember you can get set log level control for:
* lotus: use `lotus log list` to get all log systems available and set level by `lotus log set-level`. An example can be found [here](https://docs.filecoin.io/get-started/lotus/configuration-and-advanced-usage/#log-level-control).
* lotus-miner:`lotus-miner log list` to get all log systems available and set level by `lotus-miner log set-level
If you don't provide detailed logs when you raise the issue it will almost certainly be the first request I make before furthur diagnosing the problem.
render: bash
validations:
required: true
- type: textarea
id: RepoSteps
attributes:
label: Repo Steps
description: "Steps to reproduce the behavior"
value: |
1. Run '...'
2. Do '...'
3. See error '...'
...
render: bash
validations:
required: false
-35
View File
@@ -1,35 +0,0 @@
---
name: Mining Issues
about: Create a report for help with mining failures.
title: "[Mining Issue]"
labels: hint/needs-triaging, area/mining
assignees: ''
---
> Note: For security-related bugs/issues, please follow the [security policy](https://github.com/filecoin-project/lotus/security/policy).
Please provide all the information requested here to help us troubleshoot "mining/WinningPoSt failed" issues.
If the information requested is missing, you may be asked you to provide it.
**Describe the problem**
A brief description of the problem you encountered while mining new blocks.
**Version**
The output of `lotus --version`.
**Setup**
You miner and daemon setup, including what hardware do you use, your environment variable settings, how do you run your miner and worker, do you use GPU and etc.
**Lotus daemon and miner logs**
Please go through the logs of your daemon and miner, and include screenshots of any error/warning-like messages you find, highlighting the one has "winning post" in it.
Alternatively please upload full log files and share a link here
** Code modifications **
If you have modified parts of lotus, please describe which areas were modified,
and the scope of those modifications
-46
View File
@@ -1,46 +0,0 @@
---
name: Proving Issues
about: Create a report for help with proving failures.
title: "[Proving Issue]"
labels: area/proving, hint/needs-triaging
assignees: ''
---
> Note: For security-related bugs/issues, please follow the [security policy](https://github.com/filecoin-project/lotus/security/policy).
Please provide all the information requested here to help us troubleshoot "proving/window PoSt failed" issues.
If the information requested is missing, we will probably have to just ask you to provide it anyway,
before we can help debug.
**Describe the problem**
A brief description of the problem you encountered while proving the storage.
**Version**
The output of `lotus --version`.
**Setup**
You miner and daemon setup, including what hardware do you use, your environment variable settings, how do you run your miner and worker, do you use GPU and etc.
**Proving status**
The output of `lotus-miner proving` info.
**Lotus miner logs**
Please go through the logs of your miner, and include screenshots of any error-like messages you find, highlighting the one has "window post" in it.
Alternatively please upload full log files and share a link here
**Lotus miner diagnostic info**
Please collect the following diagnostic information, and share a link here
* lotus-miner diagnostic info `lotus-miner info all > allinfo.txt`
** Code modifications **
If you have modified parts of lotus, please describe which areas were modified,
and the scope of those modifications
-50
View File
@@ -1,50 +0,0 @@
---
name: Sealing Issues
about: Create a report for help with sealing (commit) failures.
title: "[Sealing Issue]"
labels: hint/needs-triaging, area/sealing
assignees: ''
---
> Note: For security-related bugs/issues, please follow the [security policy](https://github.com/filecoin-project/lotus/security/policy).
Please provide all the information requested here to help us troubleshoot "commit failed" issues.
If the information requested is missing, we will probably have to just ask you to provide it anyway,
before we can help debug.
**Describe the problem**
A brief description of the problem you encountered while sealing a sector.
**Version**
The output of `lotus --version`.
**Setup**
You miner and daemon setup, including what hardware do you use, your environment variable settings, how do you run your miner and worker, do you use GPU and etc.
**Commands**
Commands you ran.
**Sectors status**
The output of `lotus-miner sectors status --log <sectorId>` for the failed sector(s).
**Lotus miner logs**
Please go through the logs of your miner, and include screenshots of any error-like messages you find.
Alternatively please upload full log files and share a link here
**Lotus miner diagnostic info**
Please collect the following diagnostic information, and share a link here
* lotus-miner diagnostic info `lotus-miner info all > allinfo`
** Code modifications **
If you have modified parts of lotus, please describe which areas were modified,
and the scope of those modifications
+33
View File
@@ -1,5 +1,38 @@
# Lotus changelog # Lotus changelog
# 1.10.1 / 2021-07-05
This is an optional but **highly recommended** release of Lotus for lotus miners that has many bug fixes and improvements based on the feedback we got from the community since HyperDrive.
## New Features
- commit batch: AggregateAboveBaseFee config #6650
- `AggregateAboveBaseFee` is added to miner sealing configuration for setting the network base fee to start aggregating proofs. When the network base fee is lower than this value, the prove commits will be submitted individually via `ProveCommitSector`. According to the [Batch Incentive Alignment](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0013.md#batch-incentive-alignment) introduced in FIP-0013, we recommend miners to set this value to 0.15 nanoFIL(which is the default value) to avoid unexpected aggregation fee in burn and enjoy the most benefits of aggregation!
## Bug Fixes
- storage: Fix FinalizeSector with sectors in storage paths #6652
- Fix tiny error in check-client-datacap #6664
- Fix: precommit_batch method used the wrong cfg.PreCommitBatchWait #6658
- to optimize the batchwait #6636
- fix getTicket: sector precommitted but expired case #6635
- handleSubmitCommitAggregate() exception handling #6595
- remove precommit check in handleCommitFailed #6634
- ensure agg fee is adequate
- fix: miner balance is not enough, so that ProveCommitAggregate msg exec failed #6623
- commit batch: Initialize the FailedSectors map #6647
Contributors
| Contributor | Commits | Lines ± | Files Changed |
|-------------|---------|---------|---------------|
| @magik6k| 7 | +151/-56 | 21 |
| @llifezou | 4 | +59/-20 | 4 |
| @johnli-helloworld | 2 | +45/-14 | 4 |
| @wangchao | 1 | +1/-27 | 1 |
| Jerry | 2 | +9/-4 | 2 |
| @zhoutian527 | 1 | +2/-2 | 1 |
| @ribasushi| 1 | +1/-1 | 1 |
# 1.10.0 / 2021-06-23 # 1.10.0 / 2021-06-23
This is a mandatory release of Lotus that introduces Filecoin network v13, codenamed the HyperDrive upgrade. The This is a mandatory release of Lotus that introduces Filecoin network v13, codenamed the HyperDrive upgrade. The
+158 -4
View File
@@ -36,7 +36,7 @@ WORKDIR /opt/filecoin
ARG RUSTFLAGS="" ARG RUSTFLAGS=""
ARG GOFLAGS="" ARG GOFLAGS=""
RUN make deps lotus lotus-miner lotus-worker lotus-shed lotus-chainwatch lotus-stats RUN make lotus lotus-miner lotus-worker lotus-shed lotus-wallet lotus-gateway
FROM ubuntu:20.04 AS base FROM ubuntu:20.04 AS base
@@ -56,19 +56,173 @@ COPY --from=builder /usr/lib/x86_64-linux-gnu/libOpenCL.so.1 /lib/
RUN useradd -r -u 532 -U fc RUN useradd -r -u 532 -U fc
###
FROM base AS lotus FROM base AS lotus
MAINTAINER Lotus Development Team MAINTAINER Lotus Development Team
COPY --from=builder /opt/filecoin/lotus /usr/local/bin/ COPY --from=builder /opt/filecoin/lotus /usr/local/bin/
COPY --from=builder /opt/filecoin/lotus-shed /usr/local/bin/ COPY --from=builder /opt/filecoin/lotus-shed /usr/local/bin/
COPY scripts/docker-lotus-entrypoint.sh /
ENV FILECOIN_PARAMETER_CACHE /var/tmp/filecoin-proof-parameters ENV FILECOIN_PARAMETER_CACHE /var/tmp/filecoin-proof-parameters
ENV LOTUS_PATH /var/lib/lotus ENV LOTUS_PATH /var/lib/lotus
ENV LOTUS_JAEGER_AGENT_HOST 127.0.0.1
ENV LOTUS_JAEGER_AGENT_PORT 6831
ENV DOCKER_LOTUS_IMPORT_SNAPSHOT https://fil-chain-snapshots-fallback.s3.amazonaws.com/mainnet/minimal_finality_stateroots_latest.car
ENV DOCKER_LOTUS_IMPORT_WALLET ""
RUN mkdir /var/lib/lotus /var/tmp/filecoin-proof-parameters && chown fc /var/lib/lotus /var/tmp/filecoin-proof-parameters RUN mkdir /var/lib/lotus /var/tmp/filecoin-proof-parameters
RUN chown fc: /var/lib/lotus /var/tmp/filecoin-proof-parameters
VOLUME /var/lib/lotus
VOLUME /var/tmp/filecoin-proof-parameters
USER fc USER fc
ENTRYPOINT ["/usr/local/bin/lotus"] EXPOSE 1234
ENTRYPOINT ["/docker-lotus-entrypoint.sh"]
CMD ["-help"] CMD ["-help"]
###
FROM base AS lotus-wallet
MAINTAINER Lotus Development Team
COPY --from=builder /opt/filecoin/lotus-wallet /usr/local/bin/
ENV WALLET_PATH /var/lib/lotus-wallet
ENV LOTUS_JAEGER_AGENT_HOST 127.0.0.1
ENV LOTUS_JAEGER_AGENT_PORT 6831
RUN mkdir /var/lib/lotus-wallet
RUN chown fc: /var/lib/lotus-wallet
VOLUME /var/lib/lotus-wallet
USER fc
EXPOSE 1777
ENTRYPOINT ["/usr/local/bin/lotus-wallet"]
CMD ["-help"]
###
FROM base AS lotus-gateway
MAINTAINER Lotus Development Team
COPY --from=builder /opt/filecoin/lotus-gateway /usr/local/bin/
ENV LOTUS_JAEGER_AGENT_HOST 127.0.0.1
ENV LOTUS_JAEGER_AGENT_PORT 6831
ENV FULLNODE_API_INFO /ip4/127.0.0.1/tcp/1234/http
USER fc
EXPOSE 1234
ENTRYPOINT ["/usr/local/bin/lotus-gateway"]
CMD ["-help"]
###
FROM base AS lotus-miner
MAINTAINER Lotus Development Team
COPY --from=builder /opt/filecoin/lotus-miner /usr/local/bin/
COPY scripts/docker-lotus-miner-entrypoint.sh /
ENV FILECOIN_PARAMETER_CACHE /var/tmp/filecoin-proof-parameters
ENV FULLNODE_API_INFO /ip4/127.0.0.1/tcp/1234/http
ENV LOTUS_MINER_PATH /var/lib/lotus-miner
ENV LOTUS_JAEGER_AGENT_HOST 127.0.0.1
ENV LOTUS_JAEGER_AGENT_PORT 6831
ENV DOCKER_LOTUS_MINER_INIT true
RUN mkdir /var/lib/lotus-miner /var/tmp/filecoin-proof-parameters
RUN chown fc: /var/lib/lotus-miner /var/tmp/filecoin-proof-parameters
VOLUME /var/lib/lotus-miner
VOLUME /var/tmp/filecoin-proof-parameters
USER fc
EXPOSE 2345
ENTRYPOINT ["/docker-lotus-miner-entrypoint.sh"]
CMD ["-help"]
###
FROM base AS lotus-worker
MAINTAINER Lotus Development Team
COPY --from=builder /opt/filecoin/lotus-worker /usr/local/bin/
ENV FILECOIN_PARAMETER_CACHE /var/tmp/filecoin-proof-parameters
ENV MINER_API_INFO /ip4/127.0.0.1/tcp/2345/http
ENV LOTUS_WORKER_PATH /var/lib/lotus-worker
ENV LOTUS_JAEGER_AGENT_HOST 127.0.0.1
ENV LOTUS_JAEGER_AGENT_PORT 6831
RUN mkdir /var/lib/lotus-worker
RUN chown fc: /var/lib/lotus-worker
VOLUME /var/lib/lotus-worker
USER fc
EXPOSE 3456
ENTRYPOINT ["/usr/local/bin/lotus-worker"]
CMD ["-help"]
###
from base as lotus-all-in-one
ENV FILECOIN_PARAMETER_CACHE /var/tmp/filecoin-proof-parameters
ENV FULLNODE_API_INFO /ip4/127.0.0.1/tcp/1234/http
ENV LOTUS_JAEGER_AGENT_HOST 127.0.0.1
ENV LOTUS_JAEGER_AGENT_PORT 6831
ENV LOTUS_MINER_PATH /var/lib/lotus-miner
ENV LOTUS_PATH /var/lib/lotus
ENV LOTUS_WORKER_PATH /var/lib/lotus-worker
ENV MINER_API_INFO /ip4/127.0.0.1/tcp/2345/http
ENV WALLET_PATH /var/lib/lotus-wallet
ENV DOCKER_LOTUS_IMPORT_SNAPSHOT https://fil-chain-snapshots-fallback.s3.amazonaws.com/mainnet/minimal_finality_stateroots_latest.car
ENV DOCKER_LOTUS_MINER_INIT true
COPY --from=builder /opt/filecoin/lotus /usr/local/bin/
COPY --from=builder /opt/filecoin/lotus-shed /usr/local/bin/
COPY --from=builder /opt/filecoin/lotus-wallet /usr/local/bin/
COPY --from=builder /opt/filecoin/lotus-gateway /usr/local/bin/
COPY --from=builder /opt/filecoin/lotus-miner /usr/local/bin/
COPY --from=builder /opt/filecoin/lotus-worker /usr/local/bin/
RUN mkdir /var/tmp/filecoin-proof-parameters
RUN mkdir /var/lib/lotus
RUN mkdir /var/lib/lotus-miner
RUN mkdir /var/lib/lotus-worker
RUN mkdir /var/lib/lotus-wallet
RUN chown fc: /var/tmp/filecoin-proof-parameters
RUN chown fc: /var/lib/lotus
RUN chown fc: /var/lib/lotus-miner
RUN chown fc: /var/lib/lotus-worker
RUN chown fc: /var/lib/lotus-wallet
VOLUME /var/tmp/filecoin-proof-parameters
VOLUME /var/lib/lotus
VOLUME /var/lib/lotus-miner
VOLUME /var/lib/lotus-worker
VOLUME /var/lib/lotus-wallet
EXPOSE 1234
EXPOSE 2345
EXPOSE 3456
EXPOSE 1777
+7 -1
View File
@@ -131,6 +131,9 @@ install-miner:
install-worker: install-worker:
install -C ./lotus-worker /usr/local/bin/lotus-worker install -C ./lotus-worker /usr/local/bin/lotus-worker
install-app:
install -C ./$(APP) /usr/local/bin/$(APP)
# TOOLS # TOOLS
lotus-seed: $(BUILD_DEPS) lotus-seed: $(BUILD_DEPS)
@@ -333,6 +336,9 @@ api-gen:
goimports -w api goimports -w api
.PHONY: api-gen .PHONY: api-gen
cfgdoc-gen:
go run ./node/config/cfgdocgen > ./node/config/doc_gen.go
appimage: lotus appimage: lotus
rm -rf appimage-builder-cache || true rm -rf appimage-builder-cache || true
rm AppDir/io.filecoin.lotus.desktop || true rm AppDir/io.filecoin.lotus.desktop || true
@@ -370,7 +376,7 @@ docsgen-openrpc-worker: docsgen-openrpc-bin
.PHONY: docsgen docsgen-md-bin docsgen-openrpc-bin .PHONY: docsgen docsgen-md-bin docsgen-openrpc-bin
gen: actors-gen type-gen method-gen docsgen api-gen circleci gen: actors-gen type-gen method-gen cfgdoc-gen docsgen api-gen circleci
@echo ">>> IF YOU'VE MODIFIED THE CLI, REMEMBER TO ALSO MAKE docsgen-cli" @echo ">>> IF YOU'VE MODIFIED THE CLI, REMEMBER TO ALSO MAKE docsgen-cli"
.PHONY: gen .PHONY: gen
+7 -48
View File
@@ -4,15 +4,11 @@ import (
"context" "context"
"fmt" "fmt"
apitypes "github.com/filecoin-project/lotus/api/types"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/filecoin-project/go-jsonrpc/auth" "github.com/filecoin-project/go-jsonrpc/auth"
metrics "github.com/libp2p/go-libp2p-core/metrics"
"github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
protocol "github.com/libp2p/go-libp2p-core/protocol"
apitypes "github.com/filecoin-project/lotus/api/types"
) )
// MODIFYING THE API INTERFACE // MODIFYING THE API INTERFACE
@@ -27,55 +23,23 @@ import (
// * Generate openrpc blobs // * Generate openrpc blobs
type Common interface { type Common interface {
// MethodGroup: Auth // MethodGroup: Auth
AuthVerify(ctx context.Context, token string) ([]auth.Permission, error) //perm:read AuthVerify(ctx context.Context, token string) ([]auth.Permission, error) //perm:read
AuthNew(ctx context.Context, perms []auth.Permission) ([]byte, error) //perm:admin AuthNew(ctx context.Context, perms []auth.Permission) ([]byte, error) //perm:admin
// MethodGroup: Net // MethodGroup: Log
NetConnectedness(context.Context, peer.ID) (network.Connectedness, error) //perm:read LogList(context.Context) ([]string, error) //perm:write
NetPeers(context.Context) ([]peer.AddrInfo, error) //perm:read LogSetLevel(context.Context, string, string) error //perm:write
NetConnect(context.Context, peer.AddrInfo) error //perm:write
NetAddrsListen(context.Context) (peer.AddrInfo, error) //perm:read
NetDisconnect(context.Context, peer.ID) error //perm:write
NetFindPeer(context.Context, peer.ID) (peer.AddrInfo, error) //perm:read
NetPubsubScores(context.Context) ([]PubsubScore, error) //perm:read
NetAutoNatStatus(context.Context) (NatInfo, error) //perm:read
NetAgentVersion(ctx context.Context, p peer.ID) (string, error) //perm:read
NetPeerInfo(context.Context, peer.ID) (*ExtendedPeerInfo, error) //perm:read
// NetBandwidthStats returns statistics about the nodes total bandwidth
// usage and current rate across all peers and protocols.
NetBandwidthStats(ctx context.Context) (metrics.Stats, error) //perm:read
// NetBandwidthStatsByPeer returns statistics about the nodes bandwidth
// usage and current rate per peer
NetBandwidthStatsByPeer(ctx context.Context) (map[string]metrics.Stats, error) //perm:read
// NetBandwidthStatsByProtocol returns statistics about the nodes bandwidth
// usage and current rate per protocol
NetBandwidthStatsByProtocol(ctx context.Context) (map[protocol.ID]metrics.Stats, error) //perm:read
// ConnectionGater API
NetBlockAdd(ctx context.Context, acl NetBlockList) error //perm:admin
NetBlockRemove(ctx context.Context, acl NetBlockList) error //perm:admin
NetBlockList(ctx context.Context) (NetBlockList, error) //perm:read
// MethodGroup: Common // MethodGroup: Common
// Discover returns an OpenRPC document describing an RPC API.
Discover(ctx context.Context) (apitypes.OpenRPCDocument, error) //perm:read
// ID returns peerID of libp2p node backing this API
ID(context.Context) (peer.ID, error) //perm:read
// Version provides information about API provider // Version provides information about API provider
Version(context.Context) (APIVersion, error) //perm:read Version(context.Context) (APIVersion, error) //perm:read
LogList(context.Context) ([]string, error) //perm:write // Discover returns an OpenRPC document describing an RPC API.
LogSetLevel(context.Context, string, string) error //perm:write Discover(ctx context.Context) (apitypes.OpenRPCDocument, error) //perm:read
// trigger graceful shutdown // trigger graceful shutdown
Shutdown(context.Context) error //perm:admin Shutdown(context.Context) error //perm:admin
@@ -105,8 +69,3 @@ type APIVersion struct {
func (v APIVersion) String() string { func (v APIVersion) String() string {
return fmt.Sprintf("%s+api%s", v.Version, v.APIVersion.String()) return fmt.Sprintf("%s+api%s", v.Version, v.APIVersion.String())
} }
type NatInfo struct {
Reachability network.Reachability
PublicAddr string
}
+8
View File
@@ -58,6 +58,7 @@ const LookbackNoLimit = abi.ChainEpoch(-1)
// FullNode API is a low-level interface to the Filecoin network full node // FullNode API is a low-level interface to the Filecoin network full node
type FullNode interface { type FullNode interface {
Common Common
Net
// MethodGroup: Chain // MethodGroup: Chain
// The Chain method group contains methods for interacting with the // The Chain method group contains methods for interacting with the
@@ -163,6 +164,13 @@ type FullNode interface {
// If oldmsgskip is set, messages from before the requested roots are also not included. // If oldmsgskip is set, messages from before the requested roots are also not included.
ChainExport(ctx context.Context, nroots abi.ChainEpoch, oldmsgskip bool, tsk types.TipSetKey) (<-chan []byte, error) //perm:read ChainExport(ctx context.Context, nroots abi.ChainEpoch, oldmsgskip bool, tsk types.TipSetKey) (<-chan []byte, error) //perm:read
// ChainCheckBlockstore performs an (asynchronous) health check on the chain/state blockstore
// if supported by the underlying implementation.
ChainCheckBlockstore(context.Context) error //perm:admin
// ChainBlockstoreInfo returns some basic information about the blockstore
ChainBlockstoreInfo(context.Context) (map[string]interface{}, error) //perm:read
// MethodGroup: Beacon // MethodGroup: Beacon
// The Beacon method group contains methods for interacting with the random beacon (DRAND) // The Beacon method group contains methods for interacting with the random beacon (DRAND)
+1
View File
@@ -45,6 +45,7 @@ type Gateway interface {
StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (DealCollateralBounds, error) StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (DealCollateralBounds, error)
StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)
StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*ActorState, error) //perm:read
StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error)
StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (MarketBalance, error) StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (MarketBalance, error)
+66
View File
@@ -0,0 +1,66 @@
package api
import (
"context"
metrics "github.com/libp2p/go-libp2p-core/metrics"
"github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/libp2p/go-libp2p-core/protocol"
)
// MODIFYING THE API INTERFACE
//
// When adding / changing methods in this file:
// * Do the change here
// * Adjust implementation in `node/impl/`
// * Run `make gen` - this will:
// * Generate proxy structs
// * Generate mocks
// * Generate markdown docs
// * Generate openrpc blobs
type Net interface {
// MethodGroup: Net
NetConnectedness(context.Context, peer.ID) (network.Connectedness, error) //perm:read
NetPeers(context.Context) ([]peer.AddrInfo, error) //perm:read
NetConnect(context.Context, peer.AddrInfo) error //perm:write
NetAddrsListen(context.Context) (peer.AddrInfo, error) //perm:read
NetDisconnect(context.Context, peer.ID) error //perm:write
NetFindPeer(context.Context, peer.ID) (peer.AddrInfo, error) //perm:read
NetPubsubScores(context.Context) ([]PubsubScore, error) //perm:read
NetAutoNatStatus(context.Context) (NatInfo, error) //perm:read
NetAgentVersion(ctx context.Context, p peer.ID) (string, error) //perm:read
NetPeerInfo(context.Context, peer.ID) (*ExtendedPeerInfo, error) //perm:read
// NetBandwidthStats returns statistics about the nodes total bandwidth
// usage and current rate across all peers and protocols.
NetBandwidthStats(ctx context.Context) (metrics.Stats, error) //perm:read
// NetBandwidthStatsByPeer returns statistics about the nodes bandwidth
// usage and current rate per peer
NetBandwidthStatsByPeer(ctx context.Context) (map[string]metrics.Stats, error) //perm:read
// NetBandwidthStatsByProtocol returns statistics about the nodes bandwidth
// usage and current rate per protocol
NetBandwidthStatsByProtocol(ctx context.Context) (map[protocol.ID]metrics.Stats, error) //perm:read
// ConnectionGater API
NetBlockAdd(ctx context.Context, acl NetBlockList) error //perm:admin
NetBlockRemove(ctx context.Context, acl NetBlockList) error //perm:admin
NetBlockList(ctx context.Context) (NetBlockList, error) //perm:read
// ID returns peerID of libp2p node backing this API
ID(context.Context) (peer.ID, error) //perm:read
}
type CommonNet interface {
Common
Net
}
type NatInfo struct {
Reachability network.Reachability
PublicAddr string
}
+1
View File
@@ -41,6 +41,7 @@ import (
// StorageMiner is a low-level interface to the Filecoin network storage miner node // StorageMiner is a low-level interface to the Filecoin network storage miner node
type StorageMiner interface { type StorageMiner interface {
Common Common
Net
ActorAddress(context.Context) (address.Address, error) //perm:read ActorAddress(context.Context) (address.Address, error) //perm:read
+2
View File
@@ -5,6 +5,7 @@ package api
import ( import (
"fmt" "fmt"
"io" "io"
"math"
"sort" "sort"
abi "github.com/filecoin-project/go-state-types/abi" abi "github.com/filecoin-project/go-state-types/abi"
@@ -17,6 +18,7 @@ import (
var _ = xerrors.Errorf var _ = xerrors.Errorf
var _ = cid.Undef var _ = cid.Undef
var _ = math.E
var _ = sort.Sort var _ = sort.Sort
func (t *PaymentInfo) MarshalCBOR(w io.Writer) error { func (t *PaymentInfo) MarshalCBOR(w io.Writer) error {
+12 -34
View File
@@ -16,14 +16,10 @@ import (
) )
// NewCommonRPCV0 creates a new http jsonrpc client. // NewCommonRPCV0 creates a new http jsonrpc client.
func NewCommonRPCV0(ctx context.Context, addr string, requestHeader http.Header) (api.Common, jsonrpc.ClientCloser, error) { func NewCommonRPCV0(ctx context.Context, addr string, requestHeader http.Header) (api.CommonNet, jsonrpc.ClientCloser, error) {
var res v0api.CommonStruct var res v0api.CommonNetStruct
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin", closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
[]interface{}{ api.GetInternalStructs(&res), requestHeader)
&res.Internal,
},
requestHeader,
)
return &res, closer, err return &res, closer, err
} }
@@ -31,11 +27,9 @@ func NewCommonRPCV0(ctx context.Context, addr string, requestHeader http.Header)
// NewFullNodeRPCV0 creates a new http jsonrpc client. // NewFullNodeRPCV0 creates a new http jsonrpc client.
func NewFullNodeRPCV0(ctx context.Context, addr string, requestHeader http.Header) (v0api.FullNode, jsonrpc.ClientCloser, error) { func NewFullNodeRPCV0(ctx context.Context, addr string, requestHeader http.Header) (v0api.FullNode, jsonrpc.ClientCloser, error) {
var res v0api.FullNodeStruct var res v0api.FullNodeStruct
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin", closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
[]interface{}{ api.GetInternalStructs(&res), requestHeader)
&res.CommonStruct.Internal,
&res.Internal,
}, requestHeader)
return &res, closer, err return &res, closer, err
} }
@@ -44,10 +38,7 @@ func NewFullNodeRPCV0(ctx context.Context, addr string, requestHeader http.Heade
func NewFullNodeRPCV1(ctx context.Context, addr string, requestHeader http.Header) (api.FullNode, jsonrpc.ClientCloser, error) { func NewFullNodeRPCV1(ctx context.Context, addr string, requestHeader http.Header) (api.FullNode, jsonrpc.ClientCloser, error) {
var res v1api.FullNodeStruct var res v1api.FullNodeStruct
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin", closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
[]interface{}{ api.GetInternalStructs(&res), requestHeader)
&res.CommonStruct.Internal,
&res.Internal,
}, requestHeader)
return &res, closer, err return &res, closer, err
} }
@@ -78,15 +69,10 @@ func NewStorageMinerRPCV0(ctx context.Context, addr string, requestHeader http.H
var res v0api.StorageMinerStruct var res v0api.StorageMinerStruct
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin", closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
[]interface{}{ api.GetInternalStructs(&res), requestHeader,
&res.CommonStruct.Internal,
&res.Internal,
},
requestHeader,
append([]jsonrpc.Option{ append([]jsonrpc.Option{
rpcenc.ReaderParamEncoder(pushUrl), rpcenc.ReaderParamEncoder(pushUrl),
}, opts...)..., }, opts...)...)
)
return &res, closer, err return &res, closer, err
} }
@@ -99,9 +85,7 @@ func NewWorkerRPCV0(ctx context.Context, addr string, requestHeader http.Header)
var res api.WorkerStruct var res api.WorkerStruct
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin", closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
[]interface{}{ api.GetInternalStructs(&res),
&res.Internal,
},
requestHeader, requestHeader,
rpcenc.ReaderParamEncoder(pushUrl), rpcenc.ReaderParamEncoder(pushUrl),
jsonrpc.WithNoReconnect(), jsonrpc.WithNoReconnect(),
@@ -115,9 +99,7 @@ func NewWorkerRPCV0(ctx context.Context, addr string, requestHeader http.Header)
func NewGatewayRPCV1(ctx context.Context, addr string, requestHeader http.Header, opts ...jsonrpc.Option) (api.Gateway, jsonrpc.ClientCloser, error) { func NewGatewayRPCV1(ctx context.Context, addr string, requestHeader http.Header, opts ...jsonrpc.Option) (api.Gateway, jsonrpc.ClientCloser, error) {
var res api.GatewayStruct var res api.GatewayStruct
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin", closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
[]interface{}{ api.GetInternalStructs(&res),
&res.Internal,
},
requestHeader, requestHeader,
opts..., opts...,
) )
@@ -129,9 +111,7 @@ func NewGatewayRPCV1(ctx context.Context, addr string, requestHeader http.Header
func NewGatewayRPCV0(ctx context.Context, addr string, requestHeader http.Header, opts ...jsonrpc.Option) (v0api.Gateway, jsonrpc.ClientCloser, error) { func NewGatewayRPCV0(ctx context.Context, addr string, requestHeader http.Header, opts ...jsonrpc.Option) (v0api.Gateway, jsonrpc.ClientCloser, error) {
var res v0api.GatewayStruct var res v0api.GatewayStruct
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin", closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
[]interface{}{ api.GetInternalStructs(&res),
&res.Internal,
},
requestHeader, requestHeader,
opts..., opts...,
) )
@@ -142,9 +122,7 @@ func NewGatewayRPCV0(ctx context.Context, addr string, requestHeader http.Header
func NewWalletRPCV0(ctx context.Context, addr string, requestHeader http.Header) (api.Wallet, jsonrpc.ClientCloser, error) { func NewWalletRPCV0(ctx context.Context, addr string, requestHeader http.Header) (api.Wallet, jsonrpc.ClientCloser, error) {
var res api.WalletStruct var res api.WalletStruct
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin", closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
[]interface{}{ api.GetInternalStructs(&res),
&res.Internal,
},
requestHeader, requestHeader,
) )
+1 -1
View File
@@ -34,7 +34,7 @@ func main() {
doc := docgen_openrpc.NewLotusOpenRPCDocument(Comments, GroupDocs) doc := docgen_openrpc.NewLotusOpenRPCDocument(Comments, GroupDocs)
i, _, _, _ := docgen.GetAPIType(os.Args[2], os.Args[3]) i, _, _ := docgen.GetAPIType(os.Args[2], os.Args[3])
doc.RegisterReceiverName("Filecoin", i) doc.RegisterReceiverName("Filecoin", i)
out, err := doc.Discover() out, err := doc.Discover()
+11 -6
View File
@@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
"reflect"
"sort" "sort"
"strings" "strings"
@@ -15,7 +16,7 @@ func main() {
groups := make(map[string]*docgen.MethodGroup) groups := make(map[string]*docgen.MethodGroup)
_, t, permStruct, commonPermStruct := docgen.GetAPIType(os.Args[2], os.Args[3]) _, t, permStruct := docgen.GetAPIType(os.Args[2], os.Args[3])
for i := 0; i < t.NumMethod(); i++ { for i := 0; i < t.NumMethod(); i++ {
m := t.Method(i) m := t.Method(i)
@@ -88,13 +89,17 @@ func main() {
fmt.Printf("### %s\n", m.Name) fmt.Printf("### %s\n", m.Name)
fmt.Printf("%s\n\n", m.Comment) fmt.Printf("%s\n\n", m.Comment)
meth, ok := permStruct.FieldByName(m.Name) var meth reflect.StructField
if !ok { var ok bool
meth, ok = commonPermStruct.FieldByName(m.Name) for _, ps := range permStruct {
if !ok { meth, ok = ps.FieldByName(m.Name)
panic("no perms for method: " + m.Name) if ok {
break
} }
} }
if !ok {
panic("no perms for method: " + m.Name)
}
perms := meth.Tag.Get("perm") perms := meth.Tag.Get("perm")
+12 -9
View File
@@ -270,25 +270,27 @@ func init() {
addExample(map[string]interface{}{"abc": 123}) addExample(map[string]interface{}{"abc": 123})
} }
func GetAPIType(name, pkg string) (i interface{}, t, permStruct, commonPermStruct reflect.Type) { func GetAPIType(name, pkg string) (i interface{}, t reflect.Type, permStruct []reflect.Type) {
switch pkg { switch pkg {
case "api": // latest case "api": // latest
switch name { switch name {
case "FullNode": case "FullNode":
i = &api.FullNodeStruct{} i = &api.FullNodeStruct{}
t = reflect.TypeOf(new(struct{ api.FullNode })).Elem() t = reflect.TypeOf(new(struct{ api.FullNode })).Elem()
permStruct = reflect.TypeOf(api.FullNodeStruct{}.Internal) permStruct = append(permStruct, reflect.TypeOf(api.FullNodeStruct{}.Internal))
commonPermStruct = reflect.TypeOf(api.CommonStruct{}.Internal) permStruct = append(permStruct, reflect.TypeOf(api.CommonStruct{}.Internal))
permStruct = append(permStruct, reflect.TypeOf(api.NetStruct{}.Internal))
case "StorageMiner": case "StorageMiner":
i = &api.StorageMinerStruct{} i = &api.StorageMinerStruct{}
t = reflect.TypeOf(new(struct{ api.StorageMiner })).Elem() t = reflect.TypeOf(new(struct{ api.StorageMiner })).Elem()
permStruct = reflect.TypeOf(api.StorageMinerStruct{}.Internal) permStruct = append(permStruct, reflect.TypeOf(api.StorageMinerStruct{}.Internal))
commonPermStruct = reflect.TypeOf(api.CommonStruct{}.Internal) permStruct = append(permStruct, reflect.TypeOf(api.CommonStruct{}.Internal))
permStruct = append(permStruct, reflect.TypeOf(api.NetStruct{}.Internal))
case "Worker": case "Worker":
i = &api.WorkerStruct{} i = &api.WorkerStruct{}
t = reflect.TypeOf(new(struct{ api.Worker })).Elem() t = reflect.TypeOf(new(struct{ api.Worker })).Elem()
permStruct = reflect.TypeOf(api.WorkerStruct{}.Internal) permStruct = append(permStruct, reflect.TypeOf(api.WorkerStruct{}.Internal))
commonPermStruct = reflect.TypeOf(api.WorkerStruct{}.Internal)
default: default:
panic("unknown type") panic("unknown type")
} }
@@ -297,8 +299,9 @@ func GetAPIType(name, pkg string) (i interface{}, t, permStruct, commonPermStruc
case "FullNode": case "FullNode":
i = v0api.FullNodeStruct{} i = v0api.FullNodeStruct{}
t = reflect.TypeOf(new(struct{ v0api.FullNode })).Elem() t = reflect.TypeOf(new(struct{ v0api.FullNode })).Elem()
permStruct = reflect.TypeOf(v0api.FullNodeStruct{}.Internal) permStruct = append(permStruct, reflect.TypeOf(v0api.FullNodeStruct{}.Internal))
commonPermStruct = reflect.TypeOf(v0api.CommonStruct{}.Internal) permStruct = append(permStruct, reflect.TypeOf(v0api.CommonStruct{}.Internal))
permStruct = append(permStruct, reflect.TypeOf(v0api.NetStruct{}.Internal))
default: default:
panic("unknown type") panic("unknown type")
} }
+29
View File
@@ -105,6 +105,35 @@ func (mr *MockFullNodeMockRecorder) BeaconGetEntry(arg0, arg1 interface{}) *gomo
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeaconGetEntry", reflect.TypeOf((*MockFullNode)(nil).BeaconGetEntry), arg0, arg1) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeaconGetEntry", reflect.TypeOf((*MockFullNode)(nil).BeaconGetEntry), arg0, arg1)
} }
// ChainBlockstoreInfo mocks base method.
func (m *MockFullNode) ChainBlockstoreInfo(arg0 context.Context) (map[string]interface{}, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ChainBlockstoreInfo", arg0)
ret0, _ := ret[0].(map[string]interface{})
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ChainBlockstoreInfo indicates an expected call of ChainBlockstoreInfo.
func (mr *MockFullNodeMockRecorder) ChainBlockstoreInfo(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainBlockstoreInfo", reflect.TypeOf((*MockFullNode)(nil).ChainBlockstoreInfo), arg0)
}
// ChainCheckBlockstore mocks base method.
func (m *MockFullNode) ChainCheckBlockstore(arg0 context.Context) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ChainCheckBlockstore", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// ChainCheckBlockstore indicates an expected call of ChainCheckBlockstore.
func (mr *MockFullNodeMockRecorder) ChainCheckBlockstore(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainCheckBlockstore", reflect.TypeOf((*MockFullNode)(nil).ChainCheckBlockstore), arg0)
}
// ChainDeleteObj mocks base method. // ChainDeleteObj mocks base method.
func (m *MockFullNode) ChainDeleteObj(arg0 context.Context, arg1 cid.Cid) error { func (m *MockFullNode) ChainDeleteObj(arg0 context.Context, arg1 cid.Cid) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
+11 -6
View File
@@ -16,28 +16,33 @@ const (
var AllPermissions = []auth.Permission{PermRead, PermWrite, PermSign, PermAdmin} var AllPermissions = []auth.Permission{PermRead, PermWrite, PermSign, PermAdmin}
var DefaultPerms = []auth.Permission{PermRead} var DefaultPerms = []auth.Permission{PermRead}
func permissionedProxies(in, out interface{}) {
outs := GetInternalStructs(out)
for _, o := range outs {
auth.PermissionedProxy(AllPermissions, DefaultPerms, in, o)
}
}
func PermissionedStorMinerAPI(a StorageMiner) StorageMiner { func PermissionedStorMinerAPI(a StorageMiner) StorageMiner {
var out StorageMinerStruct var out StorageMinerStruct
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal) permissionedProxies(a, &out)
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.CommonStruct.Internal)
return &out return &out
} }
func PermissionedFullAPI(a FullNode) FullNode { func PermissionedFullAPI(a FullNode) FullNode {
var out FullNodeStruct var out FullNodeStruct
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal) permissionedProxies(a, &out)
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.CommonStruct.Internal)
return &out return &out
} }
func PermissionedWorkerAPI(a Worker) Worker { func PermissionedWorkerAPI(a Worker) Worker {
var out WorkerStruct var out WorkerStruct
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal) permissionedProxies(a, &out)
return &out return &out
} }
func PermissionedWalletAPI(a Wallet) Wallet { func PermissionedWalletAPI(a Wallet) Wallet {
var out WalletStruct var out WalletStruct
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal) permissionedProxies(a, &out)
return &out return &out
} }
+1671 -515
View File
File diff suppressed because it is too large Load Diff
+30
View File
@@ -0,0 +1,30 @@
package api
import "reflect"
var _internalField = "Internal"
// GetInternalStructs extracts all pointers to 'Internal' sub-structs from the provided pointer to a proxy struct
func GetInternalStructs(in interface{}) []interface{} {
return getInternalStructs(reflect.ValueOf(in).Elem())
}
func getInternalStructs(rv reflect.Value) []interface{} {
var out []interface{}
internal := rv.FieldByName(_internalField)
ii := internal.Addr().Interface()
out = append(out, ii)
for i := 0; i < rv.NumField(); i++ {
if rv.Type().Field(i).Name == _internalField {
continue
}
sub := getInternalStructs(rv.Field(i))
out = append(out, sub...)
}
return out
}
+62
View File
@@ -0,0 +1,62 @@
package api
import (
"testing"
"github.com/stretchr/testify/require"
)
type StrA struct {
StrB
Internal struct {
A int
}
}
type StrB struct {
Internal struct {
B int
}
}
type StrC struct {
Internal struct {
Internal struct {
C int
}
}
}
func TestGetInternalStructs(t *testing.T) {
var proxy StrA
sts := GetInternalStructs(&proxy)
require.Len(t, sts, 2)
sa := sts[0].(*struct{ A int })
sa.A = 3
sb := sts[1].(*struct{ B int })
sb.B = 4
require.Equal(t, 3, proxy.Internal.A)
require.Equal(t, 4, proxy.StrB.Internal.B)
}
func TestNestedInternalStructs(t *testing.T) {
var proxy StrC
// check that only the top-level internal struct gets picked up
sts := GetInternalStructs(&proxy)
require.Len(t, sts, 1)
sa := sts[0].(*struct {
Internal struct {
C int
}
})
sa.Internal.C = 5
require.Equal(t, 5, proxy.Internal.Internal.C)
}
+1
View File
@@ -46,6 +46,7 @@ import (
// FullNode API is a low-level interface to the Filecoin network full node // FullNode API is a low-level interface to the Filecoin network full node
type FullNode interface { type FullNode interface {
Common Common
Net
// MethodGroup: Chain // MethodGroup: Chain
// The Chain method group contains methods for interacting with the // The Chain method group contains methods for interacting with the
+7
View File
@@ -5,8 +5,15 @@ import (
) )
type Common = api.Common type Common = api.Common
type Net = api.Net
type CommonNet = api.CommonNet
type CommonStruct = api.CommonStruct type CommonStruct = api.CommonStruct
type CommonStub = api.CommonStub type CommonStub = api.CommonStub
type NetStruct = api.NetStruct
type NetStub = api.NetStub
type CommonNetStruct = api.CommonNetStruct
type CommonNetStub = api.CommonNetStub
type StorageMiner = api.StorageMiner type StorageMiner = api.StorageMiner
type StorageMinerStruct = api.StorageMinerStruct type StorageMinerStruct = api.StorageMinerStruct
+838 -208
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -54,8 +54,8 @@ func VersionForType(nodeType NodeType) (Version, error) {
// semver versions of the rpc api exposed // semver versions of the rpc api exposed
var ( var (
FullAPIVersion0 = newVer(1, 3, 0) FullAPIVersion0 = newVer(1, 3, 1)
FullAPIVersion1 = newVer(2, 1, 0) FullAPIVersion1 = newVer(2, 1, 1)
MinerAPIVersion0 = newVer(1, 2, 0) MinerAPIVersion0 = newVer(1, 2, 0)
WorkerAPIVersion0 = newVer(1, 1, 0) WorkerAPIVersion0 = newVer(1, 1, 0)
+37 -2
View File
@@ -4,6 +4,8 @@ import (
"context" "context"
"fmt" "fmt"
"io" "io"
"os"
"path/filepath"
"runtime" "runtime"
"sync" "sync"
@@ -84,7 +86,8 @@ type Blockstore struct {
state int state int
viewers sync.WaitGroup viewers sync.WaitGroup
DB *badger.DB DB *badger.DB
opts Options
prefixing bool prefixing bool
prefix []byte prefix []byte
@@ -95,6 +98,7 @@ var _ blockstore.Blockstore = (*Blockstore)(nil)
var _ blockstore.Viewer = (*Blockstore)(nil) var _ blockstore.Viewer = (*Blockstore)(nil)
var _ blockstore.BlockstoreIterator = (*Blockstore)(nil) var _ blockstore.BlockstoreIterator = (*Blockstore)(nil)
var _ blockstore.BlockstoreGC = (*Blockstore)(nil) var _ blockstore.BlockstoreGC = (*Blockstore)(nil)
var _ blockstore.BlockstoreSize = (*Blockstore)(nil)
var _ io.Closer = (*Blockstore)(nil) var _ io.Closer = (*Blockstore)(nil)
// Open creates a new badger-backed blockstore, with the supplied options. // Open creates a new badger-backed blockstore, with the supplied options.
@@ -109,7 +113,7 @@ func Open(opts Options) (*Blockstore, error) {
return nil, fmt.Errorf("failed to open badger blockstore: %w", err) return nil, fmt.Errorf("failed to open badger blockstore: %w", err)
} }
bs := &Blockstore{DB: db} bs := &Blockstore{DB: db, opts: opts}
if p := opts.Prefix; p != "" { if p := opts.Prefix; p != "" {
bs.prefixing = true bs.prefixing = true
bs.prefix = []byte(p) bs.prefix = []byte(p)
@@ -191,6 +195,37 @@ func (b *Blockstore) CollectGarbage() error {
return err return err
} }
// Size returns the aggregate size of the blockstore
func (b *Blockstore) Size() (int64, error) {
if err := b.access(); err != nil {
return 0, err
}
defer b.viewers.Done()
lsm, vlog := b.DB.Size()
size := lsm + vlog
if size == 0 {
// badger reports a 0 size on symlinked directories... sigh
dir := b.opts.Dir
entries, err := os.ReadDir(dir)
if err != nil {
return 0, err
}
for _, e := range entries {
path := filepath.Join(dir, e.Name())
finfo, err := os.Stat(path)
if err != nil {
return 0, err
}
size += finfo.Size()
}
}
return size, nil
}
// View implements blockstore.Viewer, which leverages zero-copy read-only // View implements blockstore.Viewer, which leverages zero-copy read-only
// access to values. // access to values.
func (b *Blockstore) View(cid cid.Cid, fn func([]byte) error) error { func (b *Blockstore) View(cid cid.Cid, fn func([]byte) error) error {
+5
View File
@@ -40,6 +40,11 @@ type BlockstoreGC interface {
CollectGarbage() error CollectGarbage() error
} }
// BlockstoreSize is a trait for on-disk blockstores that can report their size
type BlockstoreSize interface {
Size() (int64, error)
}
// WrapIDStore wraps the underlying blockstore in an "identity" blockstore. // WrapIDStore wraps the underlying blockstore in an "identity" blockstore.
// The ID store filters out all puts for blocks with CIDs using the "identity" // The ID store filters out all puts for blocks with CIDs using the "identity"
// hash function. It also extracts inlined blocks from CIDs using the identity // hash function. It also extracts inlined blocks from CIDs using the identity
+47 -4
View File
@@ -27,9 +27,38 @@ If you intend to use the discard coldstore, your also need to add the following:
ColdStoreType = "discard" ColdStoreType = "discard"
``` ```
In general you _should not_ have to use the discard store, unless you In general you _should not_ have to use the discard store, unless you
are running a network booster or have very constrained hardware with are running a network assistive node (like a bootstrapper or booster)
not enough disk space to maintain a coldstore, even with garbage or have very constrained hardware with not enough disk space to
collection. maintain a coldstore, even with garbage collection. It is also appropriate
for small nodes that are simply watching the chain.
*Warning:* Using the discard store for a general purpose node is discouraged, unless
you really know what you are doing. Use it at your own risk.
## Configuration Options
These are options in the `[Chainstore.Splitstore]` section of the configuration:
- `HotStoreType` -- specifies the type of hotstore to use.
The only currently supported option is `"badger"`.
- `ColdStoreType` -- specifies the type of coldstore to use.
The default value is `"universal"`, which will use the initial monolith blockstore
as the coldstore.
The other possible value is `"discard"`, as outlined above, which is specialized for
running without a coldstore. Note that the discard store wraps the initial monolith
blockstore and discards writes; this is necessary to support syncing from a snapshot.
- `MarkSetType` -- specifies the type of markset to use during compaction.
The markset is the data structure used by compaction/gc to track live objects.
The default value is `"map"`, which will use an in-memory map; if you are limited
in memory (or indeed see compaction run out of memory), you can also specify
`"badger"` which will use an disk backed markset, using badger. This will use
much less memory, but will also make compaction slower.
- `HotStoreMessageRetention` -- specifies how many finalities, beyond the 4
finalities maintained by default, to maintain messages and message receipts in the
hotstore. This is useful for assistive nodes that want to support syncing for other
nodes beyond 4 finalities, while running with the discard coldstore option.
It is also useful for miners who accept deals and need to lookback messages beyond
the 4 finalities, which would otherwise hit the coldstore.
## Operation ## Operation
@@ -67,6 +96,20 @@ Compaction works transactionally with the following algorithm:
- We delete in small batches taking a lock; each batch is checked again for marks, from the concurrent transactional mark, so as to never delete anything live - We delete in small batches taking a lock; each batch is checked again for marks, from the concurrent transactional mark, so as to never delete anything live
- We then end the transaction and compact/gc the hotstore. - We then end the transaction and compact/gc the hotstore.
## Coldstore Garbage Collection ## Garbage Collection
TBD -- see [#6577](https://github.com/filecoin-project/lotus/issues/6577) TBD -- see [#6577](https://github.com/filecoin-project/lotus/issues/6577)
## Utilities
`lotus-shed` has a `splitstore` command which provides some utilities:
- `rollback` -- rolls back a splitstore installation.
This command copies the hotstore on top of the coldstore, and then deletes the splitstore
directory and associated metadata keys.
It can also optionally compact/gc the coldstore after the copy (with the `--gc-coldstore` flag)
and automatically rewrite the lotus config to disable splitstore (with the `--rewrite-config` flag).
Note: the node *must be stopped* before running this command.
- `check` -- asynchronously runs a basic healthcheck on the splitstore.
The results are appended to `<lotus-repo>/datastore/splitstore/check.txt`.
- `info` -- prints some basic information about the splitstore.
+2
View File
@@ -32,6 +32,8 @@ func OpenMarkSetEnv(path string, mtype string) (MarkSetEnv, error) {
return NewBloomMarkSetEnv() return NewBloomMarkSetEnv()
case "map": case "map":
return NewMapMarkSetEnv() return NewMapMarkSetEnv()
case "badger":
return NewBadgerMarkSetEnv(path)
default: default:
return nil, xerrors.Errorf("unknown mark set type %s", mtype) return nil, xerrors.Errorf("unknown mark set type %s", mtype)
} }
+230
View File
@@ -0,0 +1,230 @@
package splitstore
import (
"os"
"path/filepath"
"sync"
"golang.org/x/xerrors"
"github.com/dgraph-io/badger/v2"
"github.com/dgraph-io/badger/v2/options"
"go.uber.org/zap"
cid "github.com/ipfs/go-cid"
)
type BadgerMarkSetEnv struct {
path string
}
var _ MarkSetEnv = (*BadgerMarkSetEnv)(nil)
type BadgerMarkSet struct {
mx sync.RWMutex
cond sync.Cond
pend map[string]struct{}
writing map[int]map[string]struct{}
writers int
seqno int
db *badger.DB
path string
}
var _ MarkSet = (*BadgerMarkSet)(nil)
var badgerMarkSetBatchSize = 16384
func NewBadgerMarkSetEnv(path string) (MarkSetEnv, error) {
msPath := filepath.Join(path, "markset.badger")
err := os.MkdirAll(msPath, 0755) //nolint:gosec
if err != nil {
return nil, xerrors.Errorf("error creating markset directory: %w", err)
}
return &BadgerMarkSetEnv{path: msPath}, nil
}
func (e *BadgerMarkSetEnv) Create(name string, sizeHint int64) (MarkSet, error) {
path := filepath.Join(e.path, name)
// clean up first
err := os.RemoveAll(path)
if err != nil {
return nil, xerrors.Errorf("error clearing markset directory: %w", err)
}
err = os.MkdirAll(path, 0755) //nolint:gosec
if err != nil {
return nil, xerrors.Errorf("error creating markset directory: %w", err)
}
opts := badger.DefaultOptions(path)
opts.SyncWrites = false
opts.CompactL0OnClose = false
opts.Compression = options.None
// Note: We use FileIO for loading modes to avoid memory thrashing and interference
// between the system blockstore and the markset.
// It was observed that using the default memory mapped option resulted in
// significant interference and unacceptably high block validation times once the markset
// exceeded 1GB in size.
opts.TableLoadingMode = options.FileIO
opts.ValueLogLoadingMode = options.FileIO
opts.Logger = &badgerLogger{
SugaredLogger: log.Desugar().WithOptions(zap.AddCallerSkip(1)).Sugar(),
skip2: log.Desugar().WithOptions(zap.AddCallerSkip(2)).Sugar(),
}
db, err := badger.Open(opts)
if err != nil {
return nil, xerrors.Errorf("error creating badger markset: %w", err)
}
ms := &BadgerMarkSet{
pend: make(map[string]struct{}),
writing: make(map[int]map[string]struct{}),
db: db,
path: path,
}
ms.cond.L = &ms.mx
return ms, nil
}
func (e *BadgerMarkSetEnv) Close() error {
return os.RemoveAll(e.path)
}
func (s *BadgerMarkSet) Mark(c cid.Cid) error {
s.mx.Lock()
if s.pend == nil {
s.mx.Unlock()
return errMarkSetClosed
}
s.pend[string(c.Hash())] = struct{}{}
if len(s.pend) < badgerMarkSetBatchSize {
s.mx.Unlock()
return nil
}
pend := s.pend
seqno := s.seqno
s.seqno++
s.writing[seqno] = pend
s.pend = make(map[string]struct{})
s.writers++
s.mx.Unlock()
defer func() {
s.mx.Lock()
defer s.mx.Unlock()
delete(s.writing, seqno)
s.writers--
if s.writers == 0 {
s.cond.Broadcast()
}
}()
empty := []byte{} // not nil
batch := s.db.NewWriteBatch()
defer batch.Cancel()
for k := range pend {
if err := batch.Set([]byte(k), empty); err != nil {
return err
}
}
err := batch.Flush()
if err != nil {
return xerrors.Errorf("error flushing batch to badger markset: %w", err)
}
return nil
}
func (s *BadgerMarkSet) Has(c cid.Cid) (bool, error) {
s.mx.RLock()
defer s.mx.RUnlock()
if s.pend == nil {
return false, errMarkSetClosed
}
key := c.Hash()
pendKey := string(key)
_, ok := s.pend[pendKey]
if ok {
return true, nil
}
for _, wr := range s.writing {
_, ok := wr[pendKey]
if ok {
return true, nil
}
}
err := s.db.View(func(txn *badger.Txn) error {
_, err := txn.Get(key)
return err
})
switch err {
case nil:
return true, nil
case badger.ErrKeyNotFound:
return false, nil
default:
return false, xerrors.Errorf("error checking badger markset: %w", err)
}
}
func (s *BadgerMarkSet) Close() error {
s.mx.Lock()
defer s.mx.Unlock()
if s.pend == nil {
return nil
}
for s.writers > 0 {
s.cond.Wait()
}
s.pend = nil
db := s.db
s.db = nil
err := db.Close()
if err != nil {
return xerrors.Errorf("error closing badger markset: %w", err)
}
err = os.RemoveAll(s.path)
if err != nil {
return xerrors.Errorf("error deleting badger markset: %w", err)
}
return nil
}
func (s *BadgerMarkSet) SetConcurrent() {}
// badger logging through go-log
type badgerLogger struct {
*zap.SugaredLogger
skip2 *zap.SugaredLogger
}
func (b *badgerLogger) Warningf(format string, args ...interface{}) {}
func (b *badgerLogger) Infof(format string, args ...interface{}) {}
func (b *badgerLogger) Debugf(format string, args ...interface{}) {}
+9
View File
@@ -16,6 +16,15 @@ func TestBloomMarkSet(t *testing.T) {
testMarkSet(t, "bloom") testMarkSet(t, "bloom")
} }
func TestBadgerMarkSet(t *testing.T) {
bs := badgerMarkSetBatchSize
badgerMarkSetBatchSize = 1
t.Cleanup(func() {
badgerMarkSetBatchSize = bs
})
testMarkSet(t, "badger")
}
func testMarkSet(t *testing.T, lsType string) { func testMarkSet(t *testing.T, lsType string) {
t.Helper() t.Helper()
+25 -3
View File
@@ -62,8 +62,11 @@ func init() {
type Config struct { type Config struct {
// MarkSetType is the type of mark set to use. // MarkSetType is the type of mark set to use.
// //
// Only current sane value is "map", but we may add an option for a disk-backed // The default value is "map", which uses an in-memory map-backed markset.
// markset for memory-constrained situations. // If you are constrained in memory (i.e. compaction runs out of memory), you
// can use "badger", which will use a disk-backed markset using badger.
// Note that compaction will take quite a bit longer when using the "badger" option,
// but that shouldn't really matter (as long as it is under 7.5hrs).
MarkSetType string MarkSetType string
// DiscardColdBlocks indicates whether to skip moving cold blocks to the coldstore. // DiscardColdBlocks indicates whether to skip moving cold blocks to the coldstore.
@@ -71,6 +74,13 @@ type Config struct {
// which skips moving (as it is a noop, but still takes time to read all the cold objects) // which skips moving (as it is a noop, but still takes time to read all the cold objects)
// and directly purges cold blocks. // and directly purges cold blocks.
DiscardColdBlocks bool DiscardColdBlocks bool
// HotstoreMessageRetention indicates the hotstore retention policy for messages.
// It has the following semantics:
// - a value of 0 will only retain messages within the compaction boundary (4 finalities)
// - a positive integer indicates the number of finalities, outside the compaction boundary,
// for which messages will be retained in the hotstore.
HotStoreMessageRetention uint64
} }
// ChainAccessor allows the Splitstore to access the chain. It will most likely // ChainAccessor allows the Splitstore to access the chain. It will most likely
@@ -92,7 +102,8 @@ type SplitStore struct {
compacting int32 // compaction/prune/warmup in progress compacting int32 // compaction/prune/warmup in progress
closing int32 // the splitstore is closing closing int32 // the splitstore is closing
cfg *Config cfg *Config
path string
mx sync.Mutex mx sync.Mutex
warmupEpoch abi.ChainEpoch // protected by mx warmupEpoch abi.ChainEpoch // protected by mx
@@ -128,6 +139,9 @@ type SplitStore struct {
txnRefsMx sync.Mutex txnRefsMx sync.Mutex
txnRefs map[cid.Cid]struct{} txnRefs map[cid.Cid]struct{}
txnMissing map[cid.Cid]struct{} txnMissing map[cid.Cid]struct{}
// registered protectors
protectors []func(func(cid.Cid) error) error
} }
var _ bstore.Blockstore = (*SplitStore)(nil) var _ bstore.Blockstore = (*SplitStore)(nil)
@@ -156,6 +170,7 @@ func Open(path string, ds dstore.Datastore, hot, cold bstore.Blockstore, cfg *Co
// and now we can make a SplitStore // and now we can make a SplitStore
ss := &SplitStore{ ss := &SplitStore{
cfg: cfg, cfg: cfg,
path: path,
ds: ds, ds: ds,
cold: cold, cold: cold,
hot: hots, hot: hots,
@@ -520,6 +535,13 @@ func (s *SplitStore) Start(chain ChainAccessor) error {
return nil return nil
} }
func (s *SplitStore) AddProtector(protector func(func(cid.Cid) error) error) {
s.mx.Lock()
defer s.mx.Unlock()
s.protectors = append(s.protectors, protector)
}
func (s *SplitStore) Close() error { func (s *SplitStore) Close() error {
if !atomic.CompareAndSwapInt32(&s.closing, 0, 1) { if !atomic.CompareAndSwapInt32(&s.closing, 0, 1) {
// already closing // already closing
+150
View File
@@ -0,0 +1,150 @@
package splitstore
import (
"fmt"
"os"
"path/filepath"
"sync/atomic"
"time"
"golang.org/x/xerrors"
cid "github.com/ipfs/go-cid"
bstore "github.com/filecoin-project/lotus/blockstore"
"github.com/filecoin-project/lotus/chain/types"
)
// performs an asynchronous health-check on the splitstore; results are appended to
// <splitstore-path>/check.txt
func (s *SplitStore) Check() error {
s.headChangeMx.Lock()
defer s.headChangeMx.Unlock()
// try to take compaction lock and inhibit compaction while the health-check is running
if !atomic.CompareAndSwapInt32(&s.compacting, 0, 1) {
return xerrors.Errorf("can't acquire compaction lock; compacting operation in progress")
}
if s.compactionIndex == 0 {
atomic.StoreInt32(&s.compacting, 0)
return xerrors.Errorf("splitstore hasn't compacted yet; health check is not meaningful")
}
// check if we are actually closing first
if err := s.checkClosing(); err != nil {
atomic.StoreInt32(&s.compacting, 0)
return err
}
curTs := s.chain.GetHeaviestTipSet()
go func() {
defer atomic.StoreInt32(&s.compacting, 0)
log.Info("checking splitstore health")
start := time.Now()
err := s.doCheck(curTs)
if err != nil {
log.Errorf("error checking splitstore health: %s", err)
return
}
log.Infow("health check done", "took", time.Since(start))
}()
return nil
}
func (s *SplitStore) doCheck(curTs *types.TipSet) error {
currentEpoch := curTs.Height()
boundaryEpoch := currentEpoch - CompactionBoundary
outputPath := filepath.Join(s.path, "check.txt")
output, err := os.OpenFile(outputPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
return xerrors.Errorf("error opening check output file %s: %w", outputPath, err)
}
defer output.Close() //nolint:errcheck
write := func(format string, args ...interface{}) {
_, err := fmt.Fprintf(output, format+"\n", args...)
if err != nil {
log.Warnf("error writing check output: %s", err)
}
}
ts, _ := time.Now().MarshalText()
write("---------------------------------------------")
write("start check at %s", ts)
write("current epoch: %d", currentEpoch)
write("boundary epoch: %d", boundaryEpoch)
write("compaction index: %d", s.compactionIndex)
write("--")
var coldCnt, missingCnt int64
err = s.walkChain(curTs, boundaryEpoch, boundaryEpoch,
func(c cid.Cid) error {
if isUnitaryObject(c) {
return errStopWalk
}
has, err := s.hot.Has(c)
if err != nil {
return xerrors.Errorf("error checking hotstore: %w", err)
}
if has {
return nil
}
has, err = s.cold.Has(c)
if err != nil {
return xerrors.Errorf("error checking coldstore: %w", err)
}
if has {
coldCnt++
write("cold object reference: %s", c)
} else {
missingCnt++
write("missing object reference: %s", c)
return errStopWalk
}
return nil
})
if err != nil {
err = xerrors.Errorf("error walking chain: %w", err)
write("ERROR: %s", err)
return err
}
log.Infow("check done", "cold", coldCnt, "missing", missingCnt)
write("--")
write("cold: %d missing: %d", coldCnt, missingCnt)
write("DONE")
return nil
}
// provides some basic information about the splitstore
func (s *SplitStore) Info() map[string]interface{} {
info := make(map[string]interface{})
info["base epoch"] = s.baseEpoch
info["warmup epoch"] = s.warmupEpoch
info["compactions"] = s.compactionIndex
sizer, ok := s.hot.(bstore.BlockstoreSize)
if ok {
size, err := sizer.Size()
if err != nil {
log.Warnf("error getting hotstore size: %s", err)
} else {
info["hotstore size"] = size
}
}
return info
}
+60 -33
View File
@@ -184,16 +184,6 @@ func (s *SplitStore) trackTxnRef(c cid.Cid) {
return return
} }
if s.txnProtect != nil {
mark, err := s.txnProtect.Has(c)
if err != nil {
log.Warnf("error checking markset: %s", err)
// track it anyways
} else if mark {
return
}
}
s.txnRefsMx.Lock() s.txnRefsMx.Lock()
s.txnRefs[c] = struct{}{} s.txnRefs[c] = struct{}{}
s.txnRefsMx.Unlock() s.txnRefsMx.Unlock()
@@ -209,27 +199,11 @@ func (s *SplitStore) trackTxnRefMany(cids []cid.Cid) {
s.txnRefsMx.Lock() s.txnRefsMx.Lock()
defer s.txnRefsMx.Unlock() defer s.txnRefsMx.Unlock()
quiet := false
for _, c := range cids { for _, c := range cids {
if isUnitaryObject(c) { if isUnitaryObject(c) {
continue continue
} }
if s.txnProtect != nil {
mark, err := s.txnProtect.Has(c)
if err != nil {
if !quiet {
quiet = true
log.Warnf("error checking markset: %s", err)
}
// track it anyways
}
if mark {
continue
}
}
s.txnRefs[c] = struct{}{} s.txnRefs[c] = struct{}{}
} }
@@ -345,6 +319,30 @@ func (s *SplitStore) doTxnProtect(root cid.Cid, markSet MarkSet) error {
}) })
} }
func (s *SplitStore) applyProtectors() error {
s.mx.Lock()
defer s.mx.Unlock()
count := 0
for _, protect := range s.protectors {
err := protect(func(c cid.Cid) error {
s.trackTxnRef(c)
count++
return nil
})
if err != nil {
return xerrors.Errorf("error applynig protector: %w", err)
}
}
if count > 0 {
log.Infof("protected %d references through %d protectors", count, len(s.protectors))
}
return nil
}
// --- Compaction --- // --- Compaction ---
// Compaction works transactionally with the following algorithm: // Compaction works transactionally with the following algorithm:
// - We prepare a transaction, whereby all i/o referenced objects through the API are tracked. // - We prepare a transaction, whereby all i/o referenced objects through the API are tracked.
@@ -376,7 +374,13 @@ func (s *SplitStore) doCompact(curTs *types.TipSet) error {
currentEpoch := curTs.Height() currentEpoch := curTs.Height()
boundaryEpoch := currentEpoch - CompactionBoundary boundaryEpoch := currentEpoch - CompactionBoundary
log.Infow("running compaction", "currentEpoch", currentEpoch, "baseEpoch", s.baseEpoch, "boundaryEpoch", boundaryEpoch, "compactionIndex", s.compactionIndex) var inclMsgsEpoch abi.ChainEpoch
inclMsgsRange := abi.ChainEpoch(s.cfg.HotStoreMessageRetention) * build.Finality
if inclMsgsRange < boundaryEpoch {
inclMsgsEpoch = boundaryEpoch - inclMsgsRange
}
log.Infow("running compaction", "currentEpoch", currentEpoch, "baseEpoch", s.baseEpoch, "boundaryEpoch", boundaryEpoch, "inclMsgsEpoch", inclMsgsEpoch, "compactionIndex", s.compactionIndex)
markSet, err := s.markSetEnv.Create("live", s.markSetSize) markSet, err := s.markSetEnv.Create("live", s.markSetSize)
if err != nil { if err != nil {
@@ -392,13 +396,21 @@ func (s *SplitStore) doCompact(curTs *types.TipSet) error {
// we are ready for concurrent marking // we are ready for concurrent marking
s.beginTxnMarking(markSet) s.beginTxnMarking(markSet)
// 0. track all protected references at beginning of compaction; anything added later should
// be transactionally protected by the write
log.Info("protecting references with registered protectors")
err = s.applyProtectors()
if err != nil {
return err
}
// 1. mark reachable objects by walking the chain from the current epoch; we keep state roots // 1. mark reachable objects by walking the chain from the current epoch; we keep state roots
// and messages until the boundary epoch. // and messages until the boundary epoch.
log.Info("marking reachable objects") log.Info("marking reachable objects")
startMark := time.Now() startMark := time.Now()
var count int64 var count int64
err = s.walkChain(curTs, boundaryEpoch, true, err = s.walkChain(curTs, boundaryEpoch, inclMsgsEpoch,
func(c cid.Cid) error { func(c cid.Cid) error {
if isUnitaryObject(c) { if isUnitaryObject(c) {
return errStopWalk return errStopWalk
@@ -593,7 +605,7 @@ func (s *SplitStore) endTxnProtect() {
s.txnMissing = nil s.txnMissing = nil
} }
func (s *SplitStore) walkChain(ts *types.TipSet, boundary abi.ChainEpoch, inclMsgs bool, func (s *SplitStore) walkChain(ts *types.TipSet, inclState, inclMsgs abi.ChainEpoch,
f func(cid.Cid) error) error { f func(cid.Cid) error) error {
visited := cid.NewSet() visited := cid.NewSet()
walked := cid.NewSet() walked := cid.NewSet()
@@ -601,6 +613,8 @@ func (s *SplitStore) walkChain(ts *types.TipSet, boundary abi.ChainEpoch, inclMs
walkCnt := 0 walkCnt := 0
scanCnt := 0 scanCnt := 0
stopWalk := func(_ cid.Cid) error { return errStopWalk }
walkBlock := func(c cid.Cid) error { walkBlock := func(c cid.Cid) error {
if !visited.Visit(c) { if !visited.Visit(c) {
return nil return nil
@@ -621,10 +635,19 @@ func (s *SplitStore) walkChain(ts *types.TipSet, boundary abi.ChainEpoch, inclMs
return xerrors.Errorf("error unmarshaling block header (cid: %s): %w", c, err) return xerrors.Errorf("error unmarshaling block header (cid: %s): %w", c, err)
} }
// we only scan the block if it is at or above the boundary // message are retained if within the inclMsgs boundary
if hdr.Height >= boundary || hdr.Height == 0 { if hdr.Height >= inclMsgs && hdr.Height > 0 {
scanCnt++ if inclMsgs < inclState {
if inclMsgs && hdr.Height > 0 { // we need to use walkObjectIncomplete here, as messages/receipts may be missing early on if we
// synced from snapshot and have a long HotStoreMessageRetentionPolicy.
if err := s.walkObjectIncomplete(hdr.Messages, walked, f, stopWalk); err != nil {
return xerrors.Errorf("error walking messages (cid: %s): %w", hdr.Messages, err)
}
if err := s.walkObjectIncomplete(hdr.ParentMessageReceipts, walked, f, stopWalk); err != nil {
return xerrors.Errorf("error walking messages receipts (cid: %s): %w", hdr.ParentMessageReceipts, err)
}
} else {
if err := s.walkObject(hdr.Messages, walked, f); err != nil { if err := s.walkObject(hdr.Messages, walked, f); err != nil {
return xerrors.Errorf("error walking messages (cid: %s): %w", hdr.Messages, err) return xerrors.Errorf("error walking messages (cid: %s): %w", hdr.Messages, err)
} }
@@ -633,10 +656,14 @@ func (s *SplitStore) walkChain(ts *types.TipSet, boundary abi.ChainEpoch, inclMs
return xerrors.Errorf("error walking message receipts (cid: %s): %w", hdr.ParentMessageReceipts, err) return xerrors.Errorf("error walking message receipts (cid: %s): %w", hdr.ParentMessageReceipts, err)
} }
} }
}
// state is only retained if within the inclState boundary, with the exception of genesis
if hdr.Height >= inclState || hdr.Height == 0 {
if err := s.walkObject(hdr.ParentStateRoot, walked, f); err != nil { if err := s.walkObject(hdr.ParentStateRoot, walked, f); err != nil {
return xerrors.Errorf("error walking state root (cid: %s): %w", hdr.ParentStateRoot, err) return xerrors.Errorf("error walking state root (cid: %s): %w", hdr.ParentStateRoot, err)
} }
scanCnt++
} }
if hdr.Height > 0 { if hdr.Height > 0 {
+64 -6
View File
@@ -24,6 +24,7 @@ import (
func init() { func init() {
CompactionThreshold = 5 CompactionThreshold = 5
CompactionBoundary = 2 CompactionBoundary = 2
WarmupBoundary = 0
logging.SetLogLevel("splitstore", "DEBUG") logging.SetLogLevel("splitstore", "DEBUG")
} }
@@ -63,6 +64,20 @@ func testSplitStore(t *testing.T, cfg *Config) {
t.Fatal(err) t.Fatal(err)
} }
// create a garbage block that is protected with a rgistered protector
protected := blocks.NewBlock([]byte("protected!"))
err = hot.Put(protected)
if err != nil {
t.Fatal(err)
}
// and another one that is not protected
unprotected := blocks.NewBlock([]byte("unprotected!"))
err = hot.Put(unprotected)
if err != nil {
t.Fatal(err)
}
// open the splitstore // open the splitstore
ss, err := Open("", ds, hot, cold, cfg) ss, err := Open("", ds, hot, cold, cfg)
if err != nil { if err != nil {
@@ -70,6 +85,11 @@ func testSplitStore(t *testing.T, cfg *Config) {
} }
defer ss.Close() //nolint defer ss.Close() //nolint
// register our protector
ss.AddProtector(func(protect func(cid.Cid) error) error {
return protect(protected.Cid())
})
err = ss.Start(chain) err = ss.Start(chain)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@@ -132,8 +152,8 @@ func testSplitStore(t *testing.T, cfg *Config) {
t.Errorf("expected %d blocks, but got %d", 2, coldCnt) t.Errorf("expected %d blocks, but got %d", 2, coldCnt)
} }
if hotCnt != 10 { if hotCnt != 12 {
t.Errorf("expected %d blocks, but got %d", 10, hotCnt) t.Errorf("expected %d blocks, but got %d", 12, hotCnt)
} }
// trigger a compaction // trigger a compaction
@@ -146,12 +166,41 @@ func testSplitStore(t *testing.T, cfg *Config) {
coldCnt = countBlocks(cold) coldCnt = countBlocks(cold)
hotCnt = countBlocks(hot) hotCnt = countBlocks(hot)
if coldCnt != 5 { if coldCnt != 6 {
t.Errorf("expected %d cold blocks, but got %d", 5, coldCnt) t.Errorf("expected %d cold blocks, but got %d", 6, coldCnt)
} }
if hotCnt != 17 { if hotCnt != 18 {
t.Errorf("expected %d hot blocks, but got %d", 17, hotCnt) t.Errorf("expected %d hot blocks, but got %d", 18, hotCnt)
}
// ensure our protected block is still there
has, err := hot.Has(protected.Cid())
if err != nil {
t.Fatal(err)
}
if !has {
t.Fatal("protected block is missing from hotstore")
}
// ensure our unprotected block is in the coldstore now
has, err = hot.Has(unprotected.Cid())
if err != nil {
t.Fatal(err)
}
if has {
t.Fatal("unprotected block is still in hotstore")
}
has, err = cold.Has(unprotected.Cid())
if err != nil {
t.Fatal(err)
}
if !has {
t.Fatal("unprotected block is missing from coldstore")
} }
// Make sure we can revert without panicking. // Make sure we can revert without panicking.
@@ -162,6 +211,15 @@ func TestSplitStoreCompaction(t *testing.T) {
testSplitStore(t, &Config{MarkSetType: "map"}) testSplitStore(t, &Config{MarkSetType: "map"})
} }
func TestSplitStoreCompactionWithBadger(t *testing.T) {
bs := badgerMarkSetBatchSize
badgerMarkSetBatchSize = 1
t.Cleanup(func() {
badgerMarkSetBatchSize = bs
})
testSplitStore(t, &Config{MarkSetType: "badger"})
}
type mockChain struct { type mockChain struct {
t testing.TB t testing.TB
+13 -2
View File
@@ -9,10 +9,17 @@ import (
blocks "github.com/ipfs/go-block-format" blocks "github.com/ipfs/go-block-format"
cid "github.com/ipfs/go-cid" cid "github.com/ipfs/go-cid"
"github.com/filecoin-project/go-state-types/abi"
bstore "github.com/filecoin-project/lotus/blockstore" bstore "github.com/filecoin-project/lotus/blockstore"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
) )
var (
// WarmupBoundary is the number of epochs to load state during warmup.
WarmupBoundary = build.Finality
)
// warmup acuiqres the compaction lock and spawns a goroutine to warm up the hotstore; // warmup acuiqres the compaction lock and spawns a goroutine to warm up the hotstore;
// this is necessary when we sync from a snapshot or when we enable the splitstore // this is necessary when we sync from a snapshot or when we enable the splitstore
// on top of an existing blockstore (which becomes the coldstore). // on top of an existing blockstore (which becomes the coldstore).
@@ -43,12 +50,16 @@ func (s *SplitStore) warmup(curTs *types.TipSet) error {
// and headers all the way up to genesis. // and headers all the way up to genesis.
// objects are written in batches so as to minimize overhead. // objects are written in batches so as to minimize overhead.
func (s *SplitStore) doWarmup(curTs *types.TipSet) error { func (s *SplitStore) doWarmup(curTs *types.TipSet) error {
var boundaryEpoch abi.ChainEpoch
epoch := curTs.Height() epoch := curTs.Height()
if WarmupBoundary < epoch {
boundaryEpoch = epoch - WarmupBoundary
}
batchHot := make([]blocks.Block, 0, batchSize) batchHot := make([]blocks.Block, 0, batchSize)
count := int64(0) count := int64(0)
xcount := int64(0) xcount := int64(0)
missing := int64(0) missing := int64(0)
err := s.walkChain(curTs, epoch, false, err := s.walkChain(curTs, boundaryEpoch, epoch+1, // we don't load messages/receipts in warmup
func(c cid.Cid) error { func(c cid.Cid) error {
if isUnitaryObject(c) { if isUnitaryObject(c) {
return errStopWalk return errStopWalk
@@ -69,7 +80,7 @@ func (s *SplitStore) doWarmup(curTs *types.TipSet) error {
if err != nil { if err != nil {
if err == bstore.ErrNotFound { if err == bstore.ErrNotFound {
missing++ missing++
return nil return errStopWalk
} }
return err return err
} }
Binary file not shown.
Binary file not shown.
Binary file not shown.
+9 -8
View File
@@ -28,18 +28,19 @@ var UpgradeAssemblyHeight = abi.ChainEpoch(-5)
var UpgradeLiftoffHeight = abi.ChainEpoch(-6) var UpgradeLiftoffHeight = abi.ChainEpoch(-6)
var UpgradeKumquatHeight = abi.ChainEpoch(-7) var UpgradeKumquatHeight = abi.ChainEpoch(-7)
var UpgradeCalicoHeight = abi.ChainEpoch(-8) var UpgradePricelistOopsHeight = abi.ChainEpoch(-8)
var UpgradePersianHeight = abi.ChainEpoch(-9) var UpgradeCalicoHeight = abi.ChainEpoch(-9)
var UpgradeOrangeHeight = abi.ChainEpoch(-10) var UpgradePersianHeight = abi.ChainEpoch(-10)
var UpgradeClausHeight = abi.ChainEpoch(-11) var UpgradeOrangeHeight = abi.ChainEpoch(-11)
var UpgradeClausHeight = abi.ChainEpoch(-12)
var UpgradeTrustHeight = abi.ChainEpoch(-12) var UpgradeTrustHeight = abi.ChainEpoch(-13)
var UpgradeNorwegianHeight = abi.ChainEpoch(-13) var UpgradeNorwegianHeight = abi.ChainEpoch(-14)
var UpgradeTurboHeight = abi.ChainEpoch(-14) var UpgradeTurboHeight = abi.ChainEpoch(-15)
var UpgradeHyperdriveHeight = abi.ChainEpoch(-15) var UpgradeHyperdriveHeight = abi.ChainEpoch(-16)
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet, 0: DrandMainnet,
+1
View File
@@ -28,6 +28,7 @@ var UpgradeAssemblyHeight = abi.ChainEpoch(30)
const UpgradeTapeHeight = 60 const UpgradeTapeHeight = 60
const UpgradeLiftoffHeight = -5 const UpgradeLiftoffHeight = -5
const UpgradeKumquatHeight = 90 const UpgradeKumquatHeight = 90
const UpgradePricelistOopsHeight = 119
const UpgradeCalicoHeight = 120 const UpgradeCalicoHeight = 120
const UpgradePersianHeight = 150 const UpgradePersianHeight = 150
const UpgradeClausHeight = 180 const UpgradeClausHeight = 180
+2
View File
@@ -33,6 +33,8 @@ const UpgradeLiftoffHeight = -5
const UpgradeKumquatHeight = 90 const UpgradeKumquatHeight = 90
const UpgradePricelistOopsHeight = 119
const UpgradeCalicoHeight = 120 const UpgradeCalicoHeight = 120
const UpgradePersianHeight = UpgradeCalicoHeight + (builtin2.EpochsInHour * 1) const UpgradePersianHeight = UpgradeCalicoHeight + (builtin2.EpochsInHour * 1)
+9 -8
View File
@@ -31,18 +31,19 @@ var UpgradeAssemblyHeight = abi.ChainEpoch(-5)
var UpgradeLiftoffHeight = abi.ChainEpoch(-6) var UpgradeLiftoffHeight = abi.ChainEpoch(-6)
var UpgradeKumquatHeight = abi.ChainEpoch(-7) var UpgradeKumquatHeight = abi.ChainEpoch(-7)
var UpgradeCalicoHeight = abi.ChainEpoch(-8) var UpgradePricelistOopsHeight = abi.ChainEpoch(-8)
var UpgradePersianHeight = abi.ChainEpoch(-9) var UpgradeCalicoHeight = abi.ChainEpoch(-9)
var UpgradeOrangeHeight = abi.ChainEpoch(-10) var UpgradePersianHeight = abi.ChainEpoch(-10)
var UpgradeClausHeight = abi.ChainEpoch(-11) var UpgradeOrangeHeight = abi.ChainEpoch(-11)
var UpgradeClausHeight = abi.ChainEpoch(-12)
var UpgradeTrustHeight = abi.ChainEpoch(-12) var UpgradeTrustHeight = abi.ChainEpoch(-13)
var UpgradeNorwegianHeight = abi.ChainEpoch(-13) var UpgradeNorwegianHeight = abi.ChainEpoch(-14)
var UpgradeTurboHeight = abi.ChainEpoch(-14) var UpgradeTurboHeight = abi.ChainEpoch(-15)
var UpgradeHyperdriveHeight = abi.ChainEpoch(-15) var UpgradeHyperdriveHeight = abi.ChainEpoch(-16)
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet, 0: DrandMainnet,
+1
View File
@@ -45,6 +45,7 @@ const UpgradeLiftoffHeight = 148888
const UpgradeKumquatHeight = 170000 const UpgradeKumquatHeight = 170000
const UpgradePricelistOopsHeight = 265199
const UpgradeCalicoHeight = 265200 const UpgradeCalicoHeight = 265200
const UpgradePersianHeight = UpgradeCalicoHeight + (builtin2.EpochsInHour * 60) const UpgradePersianHeight = UpgradeCalicoHeight + (builtin2.EpochsInHour * 60)
+2 -1
View File
@@ -32,6 +32,7 @@ const UpgradeTapeHeight = 60
const UpgradeKumquatHeight = 90 const UpgradeKumquatHeight = 90
const UpgradePricelistOopsHeight = 99
const UpgradeCalicoHeight = 100 const UpgradeCalicoHeight = 100
const UpgradePersianHeight = UpgradeCalicoHeight + (builtin2.EpochsInHour * 1) const UpgradePersianHeight = UpgradeCalicoHeight + (builtin2.EpochsInHour * 1)
@@ -42,7 +43,7 @@ const UpgradeOrangeHeight = 300
const UpgradeTrustHeight = 600 const UpgradeTrustHeight = 600
const UpgradeNorwegianHeight = 201000 const UpgradeNorwegianHeight = 201000
const UpgradeTurboHeight = 203000 const UpgradeTurboHeight = 203000
const UpgradeHyperdriveHeight = 999999999 const UpgradeHyperdriveHeight = 379178
func init() { func init() {
// Minimum block production power is set to 4 TiB // Minimum block production power is set to 4 TiB
+16 -15
View File
@@ -82,21 +82,22 @@ var (
UpgradeBreezeHeight abi.ChainEpoch = -1 UpgradeBreezeHeight abi.ChainEpoch = -1
BreezeGasTampingDuration abi.ChainEpoch = 0 BreezeGasTampingDuration abi.ChainEpoch = 0
UpgradeSmokeHeight abi.ChainEpoch = -1 UpgradeSmokeHeight abi.ChainEpoch = -1
UpgradeIgnitionHeight abi.ChainEpoch = -2 UpgradeIgnitionHeight abi.ChainEpoch = -2
UpgradeRefuelHeight abi.ChainEpoch = -3 UpgradeRefuelHeight abi.ChainEpoch = -3
UpgradeTapeHeight abi.ChainEpoch = -4 UpgradeTapeHeight abi.ChainEpoch = -4
UpgradeAssemblyHeight abi.ChainEpoch = 10 UpgradeAssemblyHeight abi.ChainEpoch = 10
UpgradeLiftoffHeight abi.ChainEpoch = -5 UpgradeLiftoffHeight abi.ChainEpoch = -5
UpgradeKumquatHeight abi.ChainEpoch = -6 UpgradeKumquatHeight abi.ChainEpoch = -6
UpgradeCalicoHeight abi.ChainEpoch = -7 UpgradePricelistOopsHeight abi.ChainEpoch = -7
UpgradePersianHeight abi.ChainEpoch = -8 UpgradeCalicoHeight abi.ChainEpoch = -8
UpgradeOrangeHeight abi.ChainEpoch = -9 UpgradePersianHeight abi.ChainEpoch = -9
UpgradeClausHeight abi.ChainEpoch = -10 UpgradeOrangeHeight abi.ChainEpoch = -10
UpgradeTrustHeight abi.ChainEpoch = -11 UpgradeClausHeight abi.ChainEpoch = -11
UpgradeNorwegianHeight abi.ChainEpoch = -12 UpgradeTrustHeight abi.ChainEpoch = -12
UpgradeTurboHeight abi.ChainEpoch = -13 UpgradeNorwegianHeight abi.ChainEpoch = -13
UpgradeHyperdriveHeight abi.ChainEpoch = -13 UpgradeTurboHeight abi.ChainEpoch = -14
UpgradeHyperdriveHeight abi.ChainEpoch = -15
DrandSchedule = map[abi.ChainEpoch]DrandEnum{ DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet, 0: DrandMainnet,
@@ -105,6 +105,7 @@ type State interface {
// UnallocatedSectorNumbers returns up to count unallocated sector numbers (or less than // UnallocatedSectorNumbers returns up to count unallocated sector numbers (or less than
// count if there aren't enough). // count if there aren't enough).
UnallocatedSectorNumbers(count int) ([]abi.SectorNumber, error) UnallocatedSectorNumbers(count int) ([]abi.SectorNumber, error)
GetAllocatedSectors() (*bitfield.BitField, error)
// Note that ProvingPeriodStart is deprecated and will be renamed / removed in a future version of actors // Note that ProvingPeriodStart is deprecated and will be renamed / removed in a future version of actors
GetProvingPeriodStart() (abi.ChainEpoch, error) GetProvingPeriodStart() (abi.ChainEpoch, error)
+1
View File
@@ -164,6 +164,7 @@ type State interface {
// UnallocatedSectorNumbers returns up to count unallocated sector numbers (or less than // UnallocatedSectorNumbers returns up to count unallocated sector numbers (or less than
// count if there aren't enough). // count if there aren't enough).
UnallocatedSectorNumbers(count int) ([]abi.SectorNumber, error) UnallocatedSectorNumbers(count int) ([]abi.SectorNumber, error)
GetAllocatedSectors() (*bitfield.BitField, error)
// Note that ProvingPeriodStart is deprecated and will be renamed / removed in a future version of actors // Note that ProvingPeriodStart is deprecated and will be renamed / removed in a future version of actors
GetProvingPeriodStart() (abi.ChainEpoch, error) GetProvingPeriodStart() (abi.ChainEpoch, error)
@@ -318,6 +318,15 @@ func (s *state{{.v}}) UnallocatedSectorNumbers(count int) ([]abi.SectorNumber, e
return sectors, nil return sectors, nil
} }
func (s *state{{.v}}) GetAllocatedSectors() (*bitfield.BitField, error) {
var allocatedSectors bitfield.BitField
if err := s.store.Get(s.store.Context(), s.State.AllocatedSectors, &allocatedSectors); err != nil {
return nil, err
}
return &allocatedSectors, nil
}
func (s *state{{.v}}) LoadDeadline(idx uint64) (Deadline, error) { func (s *state{{.v}}) LoadDeadline(idx uint64) (Deadline, error) {
dls, err := s.State.LoadDeadlines(s.store) dls, err := s.State.LoadDeadlines(s.store)
if err != nil { if err != nil {
+9
View File
@@ -311,6 +311,15 @@ func (s *state0) UnallocatedSectorNumbers(count int) ([]abi.SectorNumber, error)
return sectors, nil return sectors, nil
} }
func (s *state0) GetAllocatedSectors() (*bitfield.BitField, error) {
var allocatedSectors bitfield.BitField
if err := s.store.Get(s.store.Context(), s.State.AllocatedSectors, &allocatedSectors); err != nil {
return nil, err
}
return &allocatedSectors, nil
}
func (s *state0) LoadDeadline(idx uint64) (Deadline, error) { func (s *state0) LoadDeadline(idx uint64) (Deadline, error) {
dls, err := s.State.LoadDeadlines(s.store) dls, err := s.State.LoadDeadlines(s.store)
if err != nil { if err != nil {
+9
View File
@@ -309,6 +309,15 @@ func (s *state2) UnallocatedSectorNumbers(count int) ([]abi.SectorNumber, error)
return sectors, nil return sectors, nil
} }
func (s *state2) GetAllocatedSectors() (*bitfield.BitField, error) {
var allocatedSectors bitfield.BitField
if err := s.store.Get(s.store.Context(), s.State.AllocatedSectors, &allocatedSectors); err != nil {
return nil, err
}
return &allocatedSectors, nil
}
func (s *state2) LoadDeadline(idx uint64) (Deadline, error) { func (s *state2) LoadDeadline(idx uint64) (Deadline, error) {
dls, err := s.State.LoadDeadlines(s.store) dls, err := s.State.LoadDeadlines(s.store)
if err != nil { if err != nil {
+9
View File
@@ -311,6 +311,15 @@ func (s *state3) UnallocatedSectorNumbers(count int) ([]abi.SectorNumber, error)
return sectors, nil return sectors, nil
} }
func (s *state3) GetAllocatedSectors() (*bitfield.BitField, error) {
var allocatedSectors bitfield.BitField
if err := s.store.Get(s.store.Context(), s.State.AllocatedSectors, &allocatedSectors); err != nil {
return nil, err
}
return &allocatedSectors, nil
}
func (s *state3) LoadDeadline(idx uint64) (Deadline, error) { func (s *state3) LoadDeadline(idx uint64) (Deadline, error) {
dls, err := s.State.LoadDeadlines(s.store) dls, err := s.State.LoadDeadlines(s.store)
if err != nil { if err != nil {
+9
View File
@@ -311,6 +311,15 @@ func (s *state4) UnallocatedSectorNumbers(count int) ([]abi.SectorNumber, error)
return sectors, nil return sectors, nil
} }
func (s *state4) GetAllocatedSectors() (*bitfield.BitField, error) {
var allocatedSectors bitfield.BitField
if err := s.store.Get(s.store.Context(), s.State.AllocatedSectors, &allocatedSectors); err != nil {
return nil, err
}
return &allocatedSectors, nil
}
func (s *state4) LoadDeadline(idx uint64) (Deadline, error) { func (s *state4) LoadDeadline(idx uint64) (Deadline, error) {
dls, err := s.State.LoadDeadlines(s.store) dls, err := s.State.LoadDeadlines(s.store)
if err != nil { if err != nil {
+9
View File
@@ -311,6 +311,15 @@ func (s *state5) UnallocatedSectorNumbers(count int) ([]abi.SectorNumber, error)
return sectors, nil return sectors, nil
} }
func (s *state5) GetAllocatedSectors() (*bitfield.BitField, error) {
var allocatedSectors bitfield.BitField
if err := s.store.Get(s.store.Context(), s.State.AllocatedSectors, &allocatedSectors); err != nil {
return nil, err
}
return &allocatedSectors, nil
}
func (s *state5) LoadDeadline(idx uint64) (Deadline, error) { func (s *state5) LoadDeadline(idx uint64) (Deadline, error) {
dls, err := s.State.LoadDeadlines(s.store) dls, err := s.State.LoadDeadlines(s.store)
if err != nil { if err != nil {
+1 -1
View File
@@ -25,7 +25,7 @@ func VersionForNetwork(version network.Version) Version {
switch version { switch version {
case network.Version0, network.Version1, network.Version2, network.Version3: case network.Version0, network.Version1, network.Version2, network.Version3:
return Version0 return Version0
case network.Version4, network.Version5, network.Version6, network.Version7, network.Version8, network.Version9: case network.Version4, network.Version5, network.Version6, network.Version6AndAHalf, network.Version7, network.Version8, network.Version9:
return Version2 return Version2
case network.Version10, network.Version11: case network.Version10, network.Version11:
return Version3 return Version3
+27 -11
View File
@@ -5,6 +5,9 @@ import (
"math" "math"
"sync" "sync"
"github.com/filecoin-project/lotus/api"
lru "github.com/hashicorp/golang-lru"
"github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
@@ -464,14 +467,20 @@ type messageEvents struct {
lk sync.RWMutex lk sync.RWMutex
matchers map[triggerID]MsgMatchFunc matchers map[triggerID]MsgMatchFunc
blockMsgLk sync.Mutex
blockMsgCache *lru.ARCCache
} }
func newMessageEvents(ctx context.Context, hcAPI headChangeAPI, cs EventAPI) messageEvents { func newMessageEvents(ctx context.Context, hcAPI headChangeAPI, cs EventAPI) messageEvents {
blsMsgCache, _ := lru.NewARC(500)
return messageEvents{ return messageEvents{
ctx: ctx, ctx: ctx,
cs: cs, cs: cs,
hcAPI: hcAPI, hcAPI: hcAPI,
matchers: make(map[triggerID]MsgMatchFunc), matchers: make(map[triggerID]MsgMatchFunc),
blockMsgLk: sync.Mutex{},
blockMsgCache: blsMsgCache,
} }
} }
@@ -515,14 +524,21 @@ func (me *messageEvents) messagesForTs(ts *types.TipSet, consume func(*types.Mes
seen := map[cid.Cid]struct{}{} seen := map[cid.Cid]struct{}{}
for _, tsb := range ts.Blocks() { for _, tsb := range ts.Blocks() {
me.blockMsgLk.Lock()
msgs, err := me.cs.ChainGetBlockMessages(context.TODO(), tsb.Cid()) msgsI, ok := me.blockMsgCache.Get(tsb.Cid())
if err != nil { var err error
log.Errorf("messagesForTs MessagesForBlock failed (ts.H=%d, Bcid:%s, B.Mcid:%s): %s", ts.Height(), tsb.Cid(), tsb.Messages, err) if !ok {
// this is quite bad, but probably better than missing all the other updates msgsI, err = me.cs.ChainGetBlockMessages(context.TODO(), tsb.Cid())
continue if err != nil {
log.Errorf("messagesForTs MessagesForBlock failed (ts.H=%d, Bcid:%s, B.Mcid:%s): %s", ts.Height(), tsb.Cid(), tsb.Messages, err)
// this is quite bad, but probably better than missing all the other updates
me.blockMsgLk.Unlock()
continue
}
me.blockMsgCache.Add(tsb.Cid(), msgsI)
} }
me.blockMsgLk.Unlock()
msgs := msgsI.(*api.BlockMessages)
for _, m := range msgs.BlsMessages { for _, m := range msgs.BlsMessages {
_, ok := seen[m.Cid()] _, ok := seen[m.Cid()]
if ok { if ok {
+129 -61
View File
@@ -6,6 +6,8 @@ import (
"sync" "sync"
"testing" "testing"
"gotest.tools/assert"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"github.com/multiformats/go-multihash" "github.com/multiformats/go-multihash"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -44,25 +46,43 @@ type fakeCS struct {
tipsets map[types.TipSetKey]*types.TipSet tipsets map[types.TipSetKey]*types.TipSet
sub func(rev, app []*types.TipSet) sub func(rev, app []*types.TipSet)
callNumberLk sync.Mutex
callNumber map[string]int
} }
func (fcs *fakeCS) ChainHead(ctx context.Context) (*types.TipSet, error) { func (fcs *fakeCS) ChainHead(ctx context.Context) (*types.TipSet, error) {
fcs.callNumberLk.Lock()
defer fcs.callNumberLk.Unlock()
fcs.callNumber["ChainHead"] = fcs.callNumber["ChainHead"] + 1
panic("implement me") panic("implement me")
} }
func (fcs *fakeCS) ChainGetTipSet(ctx context.Context, key types.TipSetKey) (*types.TipSet, error) { func (fcs *fakeCS) ChainGetTipSet(ctx context.Context, key types.TipSetKey) (*types.TipSet, error) {
fcs.callNumberLk.Lock()
defer fcs.callNumberLk.Unlock()
fcs.callNumber["ChainGetTipSet"] = fcs.callNumber["ChainGetTipSet"] + 1
return fcs.tipsets[key], nil return fcs.tipsets[key], nil
} }
func (fcs *fakeCS) StateSearchMsg(ctx context.Context, from types.TipSetKey, msg cid.Cid, limit abi.ChainEpoch, allowReplaced bool) (*api.MsgLookup, error) { func (fcs *fakeCS) StateSearchMsg(ctx context.Context, from types.TipSetKey, msg cid.Cid, limit abi.ChainEpoch, allowReplaced bool) (*api.MsgLookup, error) {
fcs.callNumberLk.Lock()
defer fcs.callNumberLk.Unlock()
fcs.callNumber["StateSearchMsg"] = fcs.callNumber["StateSearchMsg"] + 1
return nil, nil return nil, nil
} }
func (fcs *fakeCS) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) { func (fcs *fakeCS) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) {
fcs.callNumberLk.Lock()
defer fcs.callNumberLk.Unlock()
fcs.callNumber["StateGetActor"] = fcs.callNumber["StateGetActor"] + 1
panic("Not Implemented") panic("Not Implemented")
} }
func (fcs *fakeCS) ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) { func (fcs *fakeCS) ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) {
fcs.callNumberLk.Lock()
defer fcs.callNumberLk.Unlock()
fcs.callNumber["ChainGetTipSetByHeight"] = fcs.callNumber["ChainGetTipSetByHeight"] + 1
panic("Not Implemented") panic("Not Implemented")
} }
@@ -113,6 +133,10 @@ func (fcs *fakeCS) makeTs(t *testing.T, parents []cid.Cid, h abi.ChainEpoch, msg
} }
func (fcs *fakeCS) ChainNotify(context.Context) (<-chan []*api.HeadChange, error) { func (fcs *fakeCS) ChainNotify(context.Context) (<-chan []*api.HeadChange, error) {
fcs.callNumberLk.Lock()
defer fcs.callNumberLk.Unlock()
fcs.callNumber["ChainNotify"] = fcs.callNumber["ChainNotify"] + 1
out := make(chan []*api.HeadChange, 1) out := make(chan []*api.HeadChange, 1)
best, err := fcs.tsc.best() best, err := fcs.tsc.best()
if err != nil { if err != nil {
@@ -143,6 +167,9 @@ func (fcs *fakeCS) ChainNotify(context.Context) (<-chan []*api.HeadChange, error
} }
func (fcs *fakeCS) ChainGetBlockMessages(ctx context.Context, blk cid.Cid) (*api.BlockMessages, error) { func (fcs *fakeCS) ChainGetBlockMessages(ctx context.Context, blk cid.Cid) (*api.BlockMessages, error) {
fcs.callNumberLk.Lock()
defer fcs.callNumberLk.Unlock()
fcs.callNumber["ChainGetBlockMessages"] = fcs.callNumber["ChainGetBlockMessages"] + 1
messages, ok := fcs.blkMsgs[blk] messages, ok := fcs.blkMsgs[blk]
if !ok { if !ok {
return &api.BlockMessages{}, nil return &api.BlockMessages{}, nil
@@ -152,8 +179,8 @@ func (fcs *fakeCS) ChainGetBlockMessages(ctx context.Context, blk cid.Cid) (*api
if !ok { if !ok {
return &api.BlockMessages{}, nil return &api.BlockMessages{}, nil
} }
return &api.BlockMessages{BlsMessages: ms.bmsgs, SecpkMessages: ms.smsgs}, nil
return &api.BlockMessages{BlsMessages: ms.bmsgs, SecpkMessages: ms.smsgs}, nil
} }
func (fcs *fakeCS) fakeMsgs(m fakeMsg) cid.Cid { func (fcs *fakeCS) fakeMsgs(m fakeMsg) cid.Cid {
@@ -233,9 +260,10 @@ var _ EventAPI = &fakeCS{}
func TestAt(t *testing.T) { func TestAt(t *testing.T) {
fcs := &fakeCS{ fcs := &fakeCS{
t: t, t: t,
h: 1, h: 1,
tsc: newTSCache(2*build.ForkLengthThreshold, nil), tsc: newTSCache(2*build.ForkLengthThreshold, nil),
callNumber: map[string]int{},
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -298,9 +326,10 @@ func TestAt(t *testing.T) {
func TestAtDoubleTrigger(t *testing.T) { func TestAtDoubleTrigger(t *testing.T) {
fcs := &fakeCS{ fcs := &fakeCS{
t: t, t: t,
h: 1, h: 1,
tsc: newTSCache(2*build.ForkLengthThreshold, nil), tsc: newTSCache(2*build.ForkLengthThreshold, nil),
callNumber: map[string]int{},
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -340,9 +369,10 @@ func TestAtDoubleTrigger(t *testing.T) {
func TestAtNullTrigger(t *testing.T) { func TestAtNullTrigger(t *testing.T) {
fcs := &fakeCS{ fcs := &fakeCS{
t: t, t: t,
h: 1, h: 1,
tsc: newTSCache(2*build.ForkLengthThreshold, nil), tsc: newTSCache(2*build.ForkLengthThreshold, nil),
callNumber: map[string]int{},
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -374,9 +404,10 @@ func TestAtNullTrigger(t *testing.T) {
func TestAtNullConf(t *testing.T) { func TestAtNullConf(t *testing.T) {
fcs := &fakeCS{ fcs := &fakeCS{
t: t, t: t,
h: 1, h: 1,
tsc: newTSCache(2*build.ForkLengthThreshold, nil), tsc: newTSCache(2*build.ForkLengthThreshold, nil),
callNumber: map[string]int{},
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -413,9 +444,10 @@ func TestAtNullConf(t *testing.T) {
func TestAtStart(t *testing.T) { func TestAtStart(t *testing.T) {
fcs := &fakeCS{ fcs := &fakeCS{
t: t, t: t,
h: 1, h: 1,
tsc: newTSCache(2*build.ForkLengthThreshold, nil), tsc: newTSCache(2*build.ForkLengthThreshold, nil),
callNumber: map[string]int{},
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -447,9 +479,10 @@ func TestAtStart(t *testing.T) {
func TestAtStartConfidence(t *testing.T) { func TestAtStartConfidence(t *testing.T) {
fcs := &fakeCS{ fcs := &fakeCS{
t: t, t: t,
h: 1, h: 1,
tsc: newTSCache(2*build.ForkLengthThreshold, nil), tsc: newTSCache(2*build.ForkLengthThreshold, nil),
callNumber: map[string]int{},
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -477,9 +510,10 @@ func TestAtStartConfidence(t *testing.T) {
func TestAtChained(t *testing.T) { func TestAtChained(t *testing.T) {
fcs := &fakeCS{ fcs := &fakeCS{
t: t, t: t,
h: 1, h: 1,
tsc: newTSCache(2*build.ForkLengthThreshold, nil), tsc: newTSCache(2*build.ForkLengthThreshold, nil),
callNumber: map[string]int{},
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -511,9 +545,10 @@ func TestAtChained(t *testing.T) {
func TestAtChainedConfidence(t *testing.T) { func TestAtChainedConfidence(t *testing.T) {
fcs := &fakeCS{ fcs := &fakeCS{
t: t, t: t,
h: 1, h: 1,
tsc: newTSCache(2*build.ForkLengthThreshold, nil), tsc: newTSCache(2*build.ForkLengthThreshold, nil),
callNumber: map[string]int{},
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -545,9 +580,10 @@ func TestAtChainedConfidence(t *testing.T) {
func TestAtChainedConfidenceNull(t *testing.T) { func TestAtChainedConfidenceNull(t *testing.T) {
fcs := &fakeCS{ fcs := &fakeCS{
t: t, t: t,
h: 1, h: 1,
tsc: newTSCache(2*build.ForkLengthThreshold, nil), tsc: newTSCache(2*build.ForkLengthThreshold, nil),
callNumber: map[string]int{},
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -583,9 +619,10 @@ func TestCalled(t *testing.T) {
t: t, t: t,
h: 1, h: 1,
msgs: map[cid.Cid]fakeMsg{}, msgs: map[cid.Cid]fakeMsg{},
blkMsgs: map[cid.Cid]cid.Cid{}, blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil), tsc: newTSCache(2*build.ForkLengthThreshold, nil),
callNumber: map[string]int{},
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -795,9 +832,10 @@ func TestCalledTimeout(t *testing.T) {
t: t, t: t,
h: 1, h: 1,
msgs: map[cid.Cid]fakeMsg{}, msgs: map[cid.Cid]fakeMsg{},
blkMsgs: map[cid.Cid]cid.Cid{}, blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil), tsc: newTSCache(2*build.ForkLengthThreshold, nil),
callNumber: map[string]int{},
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -835,9 +873,10 @@ func TestCalledTimeout(t *testing.T) {
t: t, t: t,
h: 1, h: 1,
msgs: map[cid.Cid]fakeMsg{}, msgs: map[cid.Cid]fakeMsg{},
blkMsgs: map[cid.Cid]cid.Cid{}, blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil), callNumber: map[string]int{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -869,9 +908,10 @@ func TestCalledOrder(t *testing.T) {
t: t, t: t,
h: 1, h: 1,
msgs: map[cid.Cid]fakeMsg{}, msgs: map[cid.Cid]fakeMsg{},
blkMsgs: map[cid.Cid]cid.Cid{}, blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil), tsc: newTSCache(2*build.ForkLengthThreshold, nil),
callNumber: map[string]int{},
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -932,9 +972,10 @@ func TestCalledNull(t *testing.T) {
t: t, t: t,
h: 1, h: 1,
msgs: map[cid.Cid]fakeMsg{}, msgs: map[cid.Cid]fakeMsg{},
blkMsgs: map[cid.Cid]cid.Cid{}, blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil), tsc: newTSCache(2*build.ForkLengthThreshold, nil),
callNumber: map[string]int{},
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -997,9 +1038,10 @@ func TestRemoveTriggersOnMessage(t *testing.T) {
t: t, t: t,
h: 1, h: 1,
msgs: map[cid.Cid]fakeMsg{}, msgs: map[cid.Cid]fakeMsg{},
blkMsgs: map[cid.Cid]cid.Cid{}, blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil), tsc: newTSCache(2*build.ForkLengthThreshold, nil),
callNumber: map[string]int{},
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -1087,9 +1129,10 @@ func TestStateChanged(t *testing.T) {
t: t, t: t,
h: 1, h: 1,
msgs: map[cid.Cid]fakeMsg{}, msgs: map[cid.Cid]fakeMsg{},
blkMsgs: map[cid.Cid]cid.Cid{}, blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil), tsc: newTSCache(2*build.ForkLengthThreshold, nil),
callNumber: map[string]int{},
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -1175,9 +1218,10 @@ func TestStateChangedRevert(t *testing.T) {
t: t, t: t,
h: 1, h: 1,
msgs: map[cid.Cid]fakeMsg{}, msgs: map[cid.Cid]fakeMsg{},
blkMsgs: map[cid.Cid]cid.Cid{}, blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil), tsc: newTSCache(2*build.ForkLengthThreshold, nil),
callNumber: map[string]int{},
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -1253,9 +1297,10 @@ func TestStateChangedTimeout(t *testing.T) {
t: t, t: t,
h: 1, h: 1,
msgs: map[cid.Cid]fakeMsg{}, msgs: map[cid.Cid]fakeMsg{},
blkMsgs: map[cid.Cid]cid.Cid{}, blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil), tsc: newTSCache(2*build.ForkLengthThreshold, nil),
callNumber: map[string]int{},
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -1293,9 +1338,10 @@ func TestStateChangedTimeout(t *testing.T) {
t: t, t: t,
h: 1, h: 1,
msgs: map[cid.Cid]fakeMsg{}, msgs: map[cid.Cid]fakeMsg{},
blkMsgs: map[cid.Cid]cid.Cid{}, blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil), callNumber: map[string]int{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -1329,9 +1375,10 @@ func TestCalledMultiplePerEpoch(t *testing.T) {
t: t, t: t,
h: 1, h: 1,
msgs: map[cid.Cid]fakeMsg{}, msgs: map[cid.Cid]fakeMsg{},
blkMsgs: map[cid.Cid]cid.Cid{}, blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil), callNumber: map[string]int{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
} }
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid))) require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
@@ -1382,3 +1429,24 @@ func TestCalledMultiplePerEpoch(t *testing.T) {
fcs.advance(9, 1, nil) fcs.advance(9, 1, nil)
} }
func TestCachedSameBlock(t *testing.T) {
fcs := &fakeCS{
t: t,
h: 1,
msgs: map[cid.Cid]fakeMsg{},
blkMsgs: map[cid.Cid]cid.Cid{},
callNumber: map[string]int{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
_ = NewEvents(context.Background(), fcs)
fcs.advance(0, 10, map[int]cid.Cid{})
assert.Assert(t, fcs.callNumber["ChainGetBlockMessages"] == 20, "expect call ChainGetBlockMessages %d but got ", 20, fcs.callNumber["ChainGetBlockMessages"])
fcs.advance(5, 10, map[int]cid.Cid{})
assert.Assert(t, fcs.callNumber["ChainGetBlockMessages"] == 30, "expect call ChainGetBlockMessages %d but got ", 30, fcs.callNumber["ChainGetBlockMessages"])
}
+1 -1
View File
@@ -21,7 +21,7 @@ import (
market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market" market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market"
miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner" miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner"
adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt" adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt"
tutils "github.com/filecoin-project/specs-actors/v2/support/testing" tutils "github.com/filecoin-project/specs-actors/v5/support/testing"
bstore "github.com/filecoin-project/lotus/blockstore" bstore "github.com/filecoin-project/lotus/blockstore"
"github.com/filecoin-project/lotus/chain/actors/builtin/market" "github.com/filecoin-project/lotus/chain/actors/builtin/market"
+9 -4
View File
@@ -11,7 +11,6 @@ import (
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/chain/vm"
) )
@@ -259,8 +258,14 @@ func (mp *MessagePool) checkMessages(ctx context.Context, msgs []*types.Message,
Code: api.CheckStatusMessageValidity, Code: api.CheckStatusMessageValidity,
}, },
} }
nv, err := mp.getNtwkVersion(epoch)
if err := m.ValidForBlockInclusion(0, build.NewestNetworkVersion); err != nil { if err != nil {
check.OK = false
check.Err = fmt.Sprintf("error retrieving network version: %s", err.Error())
} else {
check.OK = true
}
if err := m.ValidForBlockInclusion(0, nv); err != nil {
check.OK = false check.OK = false
check.Err = fmt.Sprintf("syntactically invalid message: %s", err.Error()) check.Err = fmt.Sprintf("syntactically invalid message: %s", err.Error())
} else { } else {
@@ -276,7 +281,7 @@ func (mp *MessagePool) checkMessages(ctx context.Context, msgs []*types.Message,
// gas checks // gas checks
// 4. Min Gas // 4. Min Gas
minGas := vm.PricelistByEpoch(epoch).OnChainMessage(m.ChainLength()) minGas := vm.PricelistByVersion(nv).OnChainMessage(m.ChainLength())
check = api.MessageCheckStatus{ check = api.MessageCheckStatus{
Cid: m.Cid(), Cid: m.Cid(),
+46 -20
View File
@@ -14,6 +14,7 @@ import (
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/go-state-types/network"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
lru "github.com/hashicorp/golang-lru" lru "github.com/hashicorp/golang-lru"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
@@ -29,6 +30,7 @@ import (
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/chain/vm"
@@ -147,6 +149,8 @@ type MessagePool struct {
minGasPrice types.BigInt minGasPrice types.BigInt
getNtwkVersion func(abi.ChainEpoch) (network.Version, error)
currentSize int currentSize int
// pruneTrigger is a channel used to trigger a mempool pruning // pruneTrigger is a channel used to trigger a mempool pruning
@@ -362,26 +366,28 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName, j journ
if j == nil { if j == nil {
j = journal.NilJournal() j = journal.NilJournal()
} }
us := stmgr.DefaultUpgradeSchedule()
mp := &MessagePool{ mp := &MessagePool{
ds: ds, ds: ds,
addSema: make(chan struct{}, 1), addSema: make(chan struct{}, 1),
closer: make(chan struct{}), closer: make(chan struct{}),
repubTk: build.Clock.Ticker(RepublishInterval), repubTk: build.Clock.Ticker(RepublishInterval),
repubTrigger: make(chan struct{}, 1), repubTrigger: make(chan struct{}, 1),
localAddrs: make(map[address.Address]struct{}), localAddrs: make(map[address.Address]struct{}),
pending: make(map[address.Address]*msgSet), pending: make(map[address.Address]*msgSet),
keyCache: make(map[address.Address]address.Address), keyCache: make(map[address.Address]address.Address),
minGasPrice: types.NewInt(0), minGasPrice: types.NewInt(0),
pruneTrigger: make(chan struct{}, 1), getNtwkVersion: us.GetNtwkVersion,
pruneCooldown: make(chan struct{}, 1), pruneTrigger: make(chan struct{}, 1),
blsSigCache: cache, pruneCooldown: make(chan struct{}, 1),
sigValCache: verifcache, blsSigCache: cache,
changes: lps.New(50), sigValCache: verifcache,
localMsgs: namespace.Wrap(ds, datastore.NewKey(localMsgsDs)), changes: lps.New(50),
api: api, localMsgs: namespace.Wrap(ds, datastore.NewKey(localMsgsDs)),
netName: netName, api: api,
cfg: cfg, netName: netName,
cfg: cfg,
evtTypes: [...]journal.EventType{ evtTypes: [...]journal.EventType{
evtTypeMpoolAdd: j.RegisterEventType("mpool", "add"), evtTypeMpoolAdd: j.RegisterEventType("mpool", "add"),
evtTypeMpoolRemove: j.RegisterEventType("mpool", "remove"), evtTypeMpoolRemove: j.RegisterEventType("mpool", "remove"),
@@ -426,6 +432,27 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName, j journ
return mp, nil return mp, nil
} }
func (mp *MessagePool) ForEachPendingMessage(f func(cid.Cid) error) error {
mp.lk.Lock()
defer mp.lk.Unlock()
for _, mset := range mp.pending {
for _, m := range mset.msgs {
err := f(m.Cid())
if err != nil {
return err
}
err = f(m.Message.Cid())
if err != nil {
return err
}
}
}
return nil
}
func (mp *MessagePool) resolveToKey(ctx context.Context, addr address.Address) (address.Address, error) { func (mp *MessagePool) resolveToKey(ctx context.Context, addr address.Address) (address.Address, error) {
// check the cache // check the cache
a, f := mp.keyCache[addr] a, f := mp.keyCache[addr]
@@ -589,8 +616,7 @@ func (mp *MessagePool) addLocal(ctx context.Context, m *types.SignedMessage) err
// For non local messages, if the message cannot be included in the next 20 blocks it returns // For non local messages, if the message cannot be included in the next 20 blocks it returns
// a (soft) validation error. // a (soft) validation error.
func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.TipSet, local bool) (bool, error) { func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.TipSet, local bool) (bool, error) {
epoch := curTs.Height() minGas := vm.PricelistByVersion(build.NewestNetworkVersion).OnChainMessage(m.ChainLength())
minGas := vm.PricelistByEpoch(epoch).OnChainMessage(m.ChainLength())
if err := m.VMMessage().ValidForBlockInclusion(minGas.Total(), build.NewestNetworkVersion); err != nil { if err := m.VMMessage().ValidForBlockInclusion(minGas.Total(), build.NewestNetworkVersion); err != nil {
return false, xerrors.Errorf("message will not be included in a block: %w", err) return false, xerrors.Errorf("message will not be included in a block: %w", err)
+2 -1
View File
@@ -105,6 +105,7 @@ func (tma *testMpoolAPI) SubscribeHeadChanges(cb func(rev, app []*types.TipSet)
func (tma *testMpoolAPI) PutMessage(m types.ChainMsg) (cid.Cid, error) { func (tma *testMpoolAPI) PutMessage(m types.ChainMsg) (cid.Cid, error) {
return cid.Undef, nil return cid.Undef, nil
} }
func (tma *testMpoolAPI) IsLite() bool { func (tma *testMpoolAPI) IsLite() bool {
return false return false
} }
@@ -286,7 +287,7 @@ func TestCheckMessageBig(t *testing.T) {
From: from, From: from,
Value: types.NewInt(1), Value: types.NewInt(1),
Nonce: 0, Nonce: 0,
GasLimit: 50000000, GasLimit: 60000000,
GasFeeCap: types.NewInt(100), GasFeeCap: types.NewInt(100),
GasPremium: types.NewInt(1), GasPremium: types.NewInt(1),
Params: make([]byte, 41<<10), // 41KiB payload Params: make([]byte, 41<<10), // 41KiB payload
+1 -1
View File
@@ -749,7 +749,7 @@ func (mp *MessagePool) createMessageChains(actor address.Address, mset map[uint6
} }
curNonce++ curNonce++
minGas := vm.PricelistByEpoch(ts.Height()).OnChainMessage(m.ChainLength()).Total() minGas := vm.PricelistByVersion(build.NewestNetworkVersion).OnChainMessage(m.ChainLength()).Total()
if m.Message.GasLimit < minGas { if m.Message.GasLimit < minGas {
break break
} }
+16
View File
@@ -161,6 +161,10 @@ func DefaultUpgradeSchedule() UpgradeSchedule {
Height: build.UpgradeKumquatHeight, Height: build.UpgradeKumquatHeight,
Network: network.Version6, Network: network.Version6,
Migration: nil, Migration: nil,
}, {
Height: build.UpgradePricelistOopsHeight,
Network: network.Version6AndAHalf,
Migration: nil,
}, { }, {
Height: build.UpgradeCalicoHeight, Height: build.UpgradeCalicoHeight,
Network: network.Version7, Network: network.Version7,
@@ -292,6 +296,18 @@ func (us UpgradeSchedule) Validate() error {
return nil return nil
} }
func (us UpgradeSchedule) GetNtwkVersion(e abi.ChainEpoch) (network.Version, error) {
// Traverse from newest to oldest returning upgrade active during epoch e
for i := len(us) - 1; i >= 0; i-- {
u := us[i]
// u.Height is the last epoch before u.Network becomes the active version
if u.Height < e {
return u.Network, nil
}
}
return network.Version0, xerrors.Errorf("Epoch %d has no defined network version", e)
}
func (sm *StateManager) handleStateForks(ctx context.Context, root cid.Cid, height abi.ChainEpoch, cb ExecMonitor, ts *types.TipSet) (cid.Cid, error) { func (sm *StateManager) handleStateForks(ctx context.Context, root cid.Cid, height abi.ChainEpoch, cb ExecMonitor, ts *types.TipSet) (cid.Cid, error) {
retCid := root retCid := root
var err error var err error
+4 -3
View File
@@ -17,6 +17,7 @@ import (
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/cbor" "github.com/filecoin-project/go-state-types/cbor"
"github.com/filecoin-project/go-state-types/network"
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init" init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init"
@@ -121,7 +122,7 @@ func TestForkHeightTriggers(t *testing.T) {
sm, err := NewStateManagerWithUpgradeSchedule( sm, err := NewStateManagerWithUpgradeSchedule(
cg.ChainStore(), UpgradeSchedule{{ cg.ChainStore(), UpgradeSchedule{{
Network: 1, Network: network.Version1,
Height: testForkHeight, Height: testForkHeight,
Migration: func(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecMonitor, Migration: func(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecMonitor,
root cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) { root cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
@@ -250,7 +251,7 @@ func TestForkRefuseCall(t *testing.T) {
sm, err := NewStateManagerWithUpgradeSchedule( sm, err := NewStateManagerWithUpgradeSchedule(
cg.ChainStore(), UpgradeSchedule{{ cg.ChainStore(), UpgradeSchedule{{
Network: 1, Network: network.Version1,
Expensive: true, Expensive: true,
Height: testForkHeight, Height: testForkHeight,
Migration: func(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecMonitor, Migration: func(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecMonitor,
@@ -365,7 +366,7 @@ func TestForkPreMigration(t *testing.T) {
sm, err := NewStateManagerWithUpgradeSchedule( sm, err := NewStateManagerWithUpgradeSchedule(
cg.ChainStore(), UpgradeSchedule{{ cg.ChainStore(), UpgradeSchedule{{
Network: 1, Network: network.Version1,
Height: testForkHeight, Height: testForkHeight,
Migration: func(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecMonitor, Migration: func(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecMonitor,
root cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) { root cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
+9 -3
View File
@@ -727,6 +727,11 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock, use
} }
// fast checks first // fast checks first
if h.Height <= baseTs.Height() {
return xerrors.Errorf("block height not greater than parent height: %d != %d", h.Height, baseTs.Height())
}
nulls := h.Height - (baseTs.Height() + 1) nulls := h.Height - (baseTs.Height() + 1)
if tgtTs := baseTs.MinTimestamp() + build.BlockDelaySecs*uint64(nulls+1); h.Timestamp != tgtTs { if tgtTs := baseTs.MinTimestamp() + build.BlockDelaySecs*uint64(nulls+1); h.Timestamp != tgtTs {
return xerrors.Errorf("block has wrong timestamp: %d != %d", h.Timestamp, tgtTs) return xerrors.Errorf("block has wrong timestamp: %d != %d", h.Timestamp, tgtTs)
@@ -1054,14 +1059,15 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
return xerrors.Errorf("failed to load base state tree: %w", err) return xerrors.Errorf("failed to load base state tree: %w", err)
} }
pl := vm.PricelistByEpoch(baseTs.Height()) nv := syncer.sm.GetNtwkVersion(ctx, b.Header.Height)
pl := vm.PricelistByVersion(nv)
var sumGasLimit int64 var sumGasLimit int64
checkMsg := func(msg types.ChainMsg) error { checkMsg := func(msg types.ChainMsg) error {
m := msg.VMMessage() m := msg.VMMessage()
// Phase 1: syntactic validation, as defined in the spec // Phase 1: syntactic validation, as defined in the spec
minGas := pl.OnChainMessage(msg.ChainLength()) minGas := pl.OnChainMessage(msg.ChainLength())
if err := m.ValidForBlockInclusion(minGas.Total(), syncer.sm.GetNtwkVersion(ctx, b.Header.Height)); err != nil { if err := m.ValidForBlockInclusion(minGas.Total(), nv); err != nil {
return err return err
} }
@@ -1075,7 +1081,7 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
// Phase 2: (Partial) semantic validation: // Phase 2: (Partial) semantic validation:
// the sender exists and is an account actor, and the nonces make sense // the sender exists and is an account actor, and the nonces make sense
var sender address.Address var sender address.Address
if syncer.sm.GetNtwkVersion(ctx, b.Header.Height) >= network.Version13 { if nv >= network.Version13 {
sender, err = st.LookupID(m.From) sender, err = st.LookupID(m.From)
if err != nil { if err != nil {
return err return err
+60 -39
View File
@@ -230,7 +230,7 @@ func (tu *syncTestUtil) pushTsExpectErr(to int, fts *store.FullTipSet, experr bo
} }
} }
func (tu *syncTestUtil) mineOnBlock(blk *store.FullTipSet, to int, miners []int, wait, fail bool, msgs [][]*types.SignedMessage, nulls abi.ChainEpoch) *store.FullTipSet { func (tu *syncTestUtil) mineOnBlock(blk *store.FullTipSet, to int, miners []int, wait, fail bool, msgs [][]*types.SignedMessage, nulls abi.ChainEpoch, push bool) *store.FullTipSet {
if miners == nil { if miners == nil {
for i := range tu.g.Miners { for i := range tu.g.Miners {
miners = append(miners, i) miners = append(miners, i)
@@ -247,7 +247,7 @@ func (tu *syncTestUtil) mineOnBlock(blk *store.FullTipSet, to int, miners []int,
var nts *store.FullTipSet var nts *store.FullTipSet
var err error var err error
if msgs != nil { if msgs != nil {
nts, err = tu.g.NextTipSetFromMinersWithMessagesAndNulls(blk.TipSet(), maddrs, msgs, 0) nts, err = tu.g.NextTipSetFromMinersWithMessagesAndNulls(blk.TipSet(), maddrs, msgs, nulls)
require.NoError(tu.t, err) require.NoError(tu.t, err)
} else { } else {
mt, err := tu.g.NextTipSetFromMiners(blk.TipSet(), maddrs, nulls) mt, err := tu.g.NextTipSetFromMiners(blk.TipSet(), maddrs, nulls)
@@ -255,17 +255,19 @@ func (tu *syncTestUtil) mineOnBlock(blk *store.FullTipSet, to int, miners []int,
nts = mt.TipSet nts = mt.TipSet
} }
if fail { if push {
tu.pushTsExpectErr(to, nts, true) if fail {
} else { tu.pushTsExpectErr(to, nts, true)
tu.pushFtsAndWait(to, nts, wait) } else {
tu.pushFtsAndWait(to, nts, wait)
}
} }
return nts return nts
} }
func (tu *syncTestUtil) mineNewBlock(src int, miners []int) { func (tu *syncTestUtil) mineNewBlock(src int, miners []int) {
mts := tu.mineOnBlock(tu.g.CurTipset, src, miners, true, false, nil, 0) mts := tu.mineOnBlock(tu.g.CurTipset, src, miners, true, false, nil, 0, true)
tu.g.CurTipset = mts tu.g.CurTipset = mts
} }
@@ -510,7 +512,7 @@ func TestSyncBadTimestamp(t *testing.T) {
fmt.Println("BASE: ", base.Cids()) fmt.Println("BASE: ", base.Cids())
tu.printHeads() tu.printHeads()
a1 := tu.mineOnBlock(base, 0, nil, false, true, nil, 0) a1 := tu.mineOnBlock(base, 0, nil, false, true, nil, 0, true)
tu.g.Timestamper = nil tu.g.Timestamper = nil
require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet())) require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet()))
@@ -519,7 +521,7 @@ func TestSyncBadTimestamp(t *testing.T) {
fmt.Println("After mine bad block!") fmt.Println("After mine bad block!")
tu.printHeads() tu.printHeads()
a2 := tu.mineOnBlock(base, 0, nil, true, false, nil, 0) a2 := tu.mineOnBlock(base, 0, nil, true, false, nil, 0, true)
tu.waitUntilSync(0, client) tu.waitUntilSync(0, client)
@@ -563,7 +565,7 @@ func TestSyncBadWinningPoSt(t *testing.T) {
tu.g.SetWinningPoStProver(tu.g.Miners[1], &badWpp{}) tu.g.SetWinningPoStProver(tu.g.Miners[1], &badWpp{})
// now ensure that new blocks are not accepted // now ensure that new blocks are not accepted
tu.mineOnBlock(base, client, nil, false, true, nil, 0) tu.mineOnBlock(base, client, nil, false, true, nil, 0, true)
} }
func (tu *syncTestUtil) loadChainToNode(to int) { func (tu *syncTestUtil) loadChainToNode(to int) {
@@ -613,16 +615,16 @@ func TestSyncFork(t *testing.T) {
fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height()) fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height())
// The two nodes fork at this point into 'a' and 'b' // The two nodes fork at this point into 'a' and 'b'
a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil, 0) a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil, 0, true)
a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil, 0) a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil, 0, true)
a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil, 0) a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil, 0, true)
require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet())) require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet()))
// chain B will now be heaviest // chain B will now be heaviest
b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil, 0) b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil, 0, true)
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0) b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0, true)
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0) b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0, true)
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0) b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0, true)
fmt.Println("A: ", a.Cids(), a.TipSet().Height()) fmt.Println("A: ", a.Cids(), a.TipSet().Height())
fmt.Println("B: ", b.Cids(), b.TipSet().Height()) fmt.Println("B: ", b.Cids(), b.TipSet().Height())
@@ -686,13 +688,13 @@ func TestDuplicateNonce(t *testing.T) {
msgs[k] = []*types.SignedMessage{makeMsg(tu.g.Miners[k])} msgs[k] = []*types.SignedMessage{makeMsg(tu.g.Miners[k])}
} }
ts1 := tu.mineOnBlock(base, 0, []int{0, 1}, true, false, msgs, 0) ts1 := tu.mineOnBlock(base, 0, []int{0, 1}, true, false, msgs, 0, true)
tu.waitUntilSyncTarget(0, ts1.TipSet()) tu.waitUntilSyncTarget(0, ts1.TipSet())
// mine another tipset // mine another tipset
ts2 := tu.mineOnBlock(ts1, 0, []int{0, 1}, true, false, make([][]*types.SignedMessage, 2), 0) ts2 := tu.mineOnBlock(ts1, 0, []int{0, 1}, true, false, make([][]*types.SignedMessage, 2), 0, true)
tu.waitUntilSyncTarget(0, ts2.TipSet()) tu.waitUntilSyncTarget(0, ts2.TipSet())
var includedMsg cid.Cid var includedMsg cid.Cid
@@ -778,7 +780,7 @@ func TestBadNonce(t *testing.T) {
msgs := make([][]*types.SignedMessage, 1) msgs := make([][]*types.SignedMessage, 1)
msgs[0] = []*types.SignedMessage{makeBadMsg()} msgs[0] = []*types.SignedMessage{makeBadMsg()}
tu.mineOnBlock(base, 0, []int{0}, true, true, msgs, 0) tu.mineOnBlock(base, 0, []int{0}, true, true, msgs, 0, true)
} }
// This test introduces a block that has 2 messages, with the same sender, and same nonce. // This test introduces a block that has 2 messages, with the same sender, and same nonce.
@@ -832,7 +834,7 @@ func TestMismatchedNoncesRobustID(t *testing.T) {
msgs := make([][]*types.SignedMessage, 1) msgs := make([][]*types.SignedMessage, 1)
msgs[0] = []*types.SignedMessage{makeMsg(false), makeMsg(true)} msgs[0] = []*types.SignedMessage{makeMsg(false), makeMsg(true)}
tu.mineOnBlock(base, 0, []int{0}, true, true, msgs, 0) tu.mineOnBlock(base, 0, []int{0}, true, true, msgs, 0, true)
} }
// This test introduces a block that has 2 messages, with the same sender, and nonces N and N+1 (so both can be included in a block) // This test introduces a block that has 2 messages, with the same sender, and nonces N and N+1 (so both can be included in a block)
@@ -886,7 +888,7 @@ func TestMatchedNoncesRobustID(t *testing.T) {
msgs := make([][]*types.SignedMessage, 1) msgs := make([][]*types.SignedMessage, 1)
msgs[0] = []*types.SignedMessage{makeMsg(ba.Nonce, false), makeMsg(ba.Nonce+1, true)} msgs[0] = []*types.SignedMessage{makeMsg(ba.Nonce, false), makeMsg(ba.Nonce+1, true)}
tu.mineOnBlock(base, 0, []int{0}, true, false, msgs, 0) tu.mineOnBlock(base, 0, []int{0}, true, false, msgs, 0, true)
} }
func BenchmarkSyncBasic(b *testing.B) { func BenchmarkSyncBasic(b *testing.B) {
@@ -951,19 +953,19 @@ func TestSyncCheckpointHead(t *testing.T) {
fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height()) fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height())
// The two nodes fork at this point into 'a' and 'b' // The two nodes fork at this point into 'a' and 'b'
a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil, 0) a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil, 0, true)
a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil, 0) a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil, 0, true)
a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil, 0) a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil, 0, true)
tu.waitUntilSyncTarget(p1, a.TipSet()) tu.waitUntilSyncTarget(p1, a.TipSet())
tu.checkpointTs(p1, a.TipSet().Key()) tu.checkpointTs(p1, a.TipSet().Key())
require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet())) require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet()))
// chain B will now be heaviest // chain B will now be heaviest
b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil, 0) b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil, 0, true)
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0) b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0, true)
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0) b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0, true)
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0) b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0, true)
fmt.Println("A: ", a.Cids(), a.TipSet().Height()) fmt.Println("A: ", a.Cids(), a.TipSet().Height())
fmt.Println("B: ", b.Cids(), b.TipSet().Height()) fmt.Println("B: ", b.Cids(), b.TipSet().Height())
@@ -998,19 +1000,19 @@ func TestSyncCheckpointEarlierThanHead(t *testing.T) {
fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height()) fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height())
// The two nodes fork at this point into 'a' and 'b' // The two nodes fork at this point into 'a' and 'b'
a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil, 0) a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil, 0, true)
a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil, 0) a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil, 0, true)
a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil, 0) a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil, 0, true)
tu.waitUntilSyncTarget(p1, a.TipSet()) tu.waitUntilSyncTarget(p1, a.TipSet())
tu.checkpointTs(p1, a1.TipSet().Key()) tu.checkpointTs(p1, a1.TipSet().Key())
require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet())) require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet()))
// chain B will now be heaviest // chain B will now be heaviest
b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil, 0) b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil, 0, true)
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0) b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0, true)
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0) b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0, true)
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0) b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0, true)
fmt.Println("A: ", a.Cids(), a.TipSet().Height()) fmt.Println("A: ", a.Cids(), a.TipSet().Height())
fmt.Println("B: ", b.Cids(), b.TipSet().Height()) fmt.Println("B: ", b.Cids(), b.TipSet().Height())
@@ -1048,7 +1050,7 @@ func TestDrandNull(t *testing.T) {
pers := crypto.DomainSeparationTag_WinningPoStChallengeSeed pers := crypto.DomainSeparationTag_WinningPoStChallengeSeed
beforeNull := tu.g.CurTipset beforeNull := tu.g.CurTipset
afterNull := tu.mineOnBlock(beforeNull, p0, nil, false, false, nil, 2) afterNull := tu.mineOnBlock(beforeNull, p0, nil, false, false, nil, 2, true)
nullHeight := beforeNull.TipSet().Height() + 1 nullHeight := beforeNull.TipSet().Height() + 1
if afterNull.TipSet().Height() == nullHeight { if afterNull.TipSet().Height() == nullHeight {
t.Fatal("didn't inject nulls as expected") t.Fatal("didn't inject nulls as expected")
@@ -1065,14 +1067,14 @@ func TestDrandNull(t *testing.T) {
require.Equal(t, []byte(rand), expectedRand) require.Equal(t, []byte(rand), expectedRand)
// zoom zoom to past the v5 upgrade by injecting many many nulls // zoom zoom to past the v5 upgrade by injecting many many nulls
postUpgrade := tu.mineOnBlock(afterNull, p0, nil, false, false, nil, v5h) postUpgrade := tu.mineOnBlock(afterNull, p0, nil, false, false, nil, v5h, true)
nv, err := tu.nds[p0].StateNetworkVersion(tu.ctx, postUpgrade.TipSet().Key()) nv, err := tu.nds[p0].StateNetworkVersion(tu.ctx, postUpgrade.TipSet().Key())
require.NoError(t, err) require.NoError(t, err)
if nv != network.Version13 { if nv != network.Version13 {
t.Fatal("expect to be v13 by now") t.Fatal("expect to be v13 by now")
} }
afterNull = tu.mineOnBlock(postUpgrade, p0, nil, false, false, nil, 2) afterNull = tu.mineOnBlock(postUpgrade, p0, nil, false, false, nil, 2, true)
nullHeight = postUpgrade.TipSet().Height() + 1 nullHeight = postUpgrade.TipSet().Height() + 1
if afterNull.TipSet().Height() == nullHeight { if afterNull.TipSet().Height() == nullHeight {
t.Fatal("didn't inject nulls as expected") t.Fatal("didn't inject nulls as expected")
@@ -1104,3 +1106,22 @@ func TestDrandNull(t *testing.T) {
build.UpgradeHyperdriveHeight = ov5h build.UpgradeHyperdriveHeight = ov5h
} }
func TestInvalidHeight(t *testing.T) {
H := 50
tu := prepSyncTest(t, H)
client := tu.addClientNode()
require.NoError(t, tu.mn.LinkAll())
tu.connect(client, 0)
tu.waitUntilSync(0, client)
base := tu.g.CurTipset
for i := 0; i < 5; i++ {
base = tu.mineOnBlock(base, 0, nil, false, false, nil, 0, false)
}
tu.mineOnBlock(base, 0, nil, false, true, nil, -1, true)
}
+13 -16
View File
@@ -3,12 +3,11 @@ package vm
import ( import (
"fmt" "fmt"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
addr "github.com/filecoin-project/go-address" addr "github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/go-state-types/network"
vmr5 "github.com/filecoin-project/specs-actors/v5/actors/runtime" vmr5 "github.com/filecoin-project/specs-actors/v5/actors/runtime"
proof5 "github.com/filecoin-project/specs-actors/v5/actors/runtime/proof" proof5 "github.com/filecoin-project/specs-actors/v5/actors/runtime/proof"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
@@ -80,8 +79,8 @@ type Pricelist interface {
OnVerifyConsensusFault() GasCharge OnVerifyConsensusFault() GasCharge
} }
var prices = map[abi.ChainEpoch]Pricelist{ var prices = map[network.Version]Pricelist{
abi.ChainEpoch(0): &pricelistV0{ network.Version0: &pricelistV0{
computeGasMulti: 1, computeGasMulti: 1,
storageGasMulti: 1000, storageGasMulti: 1000,
@@ -130,7 +129,7 @@ var prices = map[abi.ChainEpoch]Pricelist{
verifyPostDiscount: true, verifyPostDiscount: true,
verifyConsensusFault: 495422, verifyConsensusFault: 495422,
}, },
abi.ChainEpoch(build.UpgradeCalicoHeight): &pricelistV0{ network.Version6AndAHalf: &pricelistV0{
computeGasMulti: 1, computeGasMulti: 1,
storageGasMulti: 1300, storageGasMulti: 1300,
@@ -208,21 +207,19 @@ var prices = map[abi.ChainEpoch]Pricelist{
}, },
} }
// PricelistByEpoch finds the latest prices for the given epoch // PricelistByVersion finds the latest prices for the given network version
func PricelistByEpoch(epoch abi.ChainEpoch) Pricelist { func PricelistByVersion(version network.Version) Pricelist {
// since we are storing the prices as map or epoch to price bestVersion := network.Version0
// we need to get the price with the highest epoch that is lower or equal to the `epoch` arg bestPrice := prices[bestVersion]
bestEpoch := abi.ChainEpoch(0) for nv, pl := range prices {
bestPrice := prices[bestEpoch] // if `nv > bestVersion` and `nv <= version`
for e, pl := range prices { if nv > bestVersion && nv <= version {
// if `e` happened after `bestEpoch` and `e` is earlier or equal to the target `epoch` bestVersion = nv
if e > bestEpoch && e <= epoch {
bestEpoch = e
bestPrice = pl bestPrice = pl
} }
} }
if bestPrice == nil { if bestPrice == nil {
panic(fmt.Sprintf("bad setup: no gas prices available for epoch %d", epoch)) panic(fmt.Sprintf("bad setup: no gas prices available for version %d", version))
} }
return bestPrice return bestPrice
} }
+1 -1
View File
@@ -41,7 +41,7 @@ var EmptyObjectCid cid.Cid
// TryCreateAccountActor creates account actors from only BLS/SECP256K1 addresses. // TryCreateAccountActor creates account actors from only BLS/SECP256K1 addresses.
func TryCreateAccountActor(rt *Runtime, addr address.Address) (*types.Actor, address.Address, aerrors.ActorError) { func TryCreateAccountActor(rt *Runtime, addr address.Address) (*types.Actor, address.Address, aerrors.ActorError) {
if err := rt.chargeGasSafe(PricelistByEpoch(rt.height).OnCreateActor()); err != nil { if err := rt.chargeGasSafe(PricelistByVersion(rt.NetworkVersion()).OnCreateActor()); err != nil {
return nil, address.Undef, err return nil, address.Undef, err
} }
+2 -2
View File
@@ -135,7 +135,7 @@ func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, parent *Runti
gasAvailable: msg.GasLimit, gasAvailable: msg.GasLimit,
depth: 0, depth: 0,
numActorsCreated: 0, numActorsCreated: 0,
pricelist: PricelistByEpoch(vm.blockHeight), pricelist: PricelistByVersion(vm.ntwkVersion(ctx, vm.blockHeight)),
allowInternal: true, allowInternal: true,
callerValidated: false, callerValidated: false,
executionTrace: types.ExecutionTrace{Msg: msg}, executionTrace: types.ExecutionTrace{Msg: msg},
@@ -424,7 +424,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
return nil, err return nil, err
} }
pl := PricelistByEpoch(vm.blockHeight) pl := PricelistByVersion(vm.ntwkVersion(ctx, vm.blockHeight))
msgGas := pl.OnChainMessage(cmsg.ChainLength()) msgGas := pl.OnChainMessage(cmsg.ChainLength())
msgGasCost := msgGas.Total() msgGasCost := msgGas.Total()
+7
View File
@@ -446,6 +446,9 @@ var StateExecTraceCmd = &cli.Command{
if err != nil { if err != nil {
return err return err
} }
if lookup == nil {
return fmt.Errorf("failed to find message: %s", mcid)
}
ts, err := capi.ChainGetTipSet(ctx, lookup.TipSet) ts, err := capi.ChainGetTipSet(ctx, lookup.TipSet)
if err != nil { if err != nil {
@@ -1491,6 +1494,10 @@ var StateSearchMsgCmd = &cli.Command{
return err return err
} }
if mw == nil {
return fmt.Errorf("failed to find message: %s", msg)
}
m, err := api.ChainGetMessage(ctx, msg) m, err := api.ChainGetMessage(ctx, msg)
if err != nil { if err != nil {
return err return err
+1 -1
View File
@@ -149,7 +149,7 @@ func GetRawAPI(ctx *cli.Context, t repo.RepoType, version string) (string, http.
return addr, ainfo.AuthHeader(), nil return addr, ainfo.AuthHeader(), nil
} }
func GetAPI(ctx *cli.Context) (api.Common, jsonrpc.ClientCloser, error) { func GetAPI(ctx *cli.Context) (api.CommonNet, jsonrpc.ClientCloser, error) {
ti, ok := ctx.App.Metadata["repoType"] ti, ok := ctx.App.Metadata["repoType"]
if !ok { if !ok {
log.Errorf("unknown repo type, are you sure you want to use GetAPI?") log.Errorf("unknown repo type, are you sure you want to use GetAPI?")
+1
View File
@@ -60,6 +60,7 @@ func main() {
actorCmd, actorCmd,
minerTypesCmd, minerTypesCmd,
minerMultisigsCmd, minerMultisigsCmd,
splitstoreCmd,
} }
app := &cli.App{ app := &cli.App{
+310
View File
@@ -0,0 +1,310 @@
package main
import (
"bufio"
"context"
"fmt"
"io"
"os"
"path/filepath"
"runtime"
"github.com/dgraph-io/badger/v2"
"github.com/urfave/cli/v2"
"golang.org/x/sync/errgroup"
"golang.org/x/xerrors"
"go.uber.org/zap"
"github.com/ipfs/go-datastore"
"github.com/ipfs/go-datastore/query"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/node/config"
"github.com/filecoin-project/lotus/node/repo"
)
var splitstoreCmd = &cli.Command{
Name: "splitstore",
Description: "splitstore utilities",
Subcommands: []*cli.Command{
splitstoreRollbackCmd,
splitstoreCheckCmd,
splitstoreInfoCmd,
},
}
var splitstoreRollbackCmd = &cli.Command{
Name: "rollback",
Description: "rollbacks a splitstore installation",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "repo",
Value: "~/.lotus",
},
&cli.BoolFlag{
Name: "gc-coldstore",
Usage: "compact and garbage collect the coldstore after copying the hotstore",
},
&cli.BoolFlag{
Name: "rewrite-config",
Usage: "rewrite the lotus configuration to disable splitstore",
},
},
Action: func(cctx *cli.Context) error {
r, err := repo.NewFS(cctx.String("repo"))
if err != nil {
return xerrors.Errorf("error opening fs repo: %w", err)
}
exists, err := r.Exists()
if err != nil {
return err
}
if !exists {
return xerrors.Errorf("lotus repo doesn't exist")
}
lr, err := r.Lock(repo.FullNode)
if err != nil {
return xerrors.Errorf("error locking repo: %w", err)
}
defer lr.Close() //nolint:errcheck
cfg, err := lr.Config()
if err != nil {
return xerrors.Errorf("error getting config: %w", err)
}
fncfg, ok := cfg.(*config.FullNode)
if !ok {
return xerrors.Errorf("wrong config type: %T", cfg)
}
if !fncfg.Chainstore.EnableSplitstore {
return xerrors.Errorf("splitstore is not enabled")
}
fmt.Println("copying hotstore to coldstore...")
err = copyHotstoreToColdstore(lr, cctx.Bool("gc-coldstore"))
if err != nil {
return xerrors.Errorf("error copying hotstore to coldstore: %w", err)
}
fmt.Println("deleting splitstore directory...")
err = deleteSplitstoreDir(lr)
if err != nil {
return xerrors.Errorf("error deleting splitstore directory: %w", err)
}
fmt.Println("deleting splitstore keys from metadata datastore...")
err = deleteSplitstoreKeys(lr)
if err != nil {
return xerrors.Errorf("error deleting splitstore keys: %w", err)
}
if cctx.Bool("rewrite-config") {
fmt.Println("disabling splitstore in config...")
err = lr.SetConfig(func(cfg interface{}) {
cfg.(*config.FullNode).Chainstore.EnableSplitstore = false
})
if err != nil {
return xerrors.Errorf("error disabling splitstore in config: %w", err)
}
}
fmt.Println("splitstore has been rolled back.")
return nil
},
}
func copyHotstoreToColdstore(lr repo.LockedRepo, gcColdstore bool) error {
repoPath := lr.Path()
dataPath := filepath.Join(repoPath, "datastore")
coldPath := filepath.Join(dataPath, "chain")
hotPath := filepath.Join(dataPath, "splitstore", "hot.badger")
blog := &badgerLogger{
SugaredLogger: log.Desugar().WithOptions(zap.AddCallerSkip(1)).Sugar(),
skip2: log.Desugar().WithOptions(zap.AddCallerSkip(2)).Sugar(),
}
coldOpts, err := repo.BadgerBlockstoreOptions(repo.UniversalBlockstore, coldPath, false)
if err != nil {
return xerrors.Errorf("error getting coldstore badger options: %w", err)
}
coldOpts.SyncWrites = false
coldOpts.Logger = blog
hotOpts, err := repo.BadgerBlockstoreOptions(repo.HotBlockstore, hotPath, true)
if err != nil {
return xerrors.Errorf("error getting hotstore badger options: %w", err)
}
hotOpts.Logger = blog
cold, err := badger.Open(coldOpts.Options)
if err != nil {
return xerrors.Errorf("error opening coldstore: %w", err)
}
defer cold.Close() //nolint
hot, err := badger.Open(hotOpts.Options)
if err != nil {
return xerrors.Errorf("error opening hotstore: %w", err)
}
defer hot.Close() //nolint
rd, wr := io.Pipe()
g := new(errgroup.Group)
g.Go(func() error {
bwr := bufio.NewWriterSize(wr, 64<<20)
_, err := hot.Backup(bwr, 0)
if err != nil {
_ = wr.CloseWithError(err)
return err
}
err = bwr.Flush()
if err != nil {
_ = wr.CloseWithError(err)
return err
}
return wr.Close()
})
g.Go(func() error {
err := cold.Load(rd, 1024)
if err != nil {
return err
}
return cold.Sync()
})
err = g.Wait()
if err != nil {
return err
}
// compact + gc the coldstore if so requested
if gcColdstore {
fmt.Println("compacting coldstore...")
nworkers := runtime.NumCPU()
if nworkers < 2 {
nworkers = 2
}
err = cold.Flatten(nworkers)
if err != nil {
return xerrors.Errorf("error compacting coldstore: %w", err)
}
fmt.Println("garbage collecting coldstore...")
for err == nil {
err = cold.RunValueLogGC(0.0625)
}
if err != badger.ErrNoRewrite {
return xerrors.Errorf("error garbage collecting coldstore: %w", err)
}
}
return nil
}
func deleteSplitstoreDir(lr repo.LockedRepo) error {
path, err := lr.SplitstorePath()
if err != nil {
return xerrors.Errorf("error getting splitstore path: %w", err)
}
return os.RemoveAll(path)
}
func deleteSplitstoreKeys(lr repo.LockedRepo) error {
ds, err := lr.Datastore(context.TODO(), "/metadata")
if err != nil {
return xerrors.Errorf("error opening datastore: %w", err)
}
if closer, ok := ds.(io.Closer); ok {
defer closer.Close() //nolint
}
var keys []datastore.Key
res, err := ds.Query(query.Query{Prefix: "/splitstore"})
if err != nil {
return xerrors.Errorf("error querying datastore for splitstore keys: %w", err)
}
for r := range res.Next() {
if r.Error != nil {
return xerrors.Errorf("datastore query error: %w", r.Error)
}
keys = append(keys, datastore.NewKey(r.Key))
}
for _, k := range keys {
fmt.Printf("deleting %s from datastore...\n", k)
err = ds.Delete(k)
if err != nil {
return xerrors.Errorf("error deleting key %s from datastore: %w", k, err)
}
}
return nil
}
// badger logging through go-log
type badgerLogger struct {
*zap.SugaredLogger
skip2 *zap.SugaredLogger
}
func (b *badgerLogger) Warningf(format string, args ...interface{}) {}
func (b *badgerLogger) Infof(format string, args ...interface{}) {}
func (b *badgerLogger) Debugf(format string, args ...interface{}) {}
var splitstoreCheckCmd = &cli.Command{
Name: "check",
Description: "runs a healthcheck on a splitstore installation",
Action: func(cctx *cli.Context) error {
api, closer, err := lcli.GetFullNodeAPIV1(cctx)
if err != nil {
return err
}
defer closer()
ctx := lcli.ReqContext(cctx)
return api.ChainCheckBlockstore(ctx)
},
}
var splitstoreInfoCmd = &cli.Command{
Name: "info",
Description: "prints some basic splitstore information",
Action: func(cctx *cli.Context) error {
api, closer, err := lcli.GetFullNodeAPIV1(cctx)
if err != nil {
return err
}
defer closer()
ctx := lcli.ReqContext(cctx)
info, err := api.ChainBlockstoreInfo(ctx)
if err != nil {
return err
}
for k, v := range info {
fmt.Print(k)
fmt.Print(": ")
fmt.Println(v)
}
return nil
},
}
+154
View File
@@ -5,6 +5,7 @@ import (
"os" "os"
"strings" "strings"
rlepluslazy "github.com/filecoin-project/go-bitfield/rle"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
"github.com/fatih/color" "github.com/fatih/color"
@@ -14,6 +15,7 @@ import (
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-bitfield"
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/big"
@@ -41,6 +43,7 @@ var actorCmd = &cli.Command{
actorControl, actorControl,
actorProposeChangeWorker, actorProposeChangeWorker,
actorConfirmChangeWorker, actorConfirmChangeWorker,
actorCompactAllocatedCmd,
}, },
} }
@@ -987,3 +990,154 @@ var actorConfirmChangeWorker = &cli.Command{
return nil return nil
}, },
} }
var actorCompactAllocatedCmd = &cli.Command{
Name: "compact-allocated",
Usage: "compact allocated sectors bitfield",
Flags: []cli.Flag{
&cli.Uint64Flag{
Name: "mask-last-offset",
Usage: "Mask sector IDs from 0 to 'higest_allocated - offset'",
},
&cli.Uint64Flag{
Name: "mask-upto-n",
Usage: "Mask sector IDs from 0 to 'n'",
},
&cli.BoolFlag{
Name: "really-do-it",
Usage: "Actually send transaction performing the action",
Value: false,
},
},
Action: func(cctx *cli.Context) error {
if !cctx.Bool("really-do-it") {
fmt.Println("Pass --really-do-it to actually execute this action")
return nil
}
if !cctx.Args().Present() {
return fmt.Errorf("must pass address of new owner address")
}
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
if err != nil {
return err
}
defer closer()
api, acloser, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer acloser()
ctx := lcli.ReqContext(cctx)
maddr, err := nodeApi.ActorAddress(ctx)
if err != nil {
return err
}
mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK)
if err != nil {
return err
}
store := adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewAPIBlockstore(api)))
mst, err := miner.Load(store, mact)
if err != nil {
return err
}
allocs, err := mst.GetAllocatedSectors()
if err != nil {
return err
}
var maskBf bitfield.BitField
{
exclusiveFlags := []string{"mask-last-offset", "mask-upto-n"}
hasFlag := false
for _, f := range exclusiveFlags {
if hasFlag && cctx.IsSet(f) {
return xerrors.Errorf("more than one 'mask` flag set")
}
hasFlag = hasFlag || cctx.IsSet(f)
}
}
switch {
case cctx.IsSet("mask-last-offset"):
last, err := allocs.Last()
if err != nil {
return err
}
m := cctx.Uint64("mask-last-offset")
if last <= m+1 {
return xerrors.Errorf("highest allocated sector lower than mask offset %d: %d", m+1, last)
}
// securty to not brick a miner
if last > 1<<60 {
return xerrors.Errorf("very high last sector number, refusing to mask: %d", last)
}
maskBf, err = bitfield.NewFromIter(&rlepluslazy.RunSliceIterator{
Runs: []rlepluslazy.Run{{Val: true, Len: last - m}}})
if err != nil {
return xerrors.Errorf("forming bitfield: %w", err)
}
case cctx.IsSet("mask-upto-n"):
n := cctx.Uint64("mask-upto-n")
maskBf, err = bitfield.NewFromIter(&rlepluslazy.RunSliceIterator{
Runs: []rlepluslazy.Run{{Val: true, Len: n}}})
if err != nil {
return xerrors.Errorf("forming bitfield: %w", err)
}
default:
return xerrors.Errorf("no 'mask' flags set")
}
mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
if err != nil {
return err
}
params := &miner2.CompactSectorNumbersParams{
MaskSectorNumbers: maskBf,
}
sp, err := actors.SerializeParams(params)
if err != nil {
return xerrors.Errorf("serializing params: %w", err)
}
smsg, err := api.MpoolPushMessage(ctx, &types.Message{
From: mi.Worker,
To: maddr,
Method: miner.Methods.CompactSectorNumbers,
Value: big.Zero(),
Params: sp,
}, nil)
if err != nil {
return xerrors.Errorf("mpool push: %w", err)
}
fmt.Println("CompactSectorNumbers Message CID:", smsg.Cid())
// wait for it to get mined into a block
wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence)
if err != nil {
return err
}
// check it executed successfully
if wait.Receipt.ExitCode != 0 {
fmt.Println("Propose owner change failed!")
return err
}
return nil
},
}
+75 -3
View File
@@ -4,19 +4,91 @@ import (
"fmt" "fmt"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/node/config" "github.com/filecoin-project/lotus/node/config"
"github.com/filecoin-project/lotus/node/repo"
) )
var configCmd = &cli.Command{ var configCmd = &cli.Command{
Name: "config", Name: "config",
Usage: "Output default configuration", Usage: "Manage node config",
Subcommands: []*cli.Command{
configDefaultCmd,
configUpdateCmd,
},
}
var configDefaultCmd = &cli.Command{
Name: "default",
Usage: "Print default node config",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "no-comment",
Usage: "don't comment default values",
},
},
Action: func(cctx *cli.Context) error { Action: func(cctx *cli.Context) error {
comm, err := config.ConfigComment(config.DefaultStorageMiner()) c := config.DefaultStorageMiner()
cb, err := config.ConfigUpdate(c, nil, !cctx.Bool("no-comment"))
if err != nil { if err != nil {
return err return err
} }
fmt.Println(string(comm))
fmt.Println(string(cb))
return nil
},
}
var configUpdateCmd = &cli.Command{
Name: "updated",
Usage: "Print updated node config",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "no-comment",
Usage: "don't comment default values",
},
},
Action: func(cctx *cli.Context) error {
r, err := repo.NewFS(cctx.String(FlagMinerRepo))
if err != nil {
return err
}
ok, err := r.Exists()
if err != nil {
return err
}
if !ok {
return xerrors.Errorf("repo not initialized")
}
lr, err := r.LockRO(repo.StorageMiner)
if err != nil {
return xerrors.Errorf("locking repo: %w", err)
}
cfgNode, err := lr.Config()
if err != nil {
_ = lr.Close()
return xerrors.Errorf("getting node config: %w", err)
}
if err := lr.Close(); err != nil {
return err
}
cfgDef := config.DefaultStorageMiner()
updated, err := config.ConfigUpdate(cfgNode, cfgDef, !cctx.Bool("no-comment"))
if err != nil {
return err
}
fmt.Print(string(updated))
return nil return nil
}, },
} }
+94
View File
@@ -0,0 +1,94 @@
package main
import (
"fmt"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/node/config"
"github.com/filecoin-project/lotus/node/repo"
)
var configCmd = &cli.Command{
Name: "config",
Usage: "Manage node config",
Subcommands: []*cli.Command{
configDefaultCmd,
configUpdateCmd,
},
}
var configDefaultCmd = &cli.Command{
Name: "default",
Usage: "Print default node config",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "no-comment",
Usage: "don't comment default values",
},
},
Action: func(cctx *cli.Context) error {
c := config.DefaultFullNode()
cb, err := config.ConfigUpdate(c, nil, !cctx.Bool("no-comment"))
if err != nil {
return err
}
fmt.Println(string(cb))
return nil
},
}
var configUpdateCmd = &cli.Command{
Name: "updated",
Usage: "Print updated node config",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "no-comment",
Usage: "don't comment default values",
},
},
Action: func(cctx *cli.Context) error {
r, err := repo.NewFS(cctx.String("repo"))
if err != nil {
return err
}
ok, err := r.Exists()
if err != nil {
return err
}
if !ok {
return xerrors.Errorf("repo not initialized")
}
lr, err := r.LockRO(repo.FullNode)
if err != nil {
return xerrors.Errorf("locking repo: %w", err)
}
cfgNode, err := lr.Config()
if err != nil {
_ = lr.Close()
return xerrors.Errorf("getting node config: %w", err)
}
if err := lr.Close(); err != nil {
return err
}
cfgDef := config.DefaultFullNode()
updated, err := config.ConfigUpdate(cfgNode, cfgDef, !cctx.Bool("no-comment"))
if err != nil {
return err
}
fmt.Print(string(updated))
return nil
},
}
+1
View File
@@ -29,6 +29,7 @@ func main() {
local := []*cli.Command{ local := []*cli.Command{
DaemonCmd, DaemonCmd,
backupCmd, backupCmd,
configCmd,
} }
if AdvanceBlockCmd != nil { if AdvanceBlockCmd != nil {
local = append(local, AdvanceBlockCmd) local = append(local, AdvanceBlockCmd)
+3
View File
@@ -337,6 +337,9 @@ func resolveFromChain(ctx context.Context, api v0api.FullNode, mcid cid.Cid, blo
if err != nil { if err != nil {
return nil, nil, nil, fmt.Errorf("failed to locate message: %w", err) return nil, nil, nil, fmt.Errorf("failed to locate message: %w", err)
} }
if msgInfo == nil {
return nil, nil, nil, fmt.Errorf("failed to locate message: not found")
}
log.Printf("located message at tipset %s (height: %d) with exit code: %s", msgInfo.TipSet, msgInfo.Height, msgInfo.Receipt.ExitCode) log.Printf("located message at tipset %s (height: %d) with exit code: %s", msgInfo.TipSet, msgInfo.Height, msgInfo.Receipt.ExitCode)
+145
View File
@@ -0,0 +1,145 @@
# By default, this docker-compose file will start a lotus fullnode
#
# Some directives have been left commented out so they serve as an
# example for more advanced use.
#
# To provide a custom configuration file, or automatically import
# a wallet, uncomment the "configs" or "secrets" sections.
#
# start on a single node:
#
# docker-compose up
#
# start on docker swarm:
#
# docker swarm init (if you haven't already)
# docker stack deploy -c docker-compose.yaml mylotuscluster
#
# for more information, please visit docs.filecoin.io
version: "3.8"
volumes:
parameters:
lotus-repo:
lotus-miner-repo:
lotus-worker-repo:
configs:
lotus-config-toml:
file: /path/to/lotus/config.toml
lotus-miner-config-toml:
file: /path/to/lotus-miner/config.toml
secrets:
lotus-wallet:
file: /path/to/exported/lotus/wallet
services:
lotus:
build:
context: .
target: lotus
dockerfile: Dockerfile.lotus
image: filecoin/lotus
volumes:
- parameters:/var/tmp/filecoin-proof-parameters
- lotus-repo:/var/lib/lotus
ports:
- 1234:1234
environment:
- LOTUS_JAEGER_AGENT_HOST=jaeger
- LOTUS_JAEGER_AGENT_PORT=6831
# - DOCKER_LOTUS_IMPORT_WALLET=/tmp/wallet
deploy:
restart_policy:
condition: on-failure
delay: 30s
# configs:
# - source: lotus-config-toml
# target: /var/lib/lotus/config.toml
# secrets:
# - source: lotus-wallet
# target: /tmp/wallet
command:
- daemon
lotus-gateway:
build:
context: .
target: lotus-gateway
dockerfile: Dockerfile.lotus
image: filecoin/lotus-gateway
depends_on:
- lotus
ports:
- 1235:1234
environment:
- FULLNODE_API_INFO=/dns/lotus/tcp/1234/http
- LOTUS_JAEGER_AGENT_HOST=jaeger
- LOTUS_JAEGER_AGENT_PORT=6831
deploy:
restart_policy:
condition: on-failure
delay: 30s
command:
- run
#
# Uncomment to run miner software
#
# lotus-miner:
# build:
# context: .
# target: lotus-miner
# dockerfile: Dockerfile.lotus
# image: filecoin/lotus-miner
# volumes:
# - parameters:/var/tmp/filecoin-proof-parameters
# - lotus-miner-repo:/var/lib/lotus-miner
# depends_on:
# - lotus
# ports:
# - 2345:2345
# environment:
# - FULLNODE_API_INFO=/dns/lotus/tcp/1234/http
# - LOTUS_JAEGER_AGENT_HOST=jaeger
# - LOTUS_JAEGER_AGENT_PORT=6831
# deploy:
# restart_policy:
# condition: on-failure
# delay: 30s
# configs:
# - source: lotus-miner-config-toml
# - target: /var/lib/lotus-miner/config.toml
# command:
# - run
# lotus-worker:
# build:
# context: .
# target: lotus-worker
# dockerfile: Dockerfile.lotus
# image: filecoin/lotus-worker
# volumes:
# - parameters:/var/tmp/filecoin-proof-parameters
# - lotus-worker-repo:/var/lib/lotus-worker
# depends_on:
# - lotus-worker
# environment:
# - MINER_API_INFO=/dns/lotus-miner/tcp/1234/http
# - LOTUS_JAEGER_AGENT_HOST=jaeger
# - LOTUS_JAEGER_AGENT_PORT=6831
# deploy:
# restart_policy:
# condition: on-failure
# delay: 30s
# replicas: 2
# command:
# - run
jaeger:
image: jaegertracing/all-in-one
ports:
- "6831:6831/udp"
- "16686:16686"
deploy:
restart_policy:
condition: on-failure
delay: 30s
+1 -1
View File
@@ -199,7 +199,7 @@ Response:
```json ```json
{ {
"Version": "string value", "Version": "string value",
"APIVersion": 131328, "APIVersion": 131329,
"BlockDelay": 42 "BlockDelay": 42
} }
``` ```
+1 -1
View File
@@ -144,7 +144,7 @@ Perms: admin
Inputs: `null` Inputs: `null`
Response: `131328` Response: `131329`
## Add ## Add
+2 -2
View File
@@ -280,7 +280,7 @@ Response:
```json ```json
{ {
"Version": "string value", "Version": "string value",
"APIVersion": 131328, "APIVersion": 131329,
"BlockDelay": 42 "BlockDelay": 42
} }
``` ```
@@ -4634,7 +4634,7 @@ Inputs:
] ]
``` ```
Response: `13` Response: `1300`
### StateReadState ### StateReadState
StateReadState returns the indicated actor's state. StateReadState returns the indicated actor's state.
+30 -2
View File
@@ -11,6 +11,8 @@
* [Beacon](#Beacon) * [Beacon](#Beacon)
* [BeaconGetEntry](#BeaconGetEntry) * [BeaconGetEntry](#BeaconGetEntry)
* [Chain](#Chain) * [Chain](#Chain)
* [ChainBlockstoreInfo](#ChainBlockstoreInfo)
* [ChainCheckBlockstore](#ChainCheckBlockstore)
* [ChainDeleteObj](#ChainDeleteObj) * [ChainDeleteObj](#ChainDeleteObj)
* [ChainExport](#ChainExport) * [ChainExport](#ChainExport)
* [ChainGetBlock](#ChainGetBlock) * [ChainGetBlock](#ChainGetBlock)
@@ -282,7 +284,7 @@ Response:
```json ```json
{ {
"Version": "string value", "Version": "string value",
"APIVersion": 131328, "APIVersion": 131329,
"BlockDelay": 42 "BlockDelay": 42
} }
``` ```
@@ -350,6 +352,32 @@ The Chain method group contains methods for interacting with the
blockchain, but that do not require any form of state computation. blockchain, but that do not require any form of state computation.
### ChainBlockstoreInfo
ChainBlockstoreInfo returns some basic information about the blockstore
Perms: read
Inputs: `null`
Response:
```json
{
"abc": 123
}
```
### ChainCheckBlockstore
ChainCheckBlockstore performs an (asynchronous) health check on the chain/state blockstore
if supported by the underlying implementation.
Perms: admin
Inputs: `null`
Response: `{}`
### ChainDeleteObj ### ChainDeleteObj
ChainDeleteObj deletes node referenced by the given CID ChainDeleteObj deletes node referenced by the given CID
@@ -4855,7 +4883,7 @@ Inputs:
] ]
``` ```
Response: `13` Response: `1300`
### StateReadState ### StateReadState
StateReadState returns the indicated actor's state. StateReadState returns the indicated actor's state.
+55 -4
View File
@@ -13,7 +13,7 @@ COMMANDS:
init Initialize a lotus miner repo init Initialize a lotus miner repo
run Start a lotus miner process run Start a lotus miner process
stop Stop a running lotus miner stop Stop a running lotus miner
config Output default configuration config Manage node config
backup Create node metadata backup backup Create node metadata backup
version Print version version Print version
help, h Shows a list of commands or help for one command help, h Shows a list of commands or help for one command
@@ -145,13 +145,47 @@ OPTIONS:
## lotus-miner config ## lotus-miner config
``` ```
NAME: NAME:
lotus-miner config - Output default configuration lotus-miner config - Manage node config
USAGE: USAGE:
lotus-miner config [command options] [arguments...] lotus-miner config command [command options] [arguments...]
COMMANDS:
default Print default node config
updated Print updated node config
help, h Shows a list of commands or help for one command
OPTIONS: OPTIONS:
--help, -h show help (default: false) --help, -h show help (default: false)
--version, -v print the version (default: false)
```
### lotus-miner config default
```
NAME:
lotus-miner config default - Print default node config
USAGE:
lotus-miner config default [command options] [arguments...]
OPTIONS:
--no-comment don't comment default values (default: false)
--help, -h show help (default: false)
```
### lotus-miner config updated
```
NAME:
lotus-miner config updated - Print updated node config
USAGE:
lotus-miner config updated [command options] [arguments...]
OPTIONS:
--no-comment don't comment default values (default: false)
--help, -h show help (default: false)
``` ```
@@ -207,6 +241,7 @@ COMMANDS:
control Manage control addresses control Manage control addresses
propose-change-worker Propose a worker address change propose-change-worker Propose a worker address change
confirm-change-worker Confirm a worker address change confirm-change-worker Confirm a worker address change
compact-allocated compact allocated sectors bitfield
help, h Shows a list of commands or help for one command help, h Shows a list of commands or help for one command
OPTIONS: OPTIONS:
@@ -361,6 +396,22 @@ OPTIONS:
``` ```
### lotus-miner actor compact-allocated
```
NAME:
lotus-miner actor compact-allocated - compact allocated sectors bitfield
USAGE:
lotus-miner actor compact-allocated [command options] [arguments...]
OPTIONS:
--mask-last-offset value Mask sector IDs from 0 to 'higest_allocated - offset' (default: 0)
--mask-upto-n value Mask sector IDs from 0 to 'n' (default: 0)
--really-do-it Actually send transaction performing the action (default: false)
--help, -h show help (default: false)
```
## lotus-miner info ## lotus-miner info
``` ```
NAME: NAME:
+48
View File
@@ -12,6 +12,7 @@ VERSION:
COMMANDS: COMMANDS:
daemon Start a lotus daemon process daemon Start a lotus daemon process
backup Create node metadata backup backup Create node metadata backup
config Manage node config
version Print version version Print version
help, h Shows a list of commands or help for one command help, h Shows a list of commands or help for one command
BASIC: BASIC:
@@ -108,6 +109,53 @@ OPTIONS:
``` ```
## lotus config
```
NAME:
lotus config - Manage node config
USAGE:
lotus config command [command options] [arguments...]
COMMANDS:
default Print default node config
updated Print updated node config
help, h Shows a list of commands or help for one command
OPTIONS:
--help, -h show help (default: false)
--version, -v print the version (default: false)
```
### lotus config default
```
NAME:
lotus config default - Print default node config
USAGE:
lotus config default [command options] [arguments...]
OPTIONS:
--no-comment don't comment default values (default: false)
--help, -h show help (default: false)
```
### lotus config updated
```
NAME:
lotus config updated - Print updated node config
USAGE:
lotus config updated [command options] [arguments...]
OPTIONS:
--no-comment don't comment default values (default: false)
--help, -h show help (default: false)
```
## lotus version ## lotus version
``` ```
NAME: NAME:
+4
View File
@@ -69,6 +69,10 @@ func (mgr *CurrentDealInfoManager) dealIDFromPublishDealsMsg(ctx context.Context
return dealID, nil, xerrors.Errorf("looking for publish deal message %s: search msg failed: %w", publishCid, err) return dealID, nil, xerrors.Errorf("looking for publish deal message %s: search msg failed: %w", publishCid, err)
} }
if lookup == nil {
return dealID, nil, xerrors.Errorf("looking for publish deal message %s: not found", publishCid)
}
if lookup.Receipt.ExitCode != exitcode.Ok { if lookup.Receipt.ExitCode != exitcode.Ok {
return dealID, nil, xerrors.Errorf("looking for publish deal message %s: non-ok exit code: %s", publishCid, lookup.Receipt.ExitCode) return dealID, nil, xerrors.Errorf("looking for publish deal message %s: non-ok exit code: %s", publishCid, lookup.Receipt.ExitCode)
} }
+7 -1
View File
@@ -25,7 +25,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
var errNotFound = errors.New("Could not find") var errNotFound = errors.New("could not find")
func TestGetCurrentDealInfo(t *testing.T) { func TestGetCurrentDealInfo(t *testing.T) {
ctx := context.Background() ctx := context.Background()
@@ -180,6 +180,12 @@ func TestGetCurrentDealInfo(t *testing.T) {
expectedDealID: zeroDealID, expectedDealID: zeroDealID,
expectedError: xerrors.Errorf("looking for publish deal message %s: search msg failed: something went wrong", dummyCid), expectedError: xerrors.Errorf("looking for publish deal message %s: search msg failed: something went wrong", dummyCid),
}, },
"search message not found": {
publishCid: dummyCid,
targetProposal: &proposal,
expectedDealID: zeroDealID,
expectedError: xerrors.Errorf("looking for publish deal message %s: not found", dummyCid),
},
"return code not ok": { "return code not ok": {
publishCid: dummyCid, publishCid: dummyCid,
searchMessageLookup: &MsgLookup{ searchMessageLookup: &MsgLookup{
+9 -3
View File
@@ -358,8 +358,11 @@ func (m *Sealing) handlePreCommitting(ctx statemachine.Context, sector SectorInf
} }
params, pcd, tok, err := m.preCommitParams(ctx, sector) params, pcd, tok, err := m.preCommitParams(ctx, sector)
if params == nil || err != nil { if err != nil {
return err return ctx.Send(SectorChainPreCommitFailed{xerrors.Errorf("preCommitParams: %w", err)})
}
if params == nil {
return nil // event was sent in preCommitParams
} }
deposit, err := collateralSendAmount(ctx.Context(), m.api, m.maddr, cfg, pcd) deposit, err := collateralSendAmount(ctx.Context(), m.api, m.maddr, cfg, pcd)
@@ -403,9 +406,12 @@ func (m *Sealing) handleSubmitPreCommitBatch(ctx statemachine.Context, sector Se
} }
params, deposit, _, err := m.preCommitParams(ctx, sector) params, deposit, _, err := m.preCommitParams(ctx, sector)
if params == nil || err != nil { if err != nil {
return ctx.Send(SectorChainPreCommitFailed{xerrors.Errorf("preCommitParams: %w", err)}) return ctx.Send(SectorChainPreCommitFailed{xerrors.Errorf("preCommitParams: %w", err)})
} }
if params == nil {
return nil // event was sent in preCommitParams
}
res, err := m.precommiter.AddPreCommit(ctx.Context(), sector, deposit, params) res, err := m.precommiter.AddPreCommit(ctx.Context(), sector, deposit, params)
if err != nil { if err != nil {
+7 -1
View File
@@ -298,6 +298,9 @@ import (
} }
err = doTemplate(w, m, ` err = doTemplate(w, m, `
var ErrNotSupported = xerrors.New("method not supported")
{{range .Infos}} {{range .Infos}}
type {{.Name}}Struct struct { type {{.Name}}Struct struct {
{{range .Include}} {{range .Include}}
@@ -321,11 +324,14 @@ type {{.Name}}Stub struct {
{{$name := .Name}} {{$name := .Name}}
{{range .Methods}} {{range .Methods}}
func (s *{{$name}}Struct) {{.Name}}({{.NamedParams}}) ({{.Results}}) { func (s *{{$name}}Struct) {{.Name}}({{.NamedParams}}) ({{.Results}}) {
if s.Internal.{{.Name}} == nil {
return {{.DefRes}}ErrNotSupported
}
return s.Internal.{{.Name}}({{.ParamNames}}) return s.Internal.{{.Name}}({{.ParamNames}})
} }
func (s *{{$name}}Stub) {{.Name}}({{.NamedParams}}) ({{.Results}}) { func (s *{{$name}}Stub) {{.Name}}({{.NamedParams}}) ({{.Results}}) {
return {{.DefRes}}xerrors.New("method not supported") return {{.DefRes}}ErrNotSupported
} }
{{end}} {{end}}
{{end}} {{end}}
+5 -4
View File
@@ -35,12 +35,13 @@ require (
github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03
github.com/filecoin-project/go-data-transfer v1.7.0 github.com/filecoin-project/go-data-transfer v1.7.0
github.com/filecoin-project/go-fil-commcid v0.1.0 github.com/filecoin-project/go-fil-commcid v0.1.0
github.com/filecoin-project/go-fil-commp-hashhash v0.1.0
github.com/filecoin-project/go-fil-markets v1.6.0-rc1.0.20210726135502-29002ec31b5d github.com/filecoin-project/go-fil-markets v1.6.0-rc1.0.20210726135502-29002ec31b5d
github.com/filecoin-project/go-jsonrpc v0.1.4-0.20210217175800-45ea43ac2bec github.com/filecoin-project/go-jsonrpc v0.1.4-0.20210217175800-45ea43ac2bec
github.com/filecoin-project/go-multistore v0.0.3 github.com/filecoin-project/go-multistore v0.0.3
github.com/filecoin-project/go-padreader v0.0.0-20210723183308-812a16dc01b1 github.com/filecoin-project/go-padreader v0.0.0-20210723183308-812a16dc01b1
github.com/filecoin-project/go-paramfetch v0.0.2-0.20210614165157-25a6c7769498 github.com/filecoin-project/go-paramfetch v0.0.2-0.20210614165157-25a6c7769498
github.com/filecoin-project/go-state-types v0.1.1-0.20210506134452-99b279731c48 github.com/filecoin-project/go-state-types v0.1.1-0.20210722133031-ad9bfe54c124
github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe
github.com/filecoin-project/go-statestore v0.1.1 github.com/filecoin-project/go-statestore v0.1.1
github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b
@@ -48,7 +49,7 @@ require (
github.com/filecoin-project/specs-actors/v2 v2.3.5 github.com/filecoin-project/specs-actors/v2 v2.3.5
github.com/filecoin-project/specs-actors/v3 v3.1.1 github.com/filecoin-project/specs-actors/v3 v3.1.1
github.com/filecoin-project/specs-actors/v4 v4.0.1 github.com/filecoin-project/specs-actors/v4 v4.0.1
github.com/filecoin-project/specs-actors/v5 v5.0.1 github.com/filecoin-project/specs-actors/v5 v5.0.3
github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506
github.com/filecoin-project/test-vectors/schema v0.0.5 github.com/filecoin-project/test-vectors/schema v0.0.5
github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1
@@ -77,7 +78,7 @@ require (
github.com/ipfs/go-ds-pebble v0.0.2-0.20200921225637-ce220f8ac459 github.com/ipfs/go-ds-pebble v0.0.2-0.20200921225637-ce220f8ac459
github.com/ipfs/go-filestore v1.0.0 github.com/ipfs/go-filestore v1.0.0
github.com/ipfs/go-fs-lock v0.0.6 github.com/ipfs/go-fs-lock v0.0.6
github.com/ipfs/go-graphsync v0.6.4 github.com/ipfs/go-graphsync v0.6.5
github.com/ipfs/go-ipfs-blockstore v1.0.4 github.com/ipfs/go-ipfs-blockstore v1.0.4
github.com/ipfs/go-ipfs-blocksutil v0.0.1 github.com/ipfs/go-ipfs-blocksutil v0.0.1
github.com/ipfs/go-ipfs-chunker v0.0.5 github.com/ipfs/go-ipfs-chunker v0.0.5
@@ -153,7 +154,7 @@ require (
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 golang.org/x/time v0.0.0-20191024005414-555d28b269f0
golang.org/x/tools v0.1.0 golang.org/x/tools v0.1.5
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
gopkg.in/cheggaaa/pb.v1 v1.0.28 gopkg.in/cheggaaa/pb.v1 v1.0.28
gotest.tools v2.2.0+incompatible gotest.tools v2.2.0+incompatible

Some files were not shown because too many files have changed in this diff Show More