commit
19ee2a021b
@ -5,7 +5,7 @@ orbs:
|
||||
executors:
|
||||
golang:
|
||||
docker:
|
||||
- image: circleci/golang:1.14.2
|
||||
- image: circleci/golang:1.14.6
|
||||
resource_class: 2xlarge
|
||||
ubuntu:
|
||||
docker:
|
||||
@ -93,10 +93,10 @@ jobs:
|
||||
- store_artifacts:
|
||||
path: lotus
|
||||
- store_artifacts:
|
||||
path: lotus-storage-miner
|
||||
path: lotus-miner
|
||||
- store_artifacts:
|
||||
path: lotus-seal-worker
|
||||
- run: mkdir linux && mv lotus lotus-storage-miner lotus-seal-worker linux/
|
||||
path: lotus-worker
|
||||
- run: mkdir linux && mv lotus lotus-miner lotus-worker linux/
|
||||
- persist_to_workspace:
|
||||
root: "."
|
||||
paths:
|
||||
@ -134,7 +134,7 @@ jobs:
|
||||
description: Test suite name to report to CircleCI.
|
||||
gotestsum-format:
|
||||
type: string
|
||||
default: short
|
||||
default: pkgname-and-test-fails
|
||||
description: gotestsum format. https://github.com/gotestyourself/gotestsum#format
|
||||
coverage:
|
||||
type: string
|
||||
@ -156,21 +156,27 @@ jobs:
|
||||
- download-params
|
||||
- go/install-gotestsum:
|
||||
gobin: $HOME/.local/bin
|
||||
version: 0.5.2
|
||||
- run:
|
||||
name: go test
|
||||
environment:
|
||||
GOTESTSUM_JUNITFILE: /tmp/test-reports/<< parameters.test-suite-name >>/junit.xml
|
||||
GOTESTSUM_FORMAT: << parameters.gotestsum-format >>
|
||||
LOTUS_TEST_WINDOW_POST: << parameters.winpost-test >>
|
||||
command: |
|
||||
mkdir -p /tmp/test-reports/<< parameters.test-suite-name >>
|
||||
gotestsum -- \
|
||||
mkdir -p /tmp/test-artifacts
|
||||
gotestsum \
|
||||
--format << parameters.gotestsum-format >> \
|
||||
--junitfile /tmp/test-reports/<< parameters.test-suite-name >>/junit.xml \
|
||||
--jsonfile /tmp/test-artifacts/<< parameters.test-suite-name >>.json \
|
||||
-- \
|
||||
<< parameters.coverage >> \
|
||||
<< parameters.go-test-flags >> \
|
||||
<< parameters.packages >>
|
||||
no_output_timeout: 30m
|
||||
- store_test_results:
|
||||
path: /tmp/test-reports
|
||||
- store_artifacts:
|
||||
path: /tmp/test-artifacts/<< parameters.test-suite-name >>.json
|
||||
- when:
|
||||
condition: << parameters.codecov-upload >>
|
||||
steps:
|
||||
@ -223,10 +229,10 @@ jobs:
|
||||
- store_artifacts:
|
||||
path: lotus
|
||||
- store_artifacts:
|
||||
path: lotus-storage-miner
|
||||
path: lotus-miner
|
||||
- store_artifacts:
|
||||
path: lotus-seal-worker
|
||||
- run: mkdir darwin && mv lotus lotus-storage-miner lotus-seal-worker darwin/
|
||||
path: lotus-worker
|
||||
- run: mkdir darwin && mv lotus lotus-miner lotus-worker darwin/
|
||||
- persist_to_workspace:
|
||||
root: "."
|
||||
paths:
|
||||
@ -314,16 +320,19 @@ workflows:
|
||||
ci:
|
||||
jobs:
|
||||
- lint-changes:
|
||||
args: "--new-from-rev origin/next"
|
||||
args: "--new-from-rev origin/master"
|
||||
- mod-tidy-check
|
||||
- gofmt
|
||||
- test:
|
||||
codecov-upload: true
|
||||
test-suite-name: full
|
||||
- test-window-post:
|
||||
go-test-flags: "-run=TestWindowedPost"
|
||||
winpost-test: "1"
|
||||
test-suite-name: window-post
|
||||
- test-short:
|
||||
go-test-flags: "--timeout 10m --short"
|
||||
test-suite-name: short
|
||||
filters:
|
||||
tags:
|
||||
only:
|
||||
|
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -21,7 +21,7 @@ A clear and concise description of what you expected to happen.
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Version (run `lotus --version`):**
|
||||
**Version (run `lotus version`):**
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
8
.github/ISSUE_TEMPLATE/sealingfailed.md
vendored
8
.github/ISSUE_TEMPLATE/sealingfailed.md
vendored
@ -19,15 +19,15 @@ Including what commands you ran, and a description of your setup, is very helpfu
|
||||
|
||||
**Sectors list**
|
||||
|
||||
The output of `./lotus-storage-miner sectors list`.
|
||||
The output of `./lotus-miner sectors list`.
|
||||
|
||||
**Sectors status**
|
||||
|
||||
The output of `./lotus-storage-miner sectors status --log <sectorId>` for the failed sector(s).
|
||||
The output of `./lotus-miner sectors status --log <sectorId>` for the failed sector(s).
|
||||
|
||||
**Lotus storage miner logs**
|
||||
**Lotus miner logs**
|
||||
|
||||
Please go through the logs of your storage miner, and include screenshots of any error-like messages you find.
|
||||
Please go through the logs of your miner, and include screenshots of any error-like messages you find.
|
||||
|
||||
**Version**
|
||||
|
||||
|
18
.gitignore
vendored
18
.gitignore
vendored
@ -1,19 +1,21 @@
|
||||
/lotus
|
||||
/lotus-storage-miner
|
||||
/lotus-seal-worker
|
||||
/lotus-miner
|
||||
/lotus-worker
|
||||
/lotus-seed
|
||||
/lotus-health
|
||||
/lotus-chainwatch
|
||||
/lotus-shed
|
||||
/pond
|
||||
/townhall
|
||||
/fountain
|
||||
/stats
|
||||
/bench
|
||||
/lotus-pond
|
||||
/lotus-townhall
|
||||
/lotus-fountain
|
||||
/lotus-stats
|
||||
/lotus-bench
|
||||
/bench.json
|
||||
/lotuspond/front/node_modules
|
||||
/lotuspond/front/build
|
||||
/cmd/lotus-townhall/townhall/node_modules
|
||||
/cmd/lotus-townhall/townhall/build
|
||||
/cmd/lotus-townhall/townhall/package-lock.json
|
||||
extern/filecoin-ffi/rust/target
|
||||
**/*.a
|
||||
**/*.pc
|
||||
@ -24,7 +26,6 @@ build/paramfetch.sh
|
||||
/vendor
|
||||
/blocks.dot
|
||||
/blocks.svg
|
||||
/chainwatch
|
||||
/chainwatch.db
|
||||
/bundle
|
||||
/darwin
|
||||
@ -35,3 +36,4 @@ build/paramfetch.sh
|
||||
bin/ipget
|
||||
bin/tmp/*
|
||||
.idea
|
||||
scratchpad
|
||||
|
131
Makefile
131
Makefile
@ -6,7 +6,7 @@ all: build
|
||||
unexport GOFLAGS
|
||||
|
||||
GOVERSION:=$(shell go version | cut -d' ' -f 3 | cut -d. -f 2)
|
||||
ifeq ($(shell expr $(GOVERSION) \< 13), 1)
|
||||
ifeq ($(shell expr $(GOVERSION) \< 14), 1)
|
||||
$(warning Your Golang version is go 1.$(GOVERSION))
|
||||
$(error Update Golang to version $(shell grep '^go' go.mod))
|
||||
endif
|
||||
@ -58,10 +58,10 @@ deps: $(BUILD_DEPS)
|
||||
.PHONY: deps
|
||||
|
||||
debug: GOFLAGS+=-tags=debug
|
||||
debug: lotus lotus-storage-miner lotus-seal-worker lotus-seed
|
||||
debug: lotus lotus-miner lotus-worker lotus-seed
|
||||
|
||||
2k: GOFLAGS+=-tags=2k
|
||||
2k: lotus lotus-storage-miner lotus-seal-worker lotus-seed
|
||||
2k: lotus lotus-miner lotus-worker lotus-seed
|
||||
|
||||
lotus: $(BUILD_DEPS)
|
||||
rm -f lotus
|
||||
@ -71,19 +71,19 @@ lotus: $(BUILD_DEPS)
|
||||
.PHONY: lotus
|
||||
BINS+=lotus
|
||||
|
||||
lotus-storage-miner: $(BUILD_DEPS)
|
||||
rm -f lotus-storage-miner
|
||||
go build $(GOFLAGS) -o lotus-storage-miner ./cmd/lotus-storage-miner
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-storage-miner -i ./build
|
||||
.PHONY: lotus-storage-miner
|
||||
BINS+=lotus-storage-miner
|
||||
lotus-miner: $(BUILD_DEPS)
|
||||
rm -f lotus-miner
|
||||
go build $(GOFLAGS) -o lotus-miner ./cmd/lotus-storage-miner
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-miner -i ./build
|
||||
.PHONY: lotus-miner
|
||||
BINS+=lotus-miner
|
||||
|
||||
lotus-seal-worker: $(BUILD_DEPS)
|
||||
rm -f lotus-seal-worker
|
||||
go build $(GOFLAGS) -o lotus-seal-worker ./cmd/lotus-seal-worker
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-seal-worker -i ./build
|
||||
.PHONY: lotus-seal-worker
|
||||
BINS+=lotus-seal-worker
|
||||
lotus-worker: $(BUILD_DEPS)
|
||||
rm -f lotus-worker
|
||||
go build $(GOFLAGS) -o lotus-worker ./cmd/lotus-seal-worker
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-worker -i ./build
|
||||
.PHONY: lotus-worker
|
||||
BINS+=lotus-worker
|
||||
|
||||
lotus-shed: $(BUILD_DEPS)
|
||||
rm -f lotus-shed
|
||||
@ -92,7 +92,7 @@ lotus-shed: $(BUILD_DEPS)
|
||||
.PHONY: lotus-shed
|
||||
BINS+=lotus-shed
|
||||
|
||||
build: lotus lotus-storage-miner lotus-seal-worker
|
||||
build: lotus lotus-miner lotus-worker
|
||||
@[[ $$(type -P "lotus") ]] && echo "Caution: you have \
|
||||
an existing lotus binary in your PATH. This may cause problems if you don't run 'sudo make install'" || true
|
||||
|
||||
@ -100,20 +100,22 @@ an existing lotus binary in your PATH. This may cause problems if you don't run
|
||||
|
||||
install:
|
||||
install -C ./lotus /usr/local/bin/lotus
|
||||
install -C ./lotus-storage-miner /usr/local/bin/lotus-storage-miner
|
||||
install -C ./lotus-seal-worker /usr/local/bin/lotus-seal-worker
|
||||
install -C ./lotus-miner /usr/local/bin/lotus-miner
|
||||
install -C ./lotus-worker /usr/local/bin/lotus-worker
|
||||
|
||||
install-services: install
|
||||
mkdir -p /usr/local/lib/systemd/system
|
||||
mkdir -p /var/log/lotus
|
||||
install -C -m 0644 ./scripts/lotus-daemon.service /usr/local/lib/systemd/system/lotus-daemon.service
|
||||
install -C -m 0644 ./scripts/lotus-miner.service /usr/local/lib/systemd/system/lotus-miner.service
|
||||
systemctl daemon-reload
|
||||
@echo
|
||||
@echo "lotus and lotus-miner services installed. Don't forget to 'systemctl enable lotus|lotus-miner' for it to be enabled on startup."
|
||||
@echo "lotus-daemon and lotus-miner services installed. Don't forget to 'systemctl enable lotus-daemon|lotus-miner' for it to be enabled on startup."
|
||||
|
||||
clean-services:
|
||||
rm -f /usr/local/lib/systemd/system/lotus-daemon.service
|
||||
rm -f /usr/local/lib/systemd/system/lotus-miner.service
|
||||
rm -f /usr/local/lib/systemd/system/lotus-chainwatch.service
|
||||
systemctl daemon-reload
|
||||
|
||||
# TOOLS
|
||||
@ -132,55 +134,66 @@ benchmarks:
|
||||
@curl -X POST 'http://benchmark.kittyhawk.wtf/benchmark' -d '@bench.json' -u "${benchmark_http_cred}"
|
||||
.PHONY: benchmarks
|
||||
|
||||
pond: 2k
|
||||
go build -o pond ./lotuspond
|
||||
lotus-pond: 2k
|
||||
go build -o lotus-pond ./lotuspond
|
||||
(cd lotuspond/front && npm i && CI=false npm run build)
|
||||
.PHONY: pond
|
||||
BINS+=pond
|
||||
.PHONY: lotus-pond
|
||||
BINS+=lotus-pond
|
||||
|
||||
townhall:
|
||||
rm -f townhall
|
||||
go build -o townhall ./cmd/lotus-townhall
|
||||
lotus-townhall:
|
||||
rm -f lotus-townhall
|
||||
go build -o lotus-townhall ./cmd/lotus-townhall
|
||||
(cd ./cmd/lotus-townhall/townhall && npm i && npm run build)
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec townhall -i ./cmd/lotus-townhall -i ./build
|
||||
.PHONY: townhall
|
||||
BINS+=townhall
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-townhall -i ./cmd/lotus-townhall -i ./build
|
||||
.PHONY: lotus-townhall
|
||||
BINS+=lotus-townhall
|
||||
|
||||
fountain:
|
||||
rm -f fountain
|
||||
go build -o fountain ./cmd/lotus-fountain
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec fountain -i ./cmd/lotus-fountain -i ./build
|
||||
.PHONY: fountain
|
||||
BINS+=fountain
|
||||
lotus-fountain:
|
||||
rm -f lotus-fountain
|
||||
go build -o lotus-fountain ./cmd/lotus-fountain
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-fountain -i ./cmd/lotus-fountain -i ./build
|
||||
.PHONY: lotus-fountain
|
||||
BINS+=lotus-fountain
|
||||
|
||||
chainwatch:
|
||||
rm -f chainwatch
|
||||
go build -o chainwatch ./cmd/lotus-chainwatch
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec chainwatch -i ./cmd/lotus-chainwatch -i ./build
|
||||
.PHONY: chainwatch
|
||||
BINS+=chainwatch
|
||||
lotus-chainwatch:
|
||||
rm -f lotus-chainwatch
|
||||
go build -o lotus-chainwatch ./cmd/lotus-chainwatch
|
||||
.PHONY: lotus-chainwatch
|
||||
BINS+=lotus-chainwatch
|
||||
|
||||
bench:
|
||||
rm -f bench
|
||||
go build -o bench ./cmd/lotus-bench
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec bench -i ./build
|
||||
.PHONY: bench
|
||||
BINS+=bench
|
||||
install-chainwatch-service: chainwatch
|
||||
mkdir -p /etc/lotus
|
||||
install -C ./lotus-chainwatch /usr/local/bin/lotus-chainwatch
|
||||
install -C -m 0644 ./scripts/lotus-chainwatch.service /usr/local/lib/systemd/system/lotus-chainwatch.service
|
||||
systemctl daemon-reload
|
||||
@echo
|
||||
@echo "chainwatch installed. Don't forget to 'systemctl enable chainwatch' for it to be enabled on startup."
|
||||
|
||||
stats:
|
||||
rm -f stats
|
||||
go build -o stats ./tools/stats
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec stats -i ./build
|
||||
.PHONY: stats
|
||||
BINS+=stats
|
||||
lotus-bench:
|
||||
rm -f lotus-bench
|
||||
go build -o lotus-bench ./cmd/lotus-bench
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-bench -i ./build
|
||||
.PHONY: lotus-bench
|
||||
BINS+=lotus-bench
|
||||
|
||||
health:
|
||||
lotus-stats:
|
||||
rm -f lotus-stats
|
||||
go build -o lotus-stats ./cmd/lotus-stats
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-stats -i ./build
|
||||
.PHONY: lotus-stats
|
||||
BINS+=lotus-stats
|
||||
|
||||
lotus-health:
|
||||
rm -f lotus-health
|
||||
go build -o lotus-health ./cmd/lotus-health
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-health -i ./build
|
||||
.PHONY: lotus-health
|
||||
BINS+=lotus-health
|
||||
|
||||
.PHONY: health
|
||||
BINS+=health
|
||||
testground:
|
||||
go build -tags testground -o /dev/null ./cmd/lotus
|
||||
.PHONY: testground
|
||||
BINS+=testground
|
||||
|
||||
# MISC
|
||||
|
||||
@ -188,15 +201,15 @@ buildall: $(BINS)
|
||||
|
||||
completions:
|
||||
./scripts/make-completions.sh lotus
|
||||
./scripts/make-completions.sh lotus-storage-miner
|
||||
./scripts/make-completions.sh lotus-miner
|
||||
.PHONY: completions
|
||||
|
||||
install-completions:
|
||||
mkdir -p /usr/share/bash-completion/completions /usr/local/share/zsh/site-functions/
|
||||
install -C ./scripts/bash-completion/lotus /usr/share/bash-completion/completions/lotus
|
||||
install -C ./scripts/bash-completion/lotus-storage-miner /usr/share/bash-completion/completions/lotus-storage-miner
|
||||
install -C ./scripts/bash-completion/lotus-miner /usr/share/bash-completion/completions/lotus-miner
|
||||
install -C ./scripts/zsh-completion/lotus /usr/local/share/zsh/site-functions/_lotus
|
||||
install -C ./scripts/zsh-completion/lotus-storage-miner /usr/local/share/zsh/site-functions/_lotus-storage-miner
|
||||
install -C ./scripts/zsh-completion/lotus-miner /usr/local/share/zsh/site-functions/_lotus-miner
|
||||
|
||||
clean:
|
||||
rm -rf $(CLEAN) $(BINS)
|
||||
|
17
README.md
17
README.md
@ -4,14 +4,23 @@
|
||||
|
||||
Lotus is an implementation of the Filecoin Distributed Storage Network. For more details about Filecoin, check out the [Filecoin Spec](https://github.com/filecoin-project/specs).
|
||||
|
||||
## Development
|
||||
|
||||
All work is tracked via issues. An attempt at keeping an up-to-date view on remaining work is in the [lotus testnet github project board](https://github.com/filecoin-project/lotus/projects/1).
|
||||
|
||||
## Building & Documentation
|
||||
|
||||
For instructions on how to build lotus from source, please visit [https://docs.lotu.sh](https://docs.lotu.sh) or read the source [here](https://github.com/filecoin-project/lotus/tree/master/documentation).
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please send an email to security@filecoin.org. See our [security policy](SECURITY.md) for more details.
|
||||
|
||||
## Development
|
||||
|
||||
All work is tracked via issues. An attempt at keeping an up-to-date view on remaining work is in the [lotus testnet github project board](https://github.com/filecoin-project/lotus/projects/1).
|
||||
|
||||
The main branches under development at the moment are:
|
||||
* [`master`](https://github.com/filecoin-project/lotus): current testnet.
|
||||
* [`next`](https://github.com/filecoin-project/lotus/tree/next): working branch with chain-breaking changes.
|
||||
* [`interopnet`](https://github.com/filecoin-project/lotus/tree/interopnet): devnet running one of `next` commits.
|
||||
|
||||
## License
|
||||
|
||||
Dual-licensed under [MIT](https://github.com/filecoin-project/lotus/blob/master/LICENSE-MIT) + [Apache 2.0](https://github.com/filecoin-project/lotus/blob/master/LICENSE-APACHE)
|
||||
|
29
SECURITY.md
Normal file
29
SECURITY.md
Normal file
@ -0,0 +1,29 @@
|
||||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
For *critical* bugs, please send an email to security@filecoin.org.
|
||||
|
||||
The bug reporting process differs between bugs that are critical and may crash the network, and others that are unlikely to cause problems if malicious parties know about it. For non-critical bugs, please simply file a GitHub [issue](https://github.com/filecoin-project/lotus/issues/new?template=bug_report.md).
|
||||
|
||||
Please try to provide a clear description of any bugs reported, along with how to reproduce the bug if possible. More detailed bug reports (especially those with a PoC included) will help us move forward much faster. Additionally, please avoid reporting bugs that already have open issues. Take a moment to search the issue list of the related GitHub repositories before writing up a new report.
|
||||
|
||||
Here are some examples of bugs we would consider 'critical':
|
||||
|
||||
* If you can spend from a `multisig` wallet you do not control the keys for.
|
||||
* If you can cause a miner to be slashed without them actually misbehaving.
|
||||
* If you can maintain power without submitting windowed posts regularly.
|
||||
* If you can craft a message that causes lotus nodes to panic.
|
||||
* If you can cause your miner to win significantly more blocks than it should.
|
||||
* If you can craft a message that causes a persistent fork in the network.
|
||||
* If you can cause the total amount of Filecoin in the network to no longer be 2 billion.
|
||||
|
||||
This is not an exhaustive list, but should provide some idea of what we consider 'critical'.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
* TODO: This should be defined and set up by Mainnet launch.
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| Testnet | :white_check_mark: |
|
@ -13,11 +13,13 @@ import (
|
||||
)
|
||||
|
||||
type Common interface {
|
||||
// Auth
|
||||
|
||||
// MethodGroup: Auth
|
||||
|
||||
AuthVerify(ctx context.Context, token string) ([]auth.Permission, error)
|
||||
AuthNew(ctx context.Context, perms []auth.Permission) ([]byte, error)
|
||||
|
||||
// network
|
||||
// MethodGroup: Net
|
||||
|
||||
NetConnectedness(context.Context, peer.ID) (network.Connectedness, error)
|
||||
NetPeers(context.Context) ([]peer.AddrInfo, error)
|
||||
@ -27,6 +29,8 @@ type Common interface {
|
||||
NetFindPeer(context.Context, peer.ID) (peer.AddrInfo, error)
|
||||
NetPubsubScores(context.Context) ([]PubsubScore, error)
|
||||
|
||||
// MethodGroup: Common
|
||||
|
||||
// ID returns peerID of libp2p node backing this API
|
||||
ID(context.Context) (peer.ID, error)
|
||||
|
||||
@ -38,6 +42,8 @@ type Common interface {
|
||||
|
||||
// trigger graceful shutdown
|
||||
Shutdown(context.Context) error
|
||||
|
||||
Closing(context.Context) (<-chan struct{}, error)
|
||||
}
|
||||
|
||||
// Version provides various build-time information
|
||||
|
288
api/api_full.go
288
api/api_full.go
@ -5,7 +5,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-filestore"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
@ -16,6 +15,7 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@ -26,60 +26,136 @@ import (
|
||||
type FullNode interface {
|
||||
Common
|
||||
|
||||
// TODO: TipSetKeys
|
||||
|
||||
// MethodGroup: Chain
|
||||
// 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.
|
||||
|
||||
// ChainNotify returns channel with chain head updates
|
||||
// First message is guaranteed to be of len == 1, and type == 'current'
|
||||
// ChainNotify returns channel with chain head updates.
|
||||
// First message is guaranteed to be of len == 1, and type == 'current'.
|
||||
ChainNotify(context.Context) (<-chan []*HeadChange, error)
|
||||
// ChainHead returns the current head of the chain
|
||||
|
||||
// ChainHead returns the current head of the chain.
|
||||
ChainHead(context.Context) (*types.TipSet, error)
|
||||
// ChainGetRandomness is used to sample the chain for randomness
|
||||
|
||||
// ChainGetRandomness is used to sample the chain for randomness.
|
||||
ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
|
||||
// ChainGetBlock returns the block specified by the given CID
|
||||
|
||||
// ChainGetBlock returns the block specified by the given CID.
|
||||
ChainGetBlock(context.Context, cid.Cid) (*types.BlockHeader, error)
|
||||
// ChainGetTipSet returns the tipset specified by the given TipSetKey.
|
||||
ChainGetTipSet(context.Context, types.TipSetKey) (*types.TipSet, error)
|
||||
ChainGetBlockMessages(context.Context, cid.Cid) (*BlockMessages, error)
|
||||
ChainGetParentReceipts(context.Context, cid.Cid) ([]*types.MessageReceipt, error)
|
||||
ChainGetParentMessages(context.Context, cid.Cid) ([]Message, error)
|
||||
|
||||
// ChainGetBlockMessages returns messages stored in the specified block.
|
||||
ChainGetBlockMessages(ctx context.Context, blockCid cid.Cid) (*BlockMessages, error)
|
||||
|
||||
// ChainGetParentReceipts returns receipts for messages in parent tipset of
|
||||
// the specified block.
|
||||
ChainGetParentReceipts(ctx context.Context, blockCid cid.Cid) ([]*types.MessageReceipt, error)
|
||||
|
||||
// ChainGetParentMessages returns messages stored in parent tipset of the
|
||||
// specified block.
|
||||
ChainGetParentMessages(ctx context.Context, blockCid cid.Cid) ([]Message, error)
|
||||
|
||||
// ChainGetTipSetByHeight looks back for a tipset at the specified epoch.
|
||||
// If there are no blocks at the specified epoch, a tipset at higher epoch
|
||||
// will be returned.
|
||||
ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error)
|
||||
|
||||
// ChainReadObj reads ipld nodes referenced by the specified CID from chain
|
||||
// blockstore and returns raw bytes.
|
||||
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
|
||||
|
||||
// ChainHasObj checks if a given CID exists in the chain blockstore.
|
||||
ChainHasObj(context.Context, cid.Cid) (bool, error)
|
||||
ChainStatObj(context.Context, cid.Cid, cid.Cid) (ObjStat, error)
|
||||
|
||||
// ChainSetHead forcefully sets current chain head. Use with caution.
|
||||
ChainSetHead(context.Context, types.TipSetKey) error
|
||||
|
||||
// ChainGetGenesis returns the genesis tipset.
|
||||
ChainGetGenesis(context.Context) (*types.TipSet, error)
|
||||
|
||||
// ChainTipSetWeight computes weight for the specified tipset.
|
||||
ChainTipSetWeight(context.Context, types.TipSetKey) (types.BigInt, error)
|
||||
ChainGetNode(ctx context.Context, p string) (*IpldObject, error)
|
||||
|
||||
// ChainGetMessage reads a message referenced by the specified CID from the
|
||||
// chain blockstore.
|
||||
ChainGetMessage(context.Context, cid.Cid) (*types.Message, error)
|
||||
|
||||
// ChainGetPath returns a set of revert/apply operations needed to get from
|
||||
// one tipset to another, for example:
|
||||
//```
|
||||
// to
|
||||
// ^
|
||||
// from tAA
|
||||
// ^ ^
|
||||
// tBA tAB
|
||||
// ^---*--^
|
||||
// ^
|
||||
// tRR
|
||||
//```
|
||||
// Would return `[revert(tBA), apply(tAB), apply(tAA)]`
|
||||
ChainGetPath(ctx context.Context, from types.TipSetKey, to types.TipSetKey) ([]*HeadChange, error)
|
||||
|
||||
// ChainExport returns a stream of bytes with CAR dump of chain data.
|
||||
ChainExport(context.Context, types.TipSetKey) (<-chan []byte, error)
|
||||
|
||||
// GasEstimateGasLimit estimates gas used by the message and returns it.
|
||||
// It fails if message fails to execute.
|
||||
GasEstimateGasLimit(context.Context, *types.Message, types.TipSetKey) (int64, error)
|
||||
|
||||
// GasEstimateGasPrice estimates what gas price should be used for a
|
||||
// message to have high likelihood of inclusion in `nblocksincl` epochs.
|
||||
|
||||
GasEstimateGasPrice(_ context.Context, nblocksincl uint64,
|
||||
sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error)
|
||||
|
||||
// MethodGroup: Sync
|
||||
// The Sync method group contains methods for interacting with and
|
||||
// observing the lotus sync service
|
||||
// observing the lotus sync service.
|
||||
|
||||
// SyncState returns the current status of the lotus sync system
|
||||
// SyncState returns the current status of the lotus sync system.
|
||||
SyncState(context.Context) (*SyncState, error)
|
||||
// SyncSubmitBlock can be used to submit a newly created block to the
|
||||
|
||||
// SyncSubmitBlock can be used to submit a newly created block to the.
|
||||
// network through this node
|
||||
SyncSubmitBlock(ctx context.Context, blk *types.BlockMsg) error
|
||||
|
||||
// SyncIncomingBlocks returns a channel streaming incoming, potentially not
|
||||
// yet synced block headers.
|
||||
SyncIncomingBlocks(ctx context.Context) (<-chan *types.BlockHeader, error)
|
||||
|
||||
// SyncMarkBad marks a blocks as bad, meaning that it won't ever by synced.
|
||||
// Use with extreme caution.
|
||||
SyncMarkBad(ctx context.Context, bcid cid.Cid) error
|
||||
|
||||
// SyncCheckBad checks if a block was marked as bad, and if it was, returns
|
||||
// the reason.
|
||||
SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error)
|
||||
|
||||
// MethodGroup: Mpool
|
||||
// The Mpool methods are for interacting with the message pool. The message pool
|
||||
// manages all incoming and outgoing 'messages' going over the network.
|
||||
|
||||
// MpoolPending returns pending mempool messages.
|
||||
MpoolPending(context.Context, types.TipSetKey) ([]*types.SignedMessage, error)
|
||||
|
||||
// MpoolPush pushes a signed message to mempool.
|
||||
MpoolPush(context.Context, *types.SignedMessage) (cid.Cid, error)
|
||||
MpoolPushMessage(context.Context, *types.Message) (*types.SignedMessage, error) // get nonce, sign, push
|
||||
|
||||
// MpoolPushMessage atomically assigns a nonce, signs, and pushes a message
|
||||
// to mempool.
|
||||
MpoolPushMessage(context.Context, *types.Message) (*types.SignedMessage, error)
|
||||
|
||||
// MpoolGetNonce gets next nonce for the specified sender.
|
||||
// Note that this method may not be atomic. Use MpoolPushMessage instead.
|
||||
MpoolGetNonce(context.Context, address.Address) (uint64, error)
|
||||
MpoolSub(context.Context) (<-chan MpoolUpdate, error)
|
||||
MpoolEstimateGasPrice(context.Context, uint64, address.Address, int64, types.TipSetKey) (types.BigInt, error)
|
||||
|
||||
// MpoolEstimateGasPrice is depracated
|
||||
// Deprecated: use GasEstimateGasPrice instead
|
||||
MpoolEstimateGasPrice(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error)
|
||||
|
||||
// MethodGroup: Miner
|
||||
|
||||
@ -90,17 +166,30 @@ type FullNode interface {
|
||||
|
||||
// MethodGroup: Wallet
|
||||
|
||||
// WalletNew creates a new address in the wallet with the given sigType.
|
||||
WalletNew(context.Context, crypto.SigType) (address.Address, error)
|
||||
// WalletHas indicates whether the given address is in the wallet.
|
||||
WalletHas(context.Context, address.Address) (bool, error)
|
||||
// WalletList lists all the addresses in the wallet.
|
||||
WalletList(context.Context) ([]address.Address, error)
|
||||
// WalletBalance returns the balance of the given address at the current head of the chain.
|
||||
WalletBalance(context.Context, address.Address) (types.BigInt, error)
|
||||
// WalletSign signs the given bytes using the given address.
|
||||
WalletSign(context.Context, address.Address, []byte) (*crypto.Signature, error)
|
||||
// WalletSignMessage signs the given message using the given address.
|
||||
WalletSignMessage(context.Context, address.Address, *types.Message) (*types.SignedMessage, error)
|
||||
// WalletVerify takes an address, a signature, and some bytes, and indicates whether the signature is valid.
|
||||
// The address does not have to be in the wallet.
|
||||
WalletVerify(context.Context, address.Address, []byte, *crypto.Signature) bool
|
||||
// WalletDefaultAddress returns the address marked as default in the wallet.
|
||||
WalletDefaultAddress(context.Context) (address.Address, error)
|
||||
// WalletSetDefault marks the given address as as the default one.
|
||||
WalletSetDefault(context.Context, address.Address) error
|
||||
// WalletExport returns the private key of an address in the wallet.
|
||||
WalletExport(context.Context, address.Address) (*types.KeyInfo, error)
|
||||
// WalletImport receives a KeyInfo, which includes a private key, and imports it into the wallet.
|
||||
WalletImport(context.Context, *types.KeyInfo) (address.Address, error)
|
||||
// WalletDelete deletes an address from the wallet.
|
||||
WalletDelete(context.Context, address.Address) error
|
||||
|
||||
// Other
|
||||
@ -109,18 +198,29 @@ type FullNode interface {
|
||||
// The Client methods all have to do with interacting with the storage and
|
||||
// retrieval markets as a client
|
||||
|
||||
// ClientImport imports file under the specified path into filestore
|
||||
ClientImport(ctx context.Context, ref FileRef) (cid.Cid, error)
|
||||
// ClientStartDeal proposes a deal with a miner
|
||||
// ClientImport imports file under the specified path into filestore.
|
||||
ClientImport(ctx context.Context, ref FileRef) (*ImportRes, error)
|
||||
// ClientRemoveImport removes file import
|
||||
ClientRemoveImport(ctx context.Context, importID int) error
|
||||
// ClientStartDeal proposes a deal with a miner.
|
||||
ClientStartDeal(ctx context.Context, params *StartDealParams) (*cid.Cid, error)
|
||||
// ClientGetDeal info returns the latest information about a given deal
|
||||
// ClientGetDealInfo returns the latest information about a given deal.
|
||||
ClientGetDealInfo(context.Context, cid.Cid) (*DealInfo, error)
|
||||
// ClientListDeals returns information about the deals made by the local client.
|
||||
ClientListDeals(ctx context.Context) ([]DealInfo, error)
|
||||
// ClientHasLocal indicates whether a certain CID is locally stored.
|
||||
ClientHasLocal(ctx context.Context, root cid.Cid) (bool, error)
|
||||
ClientFindData(ctx context.Context, root cid.Cid) ([]QueryOffer, error)
|
||||
// ClientFindData identifies peers that have a certain file, and returns QueryOffers (one per peer).
|
||||
ClientFindData(ctx context.Context, root cid.Cid, piece *cid.Cid) ([]QueryOffer, error)
|
||||
// ClientMinerQueryOffer returns a QueryOffer for the specific miner and file.
|
||||
ClientMinerQueryOffer(ctx context.Context, miner address.Address, root cid.Cid, piece *cid.Cid) (QueryOffer, error)
|
||||
// ClientRetrieve initiates the retrieval of a file, as specified in the order.
|
||||
ClientRetrieve(ctx context.Context, order RetrievalOrder, ref *FileRef) error
|
||||
// ClientQueryAsk returns a signed StorageAsk from the specified miner.
|
||||
ClientQueryAsk(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error)
|
||||
// ClientCalcCommP calculates the CommP for a specified file, based on the sector size of the provided miner.
|
||||
ClientCalcCommP(ctx context.Context, inpath string, miner address.Address) (*CommPRet, error)
|
||||
// ClientGenCar generates a CAR file for the specified file.
|
||||
ClientGenCar(ctx context.Context, ref FileRef, outpath string) error
|
||||
|
||||
// ClientUnimport removes references to the specified file from filestore
|
||||
@ -132,55 +232,131 @@ type FullNode interface {
|
||||
//ClientListAsks() []Ask
|
||||
|
||||
// MethodGroup: State
|
||||
// The State methods are used to query, inspect, and interact with chain state
|
||||
// The State methods are used to query, inspect, and interact with chain state.
|
||||
// All methods take a TipSetKey as a parameter. The state looked up is the state at that tipset.
|
||||
// A nil TipSetKey can be provided as a param, this will cause the heaviest tipset in the chain to be used.
|
||||
|
||||
// if tipset is nil, we'll use heaviest
|
||||
// StateCall runs the given message and returns its result without any persisted changes.
|
||||
StateCall(context.Context, *types.Message, types.TipSetKey) (*InvocResult, error)
|
||||
// StateReplay returns the result of executing the indicated message, assuming it was executed in the indicated tipset.
|
||||
StateReplay(context.Context, types.TipSetKey, cid.Cid) (*InvocResult, error)
|
||||
// StateGetActor returns the indicated actor's nonce and balance.
|
||||
StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error)
|
||||
StateReadState(ctx context.Context, act *types.Actor, tsk types.TipSetKey) (*ActorState, error)
|
||||
// StateReadState returns the indicated actor's state.
|
||||
StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*ActorState, error)
|
||||
// StateListMessages looks back and returns all messages with a matching to or from address, stopping at the given height.
|
||||
StateListMessages(ctx context.Context, match *types.Message, tsk types.TipSetKey, toht abi.ChainEpoch) ([]cid.Cid, error)
|
||||
|
||||
// StateNetworkName returns the name of the network the node is synced to
|
||||
StateNetworkName(context.Context) (dtypes.NetworkName, error)
|
||||
// StateMinerSectors returns info about the given miner's sectors. If the filter bitfield is nil, all sectors are included.
|
||||
// If the filterOut boolean is set to true, any sectors in the filter are excluded.
|
||||
// If false, only those sectors in the filter are included.
|
||||
StateMinerSectors(context.Context, address.Address, *abi.BitField, bool, types.TipSetKey) ([]*ChainSectorInfo, error)
|
||||
StateMinerProvingSet(context.Context, address.Address, types.TipSetKey) ([]*ChainSectorInfo, error)
|
||||
// StateMinerActiveSectors returns info about sectors that a given miner is actively proving.
|
||||
StateMinerActiveSectors(context.Context, address.Address, types.TipSetKey) ([]*ChainSectorInfo, error)
|
||||
// StateMinerProvingDeadline calculates the deadline at some epoch for a proving period
|
||||
// and returns the deadline-related calculations.
|
||||
StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error)
|
||||
// StateMinerPower returns the power of the indicated miner
|
||||
StateMinerPower(context.Context, address.Address, types.TipSetKey) (*MinerPower, error)
|
||||
// StateMinerInfo returns info about the indicated miner
|
||||
StateMinerInfo(context.Context, address.Address, types.TipSetKey) (MinerInfo, error)
|
||||
StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) (*miner.Deadlines, error)
|
||||
// StateMinerDeadlines returns all the proving deadlines for the given miner
|
||||
StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) ([]*miner.Deadline, error)
|
||||
// StateMinerPartitions loads miner partitions for the specified miner/deadline
|
||||
StateMinerPartitions(context.Context, address.Address, uint64, types.TipSetKey) ([]*miner.Partition, error)
|
||||
// StateMinerFaults returns a bitfield indicating the faulty sectors of the given miner
|
||||
StateMinerFaults(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error)
|
||||
// Returns all non-expired Faults that occur within lookback epochs of the given tipset
|
||||
// StateAllMinerFaults returns all non-expired Faults that occur within lookback epochs of the given tipset
|
||||
StateAllMinerFaults(ctx context.Context, lookback abi.ChainEpoch, ts types.TipSetKey) ([]*Fault, error)
|
||||
// StateMinerRecoveries returns a bitfield indicating the recovering sectors of the given miner
|
||||
StateMinerRecoveries(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error)
|
||||
StateMinerInitialPledgeCollateral(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (types.BigInt, error)
|
||||
// StateMinerInitialPledgeCollateral returns the initial pledge collateral for the specified miner's sector
|
||||
StateMinerInitialPledgeCollateral(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error)
|
||||
// StateMinerAvailableBalance returns the portion of a miner's balance that can be withdrawn or spent
|
||||
StateMinerAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
|
||||
// StateSectorPreCommitInfo returns the PreCommit info for the specified miner's sector
|
||||
StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error)
|
||||
// StateSectorGetInfo returns the on-chain info for the specified miner's sector
|
||||
// NOTE: returned info.Expiration may not be accurate in some cases, use StateSectorExpiration to get accurate
|
||||
// expiration epoch
|
||||
StateSectorGetInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error)
|
||||
// StateSectorExpiration returns epoch at which given sector will expire
|
||||
StateSectorExpiration(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*SectorExpiration, error)
|
||||
// StateSectorPartition finds deadline/partition with the specified sector
|
||||
StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*SectorLocation, error)
|
||||
StatePledgeCollateral(context.Context, types.TipSetKey) (types.BigInt, error)
|
||||
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*MsgLookup, error)
|
||||
// StateSearchMsg searches for a message in the chain, and returns its receipt and the tipset where it was executed
|
||||
StateSearchMsg(context.Context, cid.Cid) (*MsgLookup, error)
|
||||
// StateWaitMsg looks back in the chain for a message. If not found, it blocks until the
|
||||
// message arrives on chain, and gets to the indicated confidence depth.
|
||||
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*MsgLookup, error)
|
||||
// StateListMiners returns the addresses of every miner that has claimed power in the Power Actor
|
||||
StateListMiners(context.Context, types.TipSetKey) ([]address.Address, error)
|
||||
// StateListActors returns the addresses of every actor in the state
|
||||
StateListActors(context.Context, types.TipSetKey) ([]address.Address, error)
|
||||
// StateMarketBalance looks up the Escrow and Locked balances of the given address in the Storage Market
|
||||
StateMarketBalance(context.Context, address.Address, types.TipSetKey) (MarketBalance, error)
|
||||
// StateMarketParticipants returns the Escrow and Locked balances of every participant in the Storage Market
|
||||
StateMarketParticipants(context.Context, types.TipSetKey) (map[string]MarketBalance, error)
|
||||
// StateMarketDeals returns information about every deal in the Storage Market
|
||||
StateMarketDeals(context.Context, types.TipSetKey) (map[string]MarketDeal, error)
|
||||
// StateMarketStorageDeal returns information about the indicated deal
|
||||
StateMarketStorageDeal(context.Context, abi.DealID, types.TipSetKey) (*MarketDeal, error)
|
||||
// StateLookupID retrieves the ID address of the given address
|
||||
StateLookupID(context.Context, address.Address, types.TipSetKey) (address.Address, error)
|
||||
// StateAccountKey returns the public key address of the given ID address
|
||||
StateAccountKey(context.Context, address.Address, types.TipSetKey) (address.Address, error)
|
||||
// StateChangedActors returns all the actors whose states change between the two given state CIDs
|
||||
// TODO: Should this take tipset keys instead?
|
||||
StateChangedActors(context.Context, cid.Cid, cid.Cid) (map[string]types.Actor, error)
|
||||
// StateGetReceipt returns the message receipt for the given message
|
||||
StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error)
|
||||
// StateMinerSectorCount returns the number of sectors in a miner's sector set and proving set
|
||||
StateMinerSectorCount(context.Context, address.Address, types.TipSetKey) (MinerSectors, error)
|
||||
// StateCompute is a flexible command that applies the given messages on the given tipset.
|
||||
// The messages are run as though the VM were at the provided height.
|
||||
StateCompute(context.Context, abi.ChainEpoch, []*types.Message, types.TipSetKey) (*ComputeStateOutput, error)
|
||||
// StateVerifiedClientStatus returns the data cap for the given address.
|
||||
// Returns nil if there is no entry in the data cap table for the
|
||||
// address.
|
||||
StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*verifreg.DataCap, error)
|
||||
|
||||
// MethodGroup: Msig
|
||||
// The Msig methods are used to interact with multisig wallets on the
|
||||
// filecoin network
|
||||
|
||||
// MsigGetAvailableBalance returns the portion of a multisig's balance that can be withdrawn or spent
|
||||
MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
|
||||
MsigCreate(context.Context, int64, []address.Address, types.BigInt, address.Address, types.BigInt) (cid.Cid, error)
|
||||
// MsigCreate creates a multisig wallet
|
||||
// It takes the following params: <required number of senders>, <approving addresses>, <unlock duration>
|
||||
//<initial balance>, <sender address of the create msg>, <gas price>
|
||||
MsigCreate(context.Context, uint64, []address.Address, abi.ChainEpoch, types.BigInt, address.Address, types.BigInt) (cid.Cid, error)
|
||||
// MsigPropose proposes a multisig message
|
||||
// It takes the following params: <multisig address>, <recipient address>, <value to transfer>,
|
||||
// <sender address of the propose msg>, <method to call in the proposed message>, <params to include in the proposed message>
|
||||
MsigPropose(context.Context, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
|
||||
// MsigApprove approves a previously-proposed multisig message
|
||||
// It takes the following params: <multisig address>, <proposed message ID>, <proposer address>, <recipient address>, <value to transfer>,
|
||||
// <sender address of the approve msg>, <method to call in the proposed message>, <params to include in the proposed message>
|
||||
MsigApprove(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
|
||||
MsigCancel(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
|
||||
// MsigCancel cancels a previously-proposed multisig message
|
||||
// It takes the following params: <multisig address>, <proposed message ID>, <recipient address>, <value to transfer>,
|
||||
// <sender address of the cancel msg>, <method to call in the proposed message>, <params to include in the proposed message>
|
||||
MsigCancel(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
|
||||
// MsigSwapPropose proposes swapping 2 signers in the multisig
|
||||
// It takes the following params: <multisig address>, <sender address of the propose msg>,
|
||||
// <old signer> <new signer>
|
||||
MsigSwapPropose(context.Context, address.Address, address.Address, address.Address, address.Address) (cid.Cid, error)
|
||||
// MsigSwapApprove approves a previously proposed SwapSigner
|
||||
// It takes the following params: <multisig address>, <sender address of the approve msg>, <proposed message ID>,
|
||||
// <proposer address>, <old signer> <new signer>
|
||||
MsigSwapApprove(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, address.Address) (cid.Cid, error)
|
||||
// MsigSwapCancel cancels a previously proposed SwapSigner message
|
||||
// It takes the following params: <multisig address>, <sender address of the cancel msg>, <proposed message ID>,
|
||||
// <old signer> <new signer>
|
||||
MsigSwapCancel(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error)
|
||||
|
||||
MarketEnsureAvailable(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error)
|
||||
// MarketFreeBalance
|
||||
@ -208,15 +384,35 @@ type FileRef struct {
|
||||
}
|
||||
|
||||
type MinerSectors struct {
|
||||
Sset uint64
|
||||
Pset uint64
|
||||
Sectors uint64
|
||||
Active uint64
|
||||
}
|
||||
|
||||
type SectorExpiration struct {
|
||||
OnTime abi.ChainEpoch
|
||||
|
||||
// non-zero if sector is faulty, epoch at which it will be permanently
|
||||
// removed if it doesn't recover
|
||||
Early abi.ChainEpoch
|
||||
}
|
||||
|
||||
type SectorLocation struct {
|
||||
Deadline uint64
|
||||
Partition uint64
|
||||
}
|
||||
|
||||
type ImportRes struct {
|
||||
Root cid.Cid
|
||||
ImportID int
|
||||
}
|
||||
|
||||
type Import struct {
|
||||
Status filestore.Status
|
||||
Key cid.Cid
|
||||
Key int
|
||||
Err string
|
||||
|
||||
Root *cid.Cid
|
||||
Source string
|
||||
FilePath string
|
||||
Size uint64
|
||||
}
|
||||
|
||||
type DealInfo struct {
|
||||
@ -225,6 +421,7 @@ type DealInfo struct {
|
||||
Message string // more information about deal state, particularly errors
|
||||
Provider address.Address
|
||||
|
||||
DataRef *storagemarket.DataRef
|
||||
PieceCID cid.Cid
|
||||
Size uint64
|
||||
|
||||
@ -235,8 +432,10 @@ type DealInfo struct {
|
||||
}
|
||||
|
||||
type MsgLookup struct {
|
||||
Receipt types.MessageReceipt
|
||||
TipSet *types.TipSet
|
||||
Receipt types.MessageReceipt
|
||||
ReturnDec interface{}
|
||||
TipSet types.TipSetKey
|
||||
Height abi.ChainEpoch
|
||||
}
|
||||
|
||||
type BlockMessages struct {
|
||||
@ -302,7 +501,8 @@ type MinerPower struct {
|
||||
type QueryOffer struct {
|
||||
Err string
|
||||
|
||||
Root cid.Cid
|
||||
Root cid.Cid
|
||||
Piece *cid.Cid
|
||||
|
||||
Size uint64
|
||||
MinPrice types.BigInt
|
||||
@ -315,6 +515,7 @@ type QueryOffer struct {
|
||||
func (o *QueryOffer) Order(client address.Address) RetrievalOrder {
|
||||
return RetrievalOrder{
|
||||
Root: o.Root,
|
||||
Piece: o.Piece,
|
||||
Size: o.Size,
|
||||
Total: o.MinPrice,
|
||||
PaymentInterval: o.PaymentInterval,
|
||||
@ -338,8 +539,9 @@ type MarketDeal struct {
|
||||
|
||||
type RetrievalOrder struct {
|
||||
// TODO: make this less unixfs specific
|
||||
Root cid.Cid
|
||||
Size uint64
|
||||
Root cid.Cid
|
||||
Piece *cid.Cid
|
||||
Size uint64
|
||||
// TODO: support offset
|
||||
Total types.BigInt
|
||||
PaymentInterval uint64
|
||||
@ -369,6 +571,8 @@ type StartDealParams struct {
|
||||
EpochPrice types.BigInt
|
||||
MinBlocksDuration uint64
|
||||
DealStartEpoch abi.ChainEpoch
|
||||
FastRetrieval bool
|
||||
VerifiedDeal bool
|
||||
}
|
||||
|
||||
type IpldObject struct {
|
||||
|
@ -3,12 +3,14 @@ package api
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/sector-storage/fsutil"
|
||||
"github.com/filecoin-project/sector-storage/stores"
|
||||
"github.com/filecoin-project/sector-storage/storiface"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
@ -35,11 +37,26 @@ type StorageMiner interface {
|
||||
|
||||
SectorsRefs(context.Context) (map[string][]SealedRef, error)
|
||||
|
||||
// SectorStartSealing can be called on sectors in Empty or WaitDeals states
|
||||
// to trigger sealing early
|
||||
SectorStartSealing(context.Context, abi.SectorNumber) error
|
||||
// SectorSetSealDelay sets the time that a newly-created sector
|
||||
// waits for more deals before it starts sealing
|
||||
SectorSetSealDelay(context.Context, time.Duration) error
|
||||
// SectorGetSealDelay gets the time that a newly-created sector
|
||||
// waits for more deals before it starts sealing
|
||||
SectorGetSealDelay(context.Context) (time.Duration, error)
|
||||
// SectorSetExpectedSealDuration sets the expected time for a sector to seal
|
||||
SectorSetExpectedSealDuration(context.Context, time.Duration) error
|
||||
// SectorGetExpectedSealDuration gets the expected time for a sector to seal
|
||||
SectorGetExpectedSealDuration(context.Context) (time.Duration, error)
|
||||
SectorsUpdate(context.Context, abi.SectorNumber, SectorState) error
|
||||
SectorRemove(context.Context, abi.SectorNumber) error
|
||||
SectorMarkForUpgrade(ctx context.Context, id abi.SectorNumber) error
|
||||
|
||||
StorageList(ctx context.Context) (map[stores.ID][]stores.Decl, error)
|
||||
StorageLocal(ctx context.Context) (map[stores.ID]string, error)
|
||||
StorageStat(ctx context.Context, id stores.ID) (stores.FsStat, error)
|
||||
StorageStat(ctx context.Context, id stores.ID) (fsutil.FsStat, error)
|
||||
|
||||
// WorkerConnect tells the node to connect to workers RPC
|
||||
WorkerConnect(context.Context, string) error
|
||||
@ -50,10 +67,21 @@ type StorageMiner interface {
|
||||
MarketImportDealData(ctx context.Context, propcid cid.Cid, path string) error
|
||||
MarketListDeals(ctx context.Context) ([]storagemarket.StorageDeal, error)
|
||||
MarketListIncompleteDeals(ctx context.Context) ([]storagemarket.MinerDeal, error)
|
||||
MarketSetPrice(context.Context, types.BigInt) error
|
||||
MarketSetAsk(ctx context.Context, price types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error
|
||||
MarketGetAsk(ctx context.Context) (*storagemarket.SignedStorageAsk, error)
|
||||
|
||||
DealsImportData(ctx context.Context, dealPropCid cid.Cid, file string) error
|
||||
DealsList(ctx context.Context) ([]storagemarket.StorageDeal, error)
|
||||
DealsConsiderOnlineStorageDeals(context.Context) (bool, error)
|
||||
DealsSetConsiderOnlineStorageDeals(context.Context, bool) error
|
||||
DealsConsiderOnlineRetrievalDeals(context.Context) (bool, error)
|
||||
DealsSetConsiderOnlineRetrievalDeals(context.Context, bool) error
|
||||
DealsPieceCidBlocklist(context.Context) ([]cid.Cid, error)
|
||||
DealsSetPieceCidBlocklist(context.Context, []cid.Cid) error
|
||||
DealsConsiderOfflineStorageDeals(context.Context) (bool, error)
|
||||
DealsSetConsiderOfflineStorageDeals(context.Context, bool) error
|
||||
DealsConsiderOfflineRetrievalDeals(context.Context) (bool, error)
|
||||
DealsSetConsiderOfflineRetrievalDeals(context.Context, bool) error
|
||||
|
||||
StorageAddLocal(ctx context.Context, path string) error
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package apistruct
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
@ -11,7 +12,7 @@ import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
"github.com/filecoin-project/go-jsonrpc/auth"
|
||||
|
||||
"github.com/filecoin-project/sector-storage/fsutil"
|
||||
"github.com/filecoin-project/sector-storage/sealtasks"
|
||||
"github.com/filecoin-project/sector-storage/stores"
|
||||
"github.com/filecoin-project/sector-storage/storiface"
|
||||
@ -19,6 +20,7 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-storage/storage"
|
||||
|
||||
@ -50,7 +52,8 @@ type CommonStruct struct {
|
||||
LogList func(context.Context) ([]string, error) `perm:"write"`
|
||||
LogSetLevel func(context.Context, string, string) error `perm:"write"`
|
||||
|
||||
Shutdown func(context.Context) error `perm:"admin"`
|
||||
Shutdown func(context.Context) error `perm:"admin"`
|
||||
Closing func(context.Context) (<-chan struct{}, error) `perm:"read"`
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,18 +82,20 @@ type FullNodeStruct struct {
|
||||
ChainGetPath func(context.Context, types.TipSetKey, types.TipSetKey) ([]*api.HeadChange, error) `perm:"read"`
|
||||
ChainExport func(context.Context, types.TipSetKey) (<-chan []byte, error) `perm:"read"`
|
||||
|
||||
GasEstimateGasPrice func(context.Context, uint64, address.Address, int64, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
GasEstimateGasLimit func(context.Context, *types.Message, types.TipSetKey) (int64, error) `perm:"read"`
|
||||
|
||||
SyncState func(context.Context) (*api.SyncState, error) `perm:"read"`
|
||||
SyncSubmitBlock func(ctx context.Context, blk *types.BlockMsg) error `perm:"write"`
|
||||
SyncIncomingBlocks func(ctx context.Context) (<-chan *types.BlockHeader, error) `perm:"read"`
|
||||
SyncMarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"`
|
||||
SyncCheckBad func(ctx context.Context, bcid cid.Cid) (string, error) `perm:"read"`
|
||||
|
||||
MpoolPending func(context.Context, types.TipSetKey) ([]*types.SignedMessage, error) `perm:"read"`
|
||||
MpoolPush func(context.Context, *types.SignedMessage) (cid.Cid, error) `perm:"write"`
|
||||
MpoolPushMessage func(context.Context, *types.Message) (*types.SignedMessage, error) `perm:"sign"`
|
||||
MpoolGetNonce func(context.Context, address.Address) (uint64, error) `perm:"read"`
|
||||
MpoolSub func(context.Context) (<-chan api.MpoolUpdate, error) `perm:"read"`
|
||||
MpoolEstimateGasPrice func(context.Context, uint64, address.Address, int64, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
MpoolPending func(context.Context, types.TipSetKey) ([]*types.SignedMessage, error) `perm:"read"`
|
||||
MpoolPush func(context.Context, *types.SignedMessage) (cid.Cid, error) `perm:"write"`
|
||||
MpoolPushMessage func(context.Context, *types.Message) (*types.SignedMessage, error) `perm:"sign"`
|
||||
MpoolGetNonce func(context.Context, address.Address) (uint64, error) `perm:"read"`
|
||||
MpoolSub func(context.Context) (<-chan api.MpoolUpdate, error) `perm:"read"`
|
||||
|
||||
MinerGetBaseInfo func(context.Context, address.Address, abi.ChainEpoch, types.TipSetKey) (*api.MiningBaseInfo, error) `perm:"read"`
|
||||
MinerCreateBlock func(context.Context, *api.BlockTemplate) (*types.BlockMsg, error) `perm:"write"`
|
||||
@ -108,36 +113,41 @@ type FullNodeStruct struct {
|
||||
WalletImport func(context.Context, *types.KeyInfo) (address.Address, error) `perm:"admin"`
|
||||
WalletDelete func(context.Context, address.Address) error `perm:"write"`
|
||||
|
||||
ClientImport func(ctx context.Context, ref api.FileRef) (cid.Cid, error) `perm:"admin"`
|
||||
ClientListImports func(ctx context.Context) ([]api.Import, error) `perm:"write"`
|
||||
ClientHasLocal func(ctx context.Context, root cid.Cid) (bool, error) `perm:"write"`
|
||||
ClientFindData func(ctx context.Context, root cid.Cid) ([]api.QueryOffer, error) `perm:"read"`
|
||||
ClientStartDeal func(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) `perm:"admin"`
|
||||
ClientGetDealInfo func(context.Context, cid.Cid) (*api.DealInfo, error) `perm:"read"`
|
||||
ClientListDeals func(ctx context.Context) ([]api.DealInfo, error) `perm:"write"`
|
||||
ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error `perm:"admin"`
|
||||
ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
|
||||
ClientCalcCommP func(ctx context.Context, inpath string, miner address.Address) (*api.CommPRet, error) `perm:"read"`
|
||||
ClientGenCar func(ctx context.Context, ref api.FileRef, outpath string) error `perm:"write"`
|
||||
ClientImport func(ctx context.Context, ref api.FileRef) (*api.ImportRes, error) `perm:"admin"`
|
||||
ClientListImports func(ctx context.Context) ([]api.Import, error) `perm:"write"`
|
||||
ClientRemoveImport func(ctx context.Context, importID int) error `perm:"admin"`
|
||||
ClientHasLocal func(ctx context.Context, root cid.Cid) (bool, error) `perm:"write"`
|
||||
ClientFindData func(ctx context.Context, root cid.Cid, piece *cid.Cid) ([]api.QueryOffer, error) `perm:"read"`
|
||||
ClientMinerQueryOffer func(ctx context.Context, miner address.Address, root cid.Cid, piece *cid.Cid) (api.QueryOffer, error) `perm:"read"`
|
||||
ClientStartDeal func(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) `perm:"admin"`
|
||||
ClientGetDealInfo func(context.Context, cid.Cid) (*api.DealInfo, error) `perm:"read"`
|
||||
ClientListDeals func(ctx context.Context) ([]api.DealInfo, error) `perm:"write"`
|
||||
ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error `perm:"admin"`
|
||||
ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
|
||||
ClientCalcCommP func(ctx context.Context, inpath string, miner address.Address) (*api.CommPRet, error) `perm:"read"`
|
||||
ClientGenCar func(ctx context.Context, ref api.FileRef, outpath string) error `perm:"write"`
|
||||
|
||||
StateNetworkName func(context.Context) (dtypes.NetworkName, error) `perm:"read"`
|
||||
StateMinerSectors func(context.Context, address.Address, *abi.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"`
|
||||
StateMinerProvingSet func(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"`
|
||||
StateMinerActiveSectors func(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"`
|
||||
StateMinerProvingDeadline func(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error) `perm:"read"`
|
||||
StateMinerPower func(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error) `perm:"read"`
|
||||
StateMinerInfo func(context.Context, address.Address, types.TipSetKey) (api.MinerInfo, error) `perm:"read"`
|
||||
StateMinerDeadlines func(context.Context, address.Address, types.TipSetKey) (*miner.Deadlines, error) `perm:"read"`
|
||||
StateMinerDeadlines func(context.Context, address.Address, types.TipSetKey) ([]*miner.Deadline, error) `perm:"read"`
|
||||
StateMinerPartitions func(context.Context, address.Address, uint64, types.TipSetKey) ([]*miner.Partition, error) `perm:"read"`
|
||||
StateMinerFaults func(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error) `perm:"read"`
|
||||
StateAllMinerFaults func(context.Context, abi.ChainEpoch, types.TipSetKey) ([]*api.Fault, error) `perm:"read"`
|
||||
StateMinerRecoveries func(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error) `perm:"read"`
|
||||
StateMinerInitialPledgeCollateral func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
StateMinerInitialPledgeCollateral func(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
StateMinerAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
StateSectorPreCommitInfo func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) `perm:"read"`
|
||||
StateSectorGetInfo func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error) `perm:"read"`
|
||||
StateSectorExpiration func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*api.SectorExpiration, error) `perm:"read"`
|
||||
StateSectorPartition func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*api.SectorLocation, error) `perm:"read"`
|
||||
StateCall func(context.Context, *types.Message, types.TipSetKey) (*api.InvocResult, error) `perm:"read"`
|
||||
StateReplay func(context.Context, types.TipSetKey, cid.Cid) (*api.InvocResult, error) `perm:"read"`
|
||||
StateGetActor func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) `perm:"read"`
|
||||
StateReadState func(context.Context, *types.Actor, types.TipSetKey) (*api.ActorState, error) `perm:"read"`
|
||||
StateReadState func(context.Context, address.Address, types.TipSetKey) (*api.ActorState, error) `perm:"read"`
|
||||
StatePledgeCollateral func(context.Context, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
StateWaitMsg func(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) `perm:"read"`
|
||||
StateSearchMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"`
|
||||
@ -154,12 +164,16 @@ type FullNodeStruct struct {
|
||||
StateMinerSectorCount func(context.Context, address.Address, types.TipSetKey) (api.MinerSectors, error) `perm:"read"`
|
||||
StateListMessages func(ctx context.Context, match *types.Message, tsk types.TipSetKey, toht abi.ChainEpoch) ([]cid.Cid, error) `perm:"read"`
|
||||
StateCompute func(context.Context, abi.ChainEpoch, []*types.Message, types.TipSetKey) (*api.ComputeStateOutput, error) `perm:"read"`
|
||||
StateVerifiedClientStatus func(context.Context, address.Address, types.TipSetKey) (*verifreg.DataCap, error) `perm:"read"`
|
||||
|
||||
MsigGetAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
MsigCreate func(context.Context, int64, []address.Address, types.BigInt, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"`
|
||||
MsigCreate func(context.Context, uint64, []address.Address, abi.ChainEpoch, types.BigInt, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"`
|
||||
MsigPropose func(context.Context, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
||||
MsigApprove func(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
||||
MsigCancel func(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
||||
MsigCancel func(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
||||
MsigSwapPropose func(context.Context, address.Address, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||
MsigSwapApprove func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||
MsigSwapCancel func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||
|
||||
MarketEnsureAvailable func(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"`
|
||||
|
||||
@ -192,36 +206,54 @@ type StorageMinerStruct struct {
|
||||
|
||||
MiningBase func(context.Context) (*types.TipSet, error) `perm:"read"`
|
||||
|
||||
MarketImportDealData func(context.Context, cid.Cid, string) error `perm:"write"`
|
||||
MarketListDeals func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"`
|
||||
MarketListIncompleteDeals func(ctx context.Context) ([]storagemarket.MinerDeal, error) `perm:"read"`
|
||||
MarketSetPrice func(context.Context, types.BigInt) error `perm:"admin"`
|
||||
MarketImportDealData func(context.Context, cid.Cid, string) error `perm:"write"`
|
||||
MarketListDeals func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"`
|
||||
MarketListIncompleteDeals func(ctx context.Context) ([]storagemarket.MinerDeal, error) `perm:"read"`
|
||||
MarketSetAsk func(ctx context.Context, price types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error `perm:"admin"`
|
||||
MarketGetAsk func(ctx context.Context) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
|
||||
|
||||
PledgeSector func(context.Context) error `perm:"write"`
|
||||
|
||||
SectorsStatus func(context.Context, abi.SectorNumber) (api.SectorInfo, error) `perm:"read"`
|
||||
SectorsList func(context.Context) ([]abi.SectorNumber, error) `perm:"read"`
|
||||
SectorsRefs func(context.Context) (map[string][]api.SealedRef, error) `perm:"read"`
|
||||
SectorsUpdate func(context.Context, abi.SectorNumber, api.SectorState) error `perm:"write"`
|
||||
SectorsStatus func(context.Context, abi.SectorNumber) (api.SectorInfo, error) `perm:"read"`
|
||||
SectorsList func(context.Context) ([]abi.SectorNumber, error) `perm:"read"`
|
||||
SectorsRefs func(context.Context) (map[string][]api.SealedRef, error) `perm:"read"`
|
||||
SectorStartSealing func(context.Context, abi.SectorNumber) error `perm:"write"`
|
||||
SectorSetSealDelay func(context.Context, time.Duration) error `perm:"write"`
|
||||
SectorGetSealDelay func(context.Context) (time.Duration, error) `perm:"read"`
|
||||
SectorSetExpectedSealDuration func(context.Context, time.Duration) error `perm:"write"`
|
||||
SectorGetExpectedSealDuration func(context.Context) (time.Duration, error) `perm:"read"`
|
||||
SectorsUpdate func(context.Context, abi.SectorNumber, api.SectorState) error `perm:"admin"`
|
||||
SectorRemove func(context.Context, abi.SectorNumber) error `perm:"admin"`
|
||||
SectorMarkForUpgrade func(ctx context.Context, id abi.SectorNumber) error `perm:"admin"`
|
||||
|
||||
WorkerConnect func(context.Context, string) error `perm:"admin"` // TODO: worker perm
|
||||
WorkerStats func(context.Context) (map[uint64]storiface.WorkerStats, error) `perm:"admin"`
|
||||
|
||||
StorageList func(context.Context) (map[stores.ID][]stores.Decl, error) `perm:"admin"`
|
||||
StorageLocal func(context.Context) (map[stores.ID]string, error) `perm:"admin"`
|
||||
StorageStat func(context.Context, stores.ID) (stores.FsStat, error) `perm:"admin"`
|
||||
StorageAttach func(context.Context, stores.StorageInfo, stores.FsStat) error `perm:"admin"`
|
||||
StorageDeclareSector func(context.Context, stores.ID, abi.SectorID, stores.SectorFileType, bool) error `perm:"admin"`
|
||||
StorageDropSector func(context.Context, stores.ID, abi.SectorID, stores.SectorFileType) error `perm:"admin"`
|
||||
StorageFindSector func(context.Context, abi.SectorID, stores.SectorFileType, bool) ([]stores.SectorStorageInfo, error) `perm:"admin"`
|
||||
StorageInfo func(context.Context, stores.ID) (stores.StorageInfo, error) `perm:"admin"`
|
||||
StorageBestAlloc func(ctx context.Context, allocate stores.SectorFileType, spt abi.RegisteredProof, sealing stores.PathType) ([]stores.StorageInfo, error) `perm:"admin"`
|
||||
StorageReportHealth func(ctx context.Context, id stores.ID, report stores.HealthReport) error `perm:"admin"`
|
||||
StorageLock func(ctx context.Context, sector abi.SectorID, read stores.SectorFileType, write stores.SectorFileType) error `perm:"admin"`
|
||||
StorageTryLock func(ctx context.Context, sector abi.SectorID, read stores.SectorFileType, write stores.SectorFileType) (bool, error) `perm:"admin"`
|
||||
StorageList func(context.Context) (map[stores.ID][]stores.Decl, error) `perm:"admin"`
|
||||
StorageLocal func(context.Context) (map[stores.ID]string, error) `perm:"admin"`
|
||||
StorageStat func(context.Context, stores.ID) (fsutil.FsStat, error) `perm:"admin"`
|
||||
StorageAttach func(context.Context, stores.StorageInfo, fsutil.FsStat) error `perm:"admin"`
|
||||
StorageDeclareSector func(context.Context, stores.ID, abi.SectorID, stores.SectorFileType, bool) error `perm:"admin"`
|
||||
StorageDropSector func(context.Context, stores.ID, abi.SectorID, stores.SectorFileType) error `perm:"admin"`
|
||||
StorageFindSector func(context.Context, abi.SectorID, stores.SectorFileType, bool) ([]stores.SectorStorageInfo, error) `perm:"admin"`
|
||||
StorageInfo func(context.Context, stores.ID) (stores.StorageInfo, error) `perm:"admin"`
|
||||
StorageBestAlloc func(ctx context.Context, allocate stores.SectorFileType, spt abi.RegisteredSealProof, sealing stores.PathType) ([]stores.StorageInfo, error) `perm:"admin"`
|
||||
StorageReportHealth func(ctx context.Context, id stores.ID, report stores.HealthReport) error `perm:"admin"`
|
||||
StorageLock func(ctx context.Context, sector abi.SectorID, read stores.SectorFileType, write stores.SectorFileType) error `perm:"admin"`
|
||||
StorageTryLock func(ctx context.Context, sector abi.SectorID, read stores.SectorFileType, write stores.SectorFileType) (bool, error) `perm:"admin"`
|
||||
|
||||
DealsImportData func(ctx context.Context, dealPropCid cid.Cid, file string) error `perm:"write"`
|
||||
DealsList func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"`
|
||||
DealsImportData func(ctx context.Context, dealPropCid cid.Cid, file string) error `perm:"write"`
|
||||
DealsList func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"`
|
||||
DealsConsiderOnlineStorageDeals func(context.Context) (bool, error) `perm:"read"`
|
||||
DealsSetConsiderOnlineStorageDeals func(context.Context, bool) error `perm:"admin"`
|
||||
DealsConsiderOnlineRetrievalDeals func(context.Context) (bool, error) `perm:"read"`
|
||||
DealsSetConsiderOnlineRetrievalDeals func(context.Context, bool) error `perm:"admin"`
|
||||
DealsConsiderOfflineStorageDeals func(context.Context) (bool, error) `perm:"read"`
|
||||
DealsSetConsiderOfflineStorageDeals func(context.Context, bool) error `perm:"admin"`
|
||||
DealsConsiderOfflineRetrievalDeals func(context.Context) (bool, error) `perm:"read"`
|
||||
DealsSetConsiderOfflineRetrievalDeals func(context.Context, bool) error `perm:"admin"`
|
||||
DealsPieceCidBlocklist func(context.Context) ([]cid.Cid, error) `perm:"read"`
|
||||
DealsSetPieceCidBlocklist func(context.Context, []cid.Cid) error `perm:"admin"`
|
||||
|
||||
StorageAddLocal func(ctx context.Context, path string) error `perm:"admin"`
|
||||
}
|
||||
@ -237,12 +269,14 @@ type WorkerStruct struct {
|
||||
Paths func(context.Context) ([]stores.StoragePath, error) `perm:"admin"`
|
||||
Info func(context.Context) (storiface.WorkerInfo, error) `perm:"admin"`
|
||||
|
||||
SealPreCommit1 func(ctx context.Context, sector abi.SectorID, ticket abi.SealRandomness, pieces []abi.PieceInfo) (storage.PreCommit1Out, error) `perm:"admin"`
|
||||
SealPreCommit2 func(context.Context, abi.SectorID, storage.PreCommit1Out) (cids storage.SectorCids, err error) `perm:"admin"`
|
||||
SealCommit1 func(ctx context.Context, sector abi.SectorID, ticket abi.SealRandomness, seed abi.InteractiveSealRandomness, pieces []abi.PieceInfo, cids storage.SectorCids) (storage.Commit1Out, error) `perm:"admin"`
|
||||
SealCommit2 func(context.Context, abi.SectorID, storage.Commit1Out) (storage.Proof, error) `perm:"admin"`
|
||||
FinalizeSector func(context.Context, abi.SectorID) error `perm:"admin"`
|
||||
MoveStorage func(ctx context.Context, sector abi.SectorID) error `perm:"admin"`
|
||||
SealPreCommit1 func(ctx context.Context, sector abi.SectorID, ticket abi.SealRandomness, pieces []abi.PieceInfo) (storage.PreCommit1Out, error) `perm:"admin"`
|
||||
SealPreCommit2 func(context.Context, abi.SectorID, storage.PreCommit1Out) (cids storage.SectorCids, err error) `perm:"admin"`
|
||||
SealCommit1 func(ctx context.Context, sector abi.SectorID, ticket abi.SealRandomness, seed abi.InteractiveSealRandomness, pieces []abi.PieceInfo, cids storage.SectorCids) (storage.Commit1Out, error) `perm:"admin"`
|
||||
SealCommit2 func(context.Context, abi.SectorID, storage.Commit1Out) (storage.Proof, error) `perm:"admin"`
|
||||
FinalizeSector func(context.Context, abi.SectorID, []storage.Range) error `perm:"admin"`
|
||||
ReleaseUnsealed func(ctx context.Context, sector abi.SectorID, safeToFree []storage.Range) error `perm:"admin"`
|
||||
Remove func(ctx context.Context, sector abi.SectorID) error `perm:"admin"`
|
||||
MoveStorage func(ctx context.Context, sector abi.SectorID) error `perm:"admin"`
|
||||
|
||||
UnsealPiece func(context.Context, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize, abi.SealRandomness, cid.Cid) error `perm:"admin"`
|
||||
ReadPiece func(context.Context, io.Writer, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize) error `perm:"admin"`
|
||||
@ -312,13 +346,21 @@ func (c *CommonStruct) Shutdown(ctx context.Context) error {
|
||||
return c.Internal.Shutdown(ctx)
|
||||
}
|
||||
|
||||
func (c *CommonStruct) Closing(ctx context.Context) (<-chan struct{}, error) {
|
||||
return c.Internal.Closing(ctx)
|
||||
}
|
||||
|
||||
// FullNodeStruct
|
||||
|
||||
func (c *FullNodeStruct) ClientListImports(ctx context.Context) ([]api.Import, error) {
|
||||
return c.Internal.ClientListImports(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientImport(ctx context.Context, ref api.FileRef) (cid.Cid, error) {
|
||||
func (c *FullNodeStruct) ClientRemoveImport(ctx context.Context, importID int) error {
|
||||
return c.Internal.ClientRemoveImport(ctx, importID)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientImport(ctx context.Context, ref api.FileRef) (*api.ImportRes, error) {
|
||||
return c.Internal.ClientImport(ctx, ref)
|
||||
}
|
||||
|
||||
@ -326,8 +368,12 @@ func (c *FullNodeStruct) ClientHasLocal(ctx context.Context, root cid.Cid) (bool
|
||||
return c.Internal.ClientHasLocal(ctx, root)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientFindData(ctx context.Context, root cid.Cid) ([]api.QueryOffer, error) {
|
||||
return c.Internal.ClientFindData(ctx, root)
|
||||
func (c *FullNodeStruct) ClientFindData(ctx context.Context, root cid.Cid, piece *cid.Cid) ([]api.QueryOffer, error) {
|
||||
return c.Internal.ClientFindData(ctx, root, piece)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientMinerQueryOffer(ctx context.Context, miner address.Address, root cid.Cid, piece *cid.Cid) (api.QueryOffer, error) {
|
||||
return c.Internal.ClientMinerQueryOffer(ctx, miner, root, piece)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientStartDeal(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) {
|
||||
@ -356,6 +402,16 @@ func (c *FullNodeStruct) ClientGenCar(ctx context.Context, ref api.FileRef, outp
|
||||
return c.Internal.ClientGenCar(ctx, ref, outpath)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) GasEstimateGasPrice(ctx context.Context, nblocksincl uint64,
|
||||
sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.GasEstimateGasPrice(ctx, nblocksincl, sender, gaslimit, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) GasEstimateGasLimit(ctx context.Context, msg *types.Message,
|
||||
tsk types.TipSetKey) (int64, error) {
|
||||
return c.Internal.GasEstimateGasLimit(ctx, msg, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MpoolPending(ctx context.Context, tsk types.TipSetKey) ([]*types.SignedMessage, error) {
|
||||
return c.Internal.MpoolPending(ctx, tsk)
|
||||
}
|
||||
@ -373,7 +429,7 @@ func (c *FullNodeStruct) MpoolSub(ctx context.Context) (<-chan api.MpoolUpdate,
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MpoolEstimateGasPrice(ctx context.Context, nblocksincl uint64, sender address.Address, limit int64, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.MpoolEstimateGasPrice(ctx, nblocksincl, sender, limit, tsk)
|
||||
return c.Internal.GasEstimateGasPrice(ctx, nblocksincl, sender, limit, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MinerGetBaseInfo(ctx context.Context, maddr address.Address, epoch abi.ChainEpoch, tsk types.TipSetKey) (*api.MiningBaseInfo, error) {
|
||||
@ -540,8 +596,8 @@ func (c *FullNodeStruct) StateMinerSectors(ctx context.Context, addr address.Add
|
||||
return c.Internal.StateMinerSectors(ctx, addr, filter, filterOut, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerProvingSet(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) {
|
||||
return c.Internal.StateMinerProvingSet(ctx, addr, tsk)
|
||||
func (c *FullNodeStruct) StateMinerActiveSectors(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) {
|
||||
return c.Internal.StateMinerActiveSectors(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*miner.DeadlineInfo, error) {
|
||||
@ -556,10 +612,14 @@ func (c *FullNodeStruct) StateMinerInfo(ctx context.Context, actor address.Addre
|
||||
return c.Internal.StateMinerInfo(ctx, actor, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerDeadlines(ctx context.Context, m address.Address, tsk types.TipSetKey) (*miner.Deadlines, error) {
|
||||
func (c *FullNodeStruct) StateMinerDeadlines(ctx context.Context, m address.Address, tsk types.TipSetKey) ([]*miner.Deadline, error) {
|
||||
return c.Internal.StateMinerDeadlines(ctx, m, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerPartitions(ctx context.Context, m address.Address, dlIdx uint64, tsk types.TipSetKey) ([]*miner.Partition, error) {
|
||||
return c.Internal.StateMinerPartitions(ctx, m, dlIdx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerFaults(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*abi.BitField, error) {
|
||||
return c.Internal.StateMinerFaults(ctx, actor, tsk)
|
||||
}
|
||||
@ -572,8 +632,8 @@ func (c *FullNodeStruct) StateMinerRecoveries(ctx context.Context, actor address
|
||||
return c.Internal.StateMinerRecoveries(ctx, actor, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerInitialPledgeCollateral(ctx context.Context, maddr address.Address, snum abi.SectorNumber, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.StateMinerInitialPledgeCollateral(ctx, maddr, snum, tsk)
|
||||
func (c *FullNodeStruct) StateMinerInitialPledgeCollateral(ctx context.Context, maddr address.Address, pci miner.SectorPreCommitInfo, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.StateMinerInitialPledgeCollateral(ctx, maddr, pci, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerAvailableBalance(ctx context.Context, maddr address.Address, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
@ -588,6 +648,14 @@ func (c *FullNodeStruct) StateSectorGetInfo(ctx context.Context, maddr address.A
|
||||
return c.Internal.StateSectorGetInfo(ctx, maddr, n, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateSectorExpiration(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*api.SectorExpiration, error) {
|
||||
return c.Internal.StateSectorExpiration(ctx, maddr, n, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*api.SectorLocation, error) {
|
||||
return c.Internal.StateSectorPartition(ctx, maddr, sectorNumber, tok)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateCall(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (*api.InvocResult, error) {
|
||||
return c.Internal.StateCall(ctx, msg, tsk)
|
||||
}
|
||||
@ -600,8 +668,8 @@ func (c *FullNodeStruct) StateGetActor(ctx context.Context, actor address.Addres
|
||||
return c.Internal.StateGetActor(ctx, actor, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateReadState(ctx context.Context, act *types.Actor, tsk types.TipSetKey) (*api.ActorState, error) {
|
||||
return c.Internal.StateReadState(ctx, act, tsk)
|
||||
func (c *FullNodeStruct) StateReadState(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*api.ActorState, error) {
|
||||
return c.Internal.StateReadState(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StatePledgeCollateral(ctx context.Context, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
@ -664,12 +732,16 @@ func (c *FullNodeStruct) StateCompute(ctx context.Context, height abi.ChainEpoch
|
||||
return c.Internal.StateCompute(ctx, height, msgs, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*verifreg.DataCap, error) {
|
||||
return c.Internal.StateVerifiedClientStatus(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigGetAvailableBalance(ctx context.Context, a address.Address, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.MsigGetAvailableBalance(ctx, a, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigCreate(ctx context.Context, req int64, addrs []address.Address, val types.BigInt, src address.Address, gp types.BigInt) (cid.Cid, error) {
|
||||
return c.Internal.MsigCreate(ctx, req, addrs, val, src, gp)
|
||||
func (c *FullNodeStruct) MsigCreate(ctx context.Context, req uint64, addrs []address.Address, duration abi.ChainEpoch, val types.BigInt, src address.Address, gp types.BigInt) (cid.Cid, error) {
|
||||
return c.Internal.MsigCreate(ctx, req, addrs, duration, val, src, gp)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigPropose(ctx context.Context, msig address.Address, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) {
|
||||
@ -680,8 +752,20 @@ func (c *FullNodeStruct) MsigApprove(ctx context.Context, msig address.Address,
|
||||
return c.Internal.MsigApprove(ctx, msig, txID, proposer, to, amt, src, method, params)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigCancel(ctx context.Context, msig address.Address, txID uint64, proposer address.Address, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) {
|
||||
return c.Internal.MsigCancel(ctx, msig, txID, proposer, to, amt, src, method, params)
|
||||
func (c *FullNodeStruct) MsigCancel(ctx context.Context, msig address.Address, txID uint64, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) {
|
||||
return c.Internal.MsigCancel(ctx, msig, txID, to, amt, src, method, params)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigSwapPropose(ctx context.Context, msig address.Address, src address.Address, oldAdd address.Address, newAdd address.Address) (cid.Cid, error) {
|
||||
return c.Internal.MsigSwapPropose(ctx, msig, src, oldAdd, newAdd)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigSwapApprove(ctx context.Context, msig address.Address, src address.Address, txID uint64, proposer address.Address, oldAdd address.Address, newAdd address.Address) (cid.Cid, error) {
|
||||
return c.Internal.MsigSwapApprove(ctx, msig, src, txID, proposer, oldAdd, newAdd)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigSwapCancel(ctx context.Context, msig address.Address, src address.Address, txID uint64, oldAdd address.Address, newAdd address.Address) (cid.Cid, error) {
|
||||
return c.Internal.MsigSwapCancel(ctx, msig, src, txID, oldAdd, newAdd)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MarketEnsureAvailable(ctx context.Context, addr, wallet address.Address, amt types.BigInt) (cid.Cid, error) {
|
||||
@ -768,10 +852,38 @@ func (c *StorageMinerStruct) SectorsRefs(ctx context.Context) (map[string][]api.
|
||||
return c.Internal.SectorsRefs(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) SectorStartSealing(ctx context.Context, number abi.SectorNumber) error {
|
||||
return c.Internal.SectorStartSealing(ctx, number)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) SectorSetSealDelay(ctx context.Context, delay time.Duration) error {
|
||||
return c.Internal.SectorSetSealDelay(ctx, delay)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) SectorGetSealDelay(ctx context.Context) (time.Duration, error) {
|
||||
return c.Internal.SectorGetSealDelay(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) SectorSetExpectedSealDuration(ctx context.Context, delay time.Duration) error {
|
||||
return c.Internal.SectorSetExpectedSealDuration(ctx, delay)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) SectorGetExpectedSealDuration(ctx context.Context) (time.Duration, error) {
|
||||
return c.Internal.SectorGetExpectedSealDuration(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) SectorsUpdate(ctx context.Context, id abi.SectorNumber, state api.SectorState) error {
|
||||
return c.Internal.SectorsUpdate(ctx, id, state)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) SectorRemove(ctx context.Context, number abi.SectorNumber) error {
|
||||
return c.Internal.SectorRemove(ctx, number)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) SectorMarkForUpgrade(ctx context.Context, number abi.SectorNumber) error {
|
||||
return c.Internal.SectorMarkForUpgrade(ctx, number)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) WorkerConnect(ctx context.Context, url string) error {
|
||||
return c.Internal.WorkerConnect(ctx, url)
|
||||
}
|
||||
@ -780,7 +892,7 @@ func (c *StorageMinerStruct) WorkerStats(ctx context.Context) (map[uint64]storif
|
||||
return c.Internal.WorkerStats(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) StorageAttach(ctx context.Context, si stores.StorageInfo, st stores.FsStat) error {
|
||||
func (c *StorageMinerStruct) StorageAttach(ctx context.Context, si stores.StorageInfo, st fsutil.FsStat) error {
|
||||
return c.Internal.StorageAttach(ctx, si, st)
|
||||
}
|
||||
|
||||
@ -804,7 +916,7 @@ func (c *StorageMinerStruct) StorageLocal(ctx context.Context) (map[stores.ID]st
|
||||
return c.Internal.StorageLocal(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) StorageStat(ctx context.Context, id stores.ID) (stores.FsStat, error) {
|
||||
func (c *StorageMinerStruct) StorageStat(ctx context.Context, id stores.ID) (fsutil.FsStat, error) {
|
||||
return c.Internal.StorageStat(ctx, id)
|
||||
}
|
||||
|
||||
@ -812,7 +924,7 @@ func (c *StorageMinerStruct) StorageInfo(ctx context.Context, id stores.ID) (sto
|
||||
return c.Internal.StorageInfo(ctx, id)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) StorageBestAlloc(ctx context.Context, allocate stores.SectorFileType, spt abi.RegisteredProof, pt stores.PathType) ([]stores.StorageInfo, error) {
|
||||
func (c *StorageMinerStruct) StorageBestAlloc(ctx context.Context, allocate stores.SectorFileType, spt abi.RegisteredSealProof, pt stores.PathType) ([]stores.StorageInfo, error) {
|
||||
return c.Internal.StorageBestAlloc(ctx, allocate, spt, pt)
|
||||
}
|
||||
|
||||
@ -840,8 +952,12 @@ func (c *StorageMinerStruct) MarketListIncompleteDeals(ctx context.Context) ([]s
|
||||
return c.Internal.MarketListIncompleteDeals(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) MarketSetPrice(ctx context.Context, p types.BigInt) error {
|
||||
return c.Internal.MarketSetPrice(ctx, p)
|
||||
func (c *StorageMinerStruct) MarketSetAsk(ctx context.Context, price types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error {
|
||||
return c.Internal.MarketSetAsk(ctx, price, duration, minPieceSize, maxPieceSize)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) MarketGetAsk(ctx context.Context) (*storagemarket.SignedStorageAsk, error) {
|
||||
return c.Internal.MarketGetAsk(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) DealsImportData(ctx context.Context, dealPropCid cid.Cid, file string) error {
|
||||
@ -852,6 +968,46 @@ func (c *StorageMinerStruct) DealsList(ctx context.Context) ([]storagemarket.Sto
|
||||
return c.Internal.DealsList(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) DealsConsiderOnlineStorageDeals(ctx context.Context) (bool, error) {
|
||||
return c.Internal.DealsConsiderOnlineStorageDeals(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) DealsSetConsiderOnlineStorageDeals(ctx context.Context, b bool) error {
|
||||
return c.Internal.DealsSetConsiderOnlineStorageDeals(ctx, b)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) DealsConsiderOnlineRetrievalDeals(ctx context.Context) (bool, error) {
|
||||
return c.Internal.DealsConsiderOnlineRetrievalDeals(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) DealsSetConsiderOnlineRetrievalDeals(ctx context.Context, b bool) error {
|
||||
return c.Internal.DealsSetConsiderOnlineRetrievalDeals(ctx, b)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) DealsPieceCidBlocklist(ctx context.Context) ([]cid.Cid, error) {
|
||||
return c.Internal.DealsPieceCidBlocklist(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) DealsSetPieceCidBlocklist(ctx context.Context, cids []cid.Cid) error {
|
||||
return c.Internal.DealsSetPieceCidBlocklist(ctx, cids)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) DealsConsiderOfflineStorageDeals(ctx context.Context) (bool, error) {
|
||||
return c.Internal.DealsConsiderOfflineStorageDeals(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) DealsSetConsiderOfflineStorageDeals(ctx context.Context, b bool) error {
|
||||
return c.Internal.DealsSetConsiderOfflineStorageDeals(ctx, b)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) DealsConsiderOfflineRetrievalDeals(ctx context.Context) (bool, error) {
|
||||
return c.Internal.DealsConsiderOfflineRetrievalDeals(ctx)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) DealsSetConsiderOfflineRetrievalDeals(ctx context.Context, b bool) error {
|
||||
return c.Internal.DealsSetConsiderOfflineRetrievalDeals(ctx, b)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) StorageAddLocal(ctx context.Context, path string) error {
|
||||
return c.Internal.StorageAddLocal(ctx, path)
|
||||
}
|
||||
@ -890,8 +1046,16 @@ func (w *WorkerStruct) SealCommit2(ctx context.Context, sector abi.SectorID, c1o
|
||||
return w.Internal.SealCommit2(ctx, sector, c1o)
|
||||
}
|
||||
|
||||
func (w *WorkerStruct) FinalizeSector(ctx context.Context, sector abi.SectorID) error {
|
||||
return w.Internal.FinalizeSector(ctx, sector)
|
||||
func (w *WorkerStruct) FinalizeSector(ctx context.Context, sector abi.SectorID, keepUnsealed []storage.Range) error {
|
||||
return w.Internal.FinalizeSector(ctx, sector, keepUnsealed)
|
||||
}
|
||||
|
||||
func (w *WorkerStruct) ReleaseUnsealed(ctx context.Context, sector abi.SectorID, safeToFree []storage.Range) error {
|
||||
return w.Internal.ReleaseUnsealed(ctx, sector, safeToFree)
|
||||
}
|
||||
|
||||
func (w *WorkerStruct) Remove(ctx context.Context, sector abi.SectorID) error {
|
||||
return w.Internal.Remove(ctx, sector)
|
||||
}
|
||||
|
||||
func (w *WorkerStruct) MoveStorage(ctx context.Context, sector abi.SectorID) error {
|
||||
|
@ -91,6 +91,8 @@ func (t *PaymentInfo) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *PaymentInfo) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = PaymentInfo{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@ -256,6 +258,8 @@ func (t *SealedRef) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *SealedRef) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = SealedRef{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@ -378,6 +382,8 @@ func (t *SealedRefs) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *SealedRefs) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = SealedRefs{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@ -505,6 +511,8 @@ func (t *SealTicket) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *SealTicket) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = SealTicket{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@ -647,6 +655,8 @@ func (t *SealSeed) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *SealSeed) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = SealSeed{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
|
@ -34,7 +34,7 @@ func NewFullNodeRPC(addr string, requestHeader http.Header) (api.FullNode, jsonr
|
||||
return &res, closer, err
|
||||
}
|
||||
|
||||
// NewStorageMinerRPC creates a new http jsonrpc client for storage miner
|
||||
// NewStorageMinerRPC creates a new http jsonrpc client for miner
|
||||
func NewStorageMinerRPC(addr string, requestHeader http.Header) (api.StorageMiner, jsonrpc.ClientCloser, error) {
|
||||
var res apistruct.StorageMinerStruct
|
||||
closer, err := jsonrpc.NewMergeClient(addr, "Filecoin",
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
"github.com/filecoin-project/go-jsonrpc/auth"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/api/apistruct"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
@ -72,10 +73,14 @@ func init() {
|
||||
addExample(pid)
|
||||
|
||||
addExample(bitfield.NewFromSet([]uint64{5}))
|
||||
addExample(abi.RegisteredProof_StackedDRG32GiBPoSt)
|
||||
addExample(abi.RegisteredSealProof_StackedDrg32GiBV1)
|
||||
addExample(abi.RegisteredPoStProof_StackedDrgWindow32GiBV1)
|
||||
addExample(abi.ChainEpoch(10101))
|
||||
addExample(crypto.SigTypeBLS)
|
||||
addExample(int64(9))
|
||||
addExample(12.3)
|
||||
addExample(123)
|
||||
addExample(uintptr(0))
|
||||
addExample(abi.MethodNum(1))
|
||||
addExample(exitcode.ExitCode(0))
|
||||
addExample(crypto.DomainSeparationTag_ElectionProofProduction)
|
||||
@ -94,17 +99,17 @@ func init() {
|
||||
addExample(api.PCHInbound)
|
||||
addExample(time.Minute)
|
||||
addExample(&types.ExecutionTrace{
|
||||
Msg: exampleValue(reflect.TypeOf(&types.Message{})).(*types.Message),
|
||||
MsgRct: exampleValue(reflect.TypeOf(&types.MessageReceipt{})).(*types.MessageReceipt),
|
||||
Msg: exampleValue(reflect.TypeOf(&types.Message{}), nil).(*types.Message),
|
||||
MsgRct: exampleValue(reflect.TypeOf(&types.MessageReceipt{}), nil).(*types.MessageReceipt),
|
||||
})
|
||||
addExample(map[string]types.Actor{
|
||||
"t01236": exampleValue(reflect.TypeOf(types.Actor{})).(types.Actor),
|
||||
"t01236": exampleValue(reflect.TypeOf(types.Actor{}), nil).(types.Actor),
|
||||
})
|
||||
addExample(map[string]api.MarketDeal{
|
||||
"t026363": exampleValue(reflect.TypeOf(api.MarketDeal{})).(api.MarketDeal),
|
||||
"t026363": exampleValue(reflect.TypeOf(api.MarketDeal{}), nil).(api.MarketDeal),
|
||||
})
|
||||
addExample(map[string]api.MarketBalance{
|
||||
"t026363": exampleValue(reflect.TypeOf(api.MarketBalance{})).(api.MarketBalance),
|
||||
"t026363": exampleValue(reflect.TypeOf(api.MarketBalance{}), nil).(api.MarketBalance),
|
||||
})
|
||||
|
||||
maddr, err := multiaddr.NewMultiaddr("/ip4/52.36.61.156/tcp/1347/p2p/12D3KooWFETiESTf1v4PGUvtnxMAcEFMzLZbJGg4tjWfGEimYior")
|
||||
@ -117,7 +122,7 @@ func init() {
|
||||
|
||||
}
|
||||
|
||||
func exampleValue(t reflect.Type) interface{} {
|
||||
func exampleValue(t, parent reflect.Type) interface{} {
|
||||
v, ok := ExampleValues[t]
|
||||
if ok {
|
||||
return v
|
||||
@ -126,25 +131,25 @@ func exampleValue(t reflect.Type) interface{} {
|
||||
switch t.Kind() {
|
||||
case reflect.Slice:
|
||||
out := reflect.New(t).Elem()
|
||||
reflect.Append(out, reflect.ValueOf(exampleValue(t.Elem())))
|
||||
reflect.Append(out, reflect.ValueOf(exampleValue(t.Elem(), t)))
|
||||
return out.Interface()
|
||||
case reflect.Chan:
|
||||
return exampleValue(t.Elem())
|
||||
return exampleValue(t.Elem(), nil)
|
||||
case reflect.Struct:
|
||||
es := exampleStruct(t)
|
||||
es := exampleStruct(t, parent)
|
||||
v := reflect.ValueOf(es).Elem().Interface()
|
||||
ExampleValues[t] = v
|
||||
return v
|
||||
case reflect.Array:
|
||||
out := reflect.New(t).Elem()
|
||||
for i := 0; i < t.Len(); i++ {
|
||||
out.Index(i).Set(reflect.ValueOf(exampleValue(t.Elem())))
|
||||
out.Index(i).Set(reflect.ValueOf(exampleValue(t.Elem(), t)))
|
||||
}
|
||||
return out.Interface()
|
||||
|
||||
case reflect.Ptr:
|
||||
if t.Elem().Kind() == reflect.Struct {
|
||||
es := exampleStruct(t.Elem())
|
||||
es := exampleStruct(t.Elem(), t)
|
||||
//ExampleValues[t] = es
|
||||
return es
|
||||
}
|
||||
@ -155,12 +160,15 @@ func exampleValue(t reflect.Type) interface{} {
|
||||
panic(fmt.Sprintf("No example value for type: %s", t))
|
||||
}
|
||||
|
||||
func exampleStruct(t reflect.Type) interface{} {
|
||||
func exampleStruct(t, parent reflect.Type) interface{} {
|
||||
ns := reflect.New(t)
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
f := t.Field(i)
|
||||
if f.Type == parent {
|
||||
continue
|
||||
}
|
||||
if strings.Title(f.Name) == f.Name {
|
||||
ns.Elem().Field(i).Set(reflect.ValueOf(exampleValue(f.Type)))
|
||||
ns.Elem().Field(i).Set(reflect.ValueOf(exampleValue(f.Type, t)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -286,17 +294,17 @@ func main() {
|
||||
ft := m.Func.Type()
|
||||
for j := 2; j < ft.NumIn(); j++ {
|
||||
inp := ft.In(j)
|
||||
args = append(args, exampleValue(inp))
|
||||
args = append(args, exampleValue(inp, nil))
|
||||
}
|
||||
|
||||
v, err := json.Marshal(args)
|
||||
v, err := json.MarshalIndent(args, "", " ")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
outv := exampleValue(ft.Out(0))
|
||||
outv := exampleValue(ft.Out(0), nil)
|
||||
|
||||
ov, err := json.Marshal(outv)
|
||||
ov, err := json.MarshalIndent(outv, "", " ")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -318,6 +326,18 @@ func main() {
|
||||
return groupslice[i].GroupName < groupslice[j].GroupName
|
||||
})
|
||||
|
||||
fmt.Printf("# Groups\n")
|
||||
|
||||
for _, g := range groupslice {
|
||||
fmt.Printf("* [%s](#%s)\n", g.GroupName, g.GroupName)
|
||||
for _, method := range g.Methods {
|
||||
fmt.Printf(" * [%s](#%s)\n", method.Name, method.Name)
|
||||
}
|
||||
}
|
||||
|
||||
permStruct := reflect.TypeOf(apistruct.FullNodeStruct{}.Internal)
|
||||
commonPermStruct := reflect.TypeOf(apistruct.CommonStruct{}.Internal)
|
||||
|
||||
for _, g := range groupslice {
|
||||
g := g
|
||||
fmt.Printf("## %s\n", g.GroupName)
|
||||
@ -331,8 +351,29 @@ func main() {
|
||||
fmt.Printf("### %s\n", m.Name)
|
||||
fmt.Printf("%s\n\n", m.Comment)
|
||||
|
||||
fmt.Printf("Inputs: `%s`\n\n", m.InputExample)
|
||||
fmt.Printf("Response: `%s`\n\n", m.ResponseExample)
|
||||
meth, ok := permStruct.FieldByName(m.Name)
|
||||
if !ok {
|
||||
meth, ok = commonPermStruct.FieldByName(m.Name)
|
||||
if !ok {
|
||||
panic("no perms for method: " + m.Name)
|
||||
}
|
||||
}
|
||||
|
||||
perms := meth.Tag.Get("perm")
|
||||
|
||||
fmt.Printf("Perms: %s\n\n", perms)
|
||||
|
||||
if strings.Count(m.InputExample, "\n") > 0 {
|
||||
fmt.Printf("Inputs:\n```json\n%s\n```\n\n", m.InputExample)
|
||||
} else {
|
||||
fmt.Printf("Inputs: `%s`\n\n", m.InputExample)
|
||||
}
|
||||
|
||||
if strings.Count(m.ResponseExample, "\n") > 0 {
|
||||
fmt.Printf("Response:\n```json\n%s\n```\n\n", m.ResponseExample)
|
||||
} else {
|
||||
fmt.Printf("Response: `%s`\n\n", m.ResponseExample)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
99
api/test/ccupgrade.go
Normal file
99
api/test/ccupgrade.go
Normal file
@ -0,0 +1,99 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/impl"
|
||||
)
|
||||
|
||||
func TestCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, oneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
addrinfo, err := client.NetAddrsListen(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := miner.NetConnect(ctx, addrinfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
|
||||
mine := int64(1)
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
for atomic.LoadInt64(&mine) == 1 {
|
||||
time.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, func(bool, error) {}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
maddr, err := miner.ActorAddress(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
CC := abi.SectorNumber(GenesisPreseals + 1)
|
||||
Upgraded := CC + 1
|
||||
|
||||
pledgeSectors(t, ctx, miner, 1, nil)
|
||||
|
||||
sl, err := miner.SectorsList(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(sl) != 1 {
|
||||
t.Fatal("expected 1 sector")
|
||||
}
|
||||
|
||||
if sl[0] != CC {
|
||||
t.Fatal("bad")
|
||||
}
|
||||
|
||||
{
|
||||
si, err := client.StateSectorGetInfo(ctx, maddr, CC, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
require.Less(t, 50000, int(si.Expiration))
|
||||
}
|
||||
|
||||
if err := miner.SectorMarkForUpgrade(ctx, sl[0]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
makeDeal(t, ctx, 6, client, miner, false, false)
|
||||
|
||||
// Validate upgrade
|
||||
|
||||
{
|
||||
exp, err := client.StateSectorExpiration(ctx, maddr, CC, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
require.Greater(t, 50000, int(exp.OnTime))
|
||||
}
|
||||
{
|
||||
exp, err := client.StateSectorExpiration(ctx, maddr, Upgraded, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
require.Less(t, 50000, int(exp.OnTime))
|
||||
}
|
||||
|
||||
fmt.Println("shutting down mining")
|
||||
atomic.AddInt64(&mine, -1)
|
||||
<-done
|
||||
}
|
@ -8,11 +8,13 @@ import (
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
files "github.com/ipfs/go-ipfs-files"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/ipld/go-car"
|
||||
@ -20,6 +22,7 @@ import (
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
sealing "github.com/filecoin-project/storage-fsm"
|
||||
dag "github.com/ipfs/go-merkledag"
|
||||
dstest "github.com/ipfs/go-merkledag/test"
|
||||
unixfile "github.com/ipfs/go-unixfs/file"
|
||||
@ -34,7 +37,7 @@ func init() {
|
||||
build.InsecurePoStValidation = true
|
||||
}
|
||||
|
||||
func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport bool) {
|
||||
func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport, fastRet bool) {
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
@ -52,21 +55,21 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
|
||||
mine := true
|
||||
mine := int64(1)
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
for mine {
|
||||
for atomic.LoadInt64(&mine) == 1 {
|
||||
time.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, func(bool) {}); err != nil {
|
||||
if err := sn[0].MineOne(ctx, func(bool, error) {}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
makeDeal(t, ctx, 6, client, miner, carExport)
|
||||
makeDeal(t, ctx, 6, client, miner, carExport, fastRet)
|
||||
|
||||
mine = false
|
||||
atomic.AddInt64(&mine, -1)
|
||||
fmt.Println("shutting down mining")
|
||||
<-done
|
||||
}
|
||||
@ -89,28 +92,28 @@ func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
|
||||
mine := true
|
||||
mine := int64(1)
|
||||
done := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer close(done)
|
||||
for mine {
|
||||
for atomic.LoadInt64(&mine) == 1 {
|
||||
time.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, func(bool) {}); err != nil {
|
||||
if err := sn[0].MineOne(ctx, func(bool, error) {}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
makeDeal(t, ctx, 6, client, miner, false)
|
||||
makeDeal(t, ctx, 7, client, miner, false)
|
||||
makeDeal(t, ctx, 6, client, miner, false, false)
|
||||
makeDeal(t, ctx, 7, client, miner, false, false)
|
||||
|
||||
mine = false
|
||||
atomic.AddInt64(&mine, -1)
|
||||
fmt.Println("shutting down mining")
|
||||
<-done
|
||||
}
|
||||
|
||||
func makeDeal(t *testing.T, ctx context.Context, rseed int, client *impl.FullNodeAPI, miner TestStorageNode, carExport bool) {
|
||||
func makeDeal(t *testing.T, ctx context.Context, rseed int, client *impl.FullNodeAPI, miner TestStorageNode, carExport, fastRet bool) {
|
||||
data := make([]byte, 1600)
|
||||
rand.New(rand.NewSource(int64(rseed))).Read(data)
|
||||
|
||||
@ -122,18 +125,20 @@ func makeDeal(t *testing.T, ctx context.Context, rseed int, client *impl.FullNod
|
||||
|
||||
fmt.Println("FILE CID: ", fcid)
|
||||
|
||||
deal := startDeal(t, ctx, miner, client, fcid)
|
||||
deal := startDeal(t, ctx, miner, client, fcid, fastRet)
|
||||
|
||||
// TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this
|
||||
time.Sleep(time.Second)
|
||||
waitDealSealed(t, ctx, client, deal)
|
||||
waitDealSealed(t, ctx, miner, client, deal)
|
||||
|
||||
// Retrieval
|
||||
info, err := client.ClientGetDealInfo(ctx, *deal)
|
||||
require.NoError(t, err)
|
||||
|
||||
testRetrieval(t, ctx, err, client, fcid, carExport, data)
|
||||
testRetrieval(t, ctx, err, client, fcid, &info.PieceCID, carExport, data)
|
||||
}
|
||||
|
||||
func startDeal(t *testing.T, ctx context.Context, miner TestStorageNode, client *impl.FullNodeAPI, fcid cid.Cid) *cid.Cid {
|
||||
func startDeal(t *testing.T, ctx context.Context, miner TestStorageNode, client *impl.FullNodeAPI, fcid cid.Cid, fastRet bool) *cid.Cid {
|
||||
maddr, err := miner.ActorAddress(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -149,6 +154,7 @@ func startDeal(t *testing.T, ctx context.Context, miner TestStorageNode, client
|
||||
Miner: maddr,
|
||||
EpochPrice: types.NewInt(1000000),
|
||||
MinBlocksDuration: 100,
|
||||
FastRetrieval: fastRet,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
@ -156,7 +162,7 @@ func startDeal(t *testing.T, ctx context.Context, miner TestStorageNode, client
|
||||
return deal
|
||||
}
|
||||
|
||||
func waitDealSealed(t *testing.T, ctx context.Context, client *impl.FullNodeAPI, deal *cid.Cid) {
|
||||
func waitDealSealed(t *testing.T, ctx context.Context, miner TestStorageNode, client *impl.FullNodeAPI, deal *cid.Cid) {
|
||||
loop:
|
||||
for {
|
||||
di, err := client.ClientGetDealInfo(ctx, *deal)
|
||||
@ -164,6 +170,8 @@ loop:
|
||||
t.Fatal(err)
|
||||
}
|
||||
switch di.State {
|
||||
case storagemarket.StorageDealSealing:
|
||||
startSealingWaiting(t, ctx, miner)
|
||||
case storagemarket.StorageDealProposalRejected:
|
||||
t.Fatal("deal rejected")
|
||||
case storagemarket.StorageDealFailing:
|
||||
@ -179,8 +187,23 @@ loop:
|
||||
}
|
||||
}
|
||||
|
||||
func testRetrieval(t *testing.T, ctx context.Context, err error, client *impl.FullNodeAPI, fcid cid.Cid, carExport bool, data []byte) {
|
||||
offers, err := client.ClientFindData(ctx, fcid)
|
||||
func startSealingWaiting(t *testing.T, ctx context.Context, miner TestStorageNode) {
|
||||
snums, err := miner.SectorsList(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, snum := range snums {
|
||||
si, err := miner.SectorsStatus(ctx, snum)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Logf("Sector state: %s", si.State)
|
||||
if si.State == api.SectorState(sealing.WaitDeals) {
|
||||
require.NoError(t, miner.SectorStartSealing(ctx, snum))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testRetrieval(t *testing.T, ctx context.Context, err error, client *impl.FullNodeAPI, fcid cid.Cid, piece *cid.Cid, carExport bool, data []byte) {
|
||||
offers, err := client.ClientFindData(ctx, fcid, piece)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ func (ts *testSuite) testMining(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
<-newHeads
|
||||
|
||||
err = sn[0].MineOne(ctx, func(bool) {})
|
||||
err = sn[0].MineOne(ctx, func(bool, error) {})
|
||||
require.NoError(t, err)
|
||||
|
||||
<-newHeads
|
||||
@ -62,7 +62,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
<-newHeads
|
||||
|
||||
err = sn[0].MineOne(ctx, func(bool) {})
|
||||
err = sn[0].MineOne(ctx, func(bool, error) {})
|
||||
require.NoError(t, err)
|
||||
|
||||
<-newHeads
|
||||
@ -71,7 +71,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, abi.ChainEpoch(1), h2.Height())
|
||||
|
||||
err = sn[0].MineOne(ctx, func(bool) {})
|
||||
err = sn[0].MineOne(ctx, func(bool, error) {})
|
||||
require.NoError(t, err)
|
||||
|
||||
<-newHeads
|
||||
@ -89,7 +89,7 @@ func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExpo
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, []StorageMiner{
|
||||
{Full: 0, Preseal: PresealGenesis},
|
||||
{Full: 0, Preseal: 0}, // TODO: Add support for storage miners on non-first full node
|
||||
{Full: 0, Preseal: 0}, // TODO: Add support for miners on non-first full node
|
||||
})
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
provider := sn[1]
|
||||
@ -126,12 +126,13 @@ func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExpo
|
||||
minedTwo := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
doneMinedTwo := false
|
||||
defer close(done)
|
||||
|
||||
prevExpect := 0
|
||||
for atomic.LoadInt32(&mine) != 0 {
|
||||
wait := make(chan int, 2)
|
||||
mdone := func(mined bool) {
|
||||
mdone := func(mined bool, err error) {
|
||||
go func() {
|
||||
n := 0
|
||||
if mined {
|
||||
@ -153,6 +154,10 @@ func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExpo
|
||||
expect += <-wait
|
||||
|
||||
time.Sleep(blocktime)
|
||||
if expect == 0 {
|
||||
// null block
|
||||
continue
|
||||
}
|
||||
|
||||
for {
|
||||
n := 0
|
||||
@ -175,21 +180,21 @@ func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExpo
|
||||
time.Sleep(blocktime)
|
||||
}
|
||||
|
||||
if prevExpect == 2 && expect == 2 && minedTwo != nil {
|
||||
if prevExpect == 2 && expect == 2 && !doneMinedTwo {
|
||||
close(minedTwo)
|
||||
minedTwo = nil
|
||||
doneMinedTwo = true
|
||||
}
|
||||
|
||||
prevExpect = expect
|
||||
}
|
||||
}()
|
||||
|
||||
deal := startDeal(t, ctx, provider, client, fcid)
|
||||
deal := startDeal(t, ctx, provider, client, fcid, false)
|
||||
|
||||
// TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this
|
||||
time.Sleep(time.Second)
|
||||
|
||||
waitDealSealed(t, ctx, client, deal)
|
||||
waitDealSealed(t, ctx, provider, client, deal)
|
||||
|
||||
<-minedTwo
|
||||
|
||||
|
@ -18,7 +18,7 @@ type TestNode struct {
|
||||
type TestStorageNode struct {
|
||||
api.StorageMiner
|
||||
|
||||
MineOne func(context.Context, func(bool)) error
|
||||
MineOne func(context.Context, func(bool, error)) error
|
||||
}
|
||||
|
||||
var PresealGenesis = -1
|
||||
|
@ -3,7 +3,10 @@ package test
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
@ -35,30 +38,40 @@ func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSect
|
||||
if err := miner.NetConnect(ctx, addrinfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
build.Clock.Sleep(time.Second)
|
||||
|
||||
mine := true
|
||||
done := make(chan struct{})
|
||||
blockNotif := make(chan struct{}, 1)
|
||||
go func() {
|
||||
defer close(done)
|
||||
for mine {
|
||||
time.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, func(bool) {}); err != nil {
|
||||
build.Clock.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, func(bool, error) {
|
||||
select {
|
||||
case blockNotif <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
|
||||
}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
pledgeSectors(t, ctx, miner, nSectors)
|
||||
pledgeSectors(t, ctx, miner, nSectors, blockNotif)
|
||||
|
||||
mine = false
|
||||
<-done
|
||||
}
|
||||
|
||||
func pledgeSectors(t *testing.T, ctx context.Context, miner TestStorageNode, n int) {
|
||||
func pledgeSectors(t *testing.T, ctx context.Context, miner TestStorageNode, n int, blockNotif <-chan struct{}) {
|
||||
for i := 0; i < n; i++ {
|
||||
err := miner.PledgeSector(ctx)
|
||||
require.NoError(t, err)
|
||||
if i%3 == 0 && blockNotif != nil {
|
||||
<-blockNotif
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
@ -69,7 +82,7 @@ func pledgeSectors(t *testing.T, ctx context.Context, miner TestStorageNode, n i
|
||||
break
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
build.Clock.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
fmt.Printf("All sectors is fsm\n")
|
||||
@ -94,7 +107,7 @@ func pledgeSectors(t *testing.T, ctx context.Context, miner TestStorageNode, n i
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
build.Clock.Sleep(100 * time.Millisecond)
|
||||
fmt.Printf("WaitSeal: %d\n", len(s))
|
||||
}
|
||||
}
|
||||
@ -115,21 +128,21 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
||||
if err := miner.NetConnect(ctx, addrinfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
build.Clock.Sleep(time.Second)
|
||||
|
||||
mine := true
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
for mine {
|
||||
time.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, func(bool) {}); err != nil {
|
||||
build.Clock.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, func(bool, error) {}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
pledgeSectors(t, ctx, miner, nSectors)
|
||||
pledgeSectors(t, ctx, miner, nSectors, nil)
|
||||
|
||||
maddr, err := miner.ActorAddress(ctx)
|
||||
require.NoError(t, err)
|
||||
@ -150,7 +163,7 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
||||
if head.Height()%100 == 0 {
|
||||
fmt.Printf("@%d\n", head.Height())
|
||||
}
|
||||
time.Sleep(blocktime)
|
||||
build.Clock.Sleep(blocktime)
|
||||
}
|
||||
|
||||
p, err := client.StateMinerPower(ctx, maddr, types.EmptyTSK)
|
||||
|
@ -50,12 +50,12 @@ type MinerInfo struct {
|
||||
WorkerChangeEpoch abi.ChainEpoch
|
||||
PeerId peer.ID
|
||||
Multiaddrs []abi.Multiaddrs
|
||||
SealProofType abi.RegisteredProof
|
||||
SealProofType abi.RegisteredSealProof
|
||||
SectorSize abi.SectorSize
|
||||
WindowPoStPartitionSectors uint64
|
||||
}
|
||||
|
||||
func NewApiMinerInfo(info miner.MinerInfo) MinerInfo {
|
||||
func NewApiMinerInfo(info *miner.MinerInfo) MinerInfo {
|
||||
mi := MinerInfo{
|
||||
Owner: info.Owner,
|
||||
Worker: info.Worker,
|
||||
|
@ -13,6 +13,10 @@ import (
|
||||
)
|
||||
|
||||
func BuiltinBootstrap() ([]peer.AddrInfo, error) {
|
||||
if DisableBuiltinAssets {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var out []peer.AddrInfo
|
||||
|
||||
b := rice.MustFindBox("bootstrap")
|
||||
|
@ -1,12 +1,12 @@
|
||||
/dns4/bootstrap-0-sin.fil-test.net/tcp/1347/p2p/12D3KooWKNF7vNFEhnvB45E9mw2B5z6t419W3ziZPLdUDVnLLKGs
|
||||
/ip4/86.109.15.57/tcp/1347/p2p/12D3KooWKNF7vNFEhnvB45E9mw2B5z6t419W3ziZPLdUDVnLLKGs
|
||||
/dns4/bootstrap-0-dfw.fil-test.net/tcp/1347/p2p/12D3KooWECJTm7RUPyGfNbRwm6y2fK4wA7EB8rDJtWsq5AKi7iDr
|
||||
/ip4/139.178.84.45/tcp/1347/p2p/12D3KooWECJTm7RUPyGfNbRwm6y2fK4wA7EB8rDJtWsq5AKi7iDr
|
||||
/dns4/bootstrap-0-fra.fil-test.net/tcp/1347/p2p/12D3KooWC7MD6m7iNCuDsYtNr7xVtazihyVUizBbhmhEiyMAm9ym
|
||||
/ip4/136.144.49.17/tcp/1347/p2p/12D3KooWC7MD6m7iNCuDsYtNr7xVtazihyVUizBbhmhEiyMAm9ym
|
||||
/dns4/bootstrap-1-sin.fil-test.net/tcp/1347/p2p/12D3KooWD8eYqsKcEMFax6EbWN3rjA7qFsxCez2rmN8dWqkzgNaN
|
||||
/ip4/86.109.15.55/tcp/1347/p2p/12D3KooWD8eYqsKcEMFax6EbWN3rjA7qFsxCez2rmN8dWqkzgNaN
|
||||
/dns4/bootstrap-1-dfw.fil-test.net/tcp/1347/p2p/12D3KooWLB3RR8frLAmaK4ntHC2dwrAjyGzQgyUzWxAum1FxyyqD
|
||||
/ip4/139.178.84.41/tcp/1347/p2p/12D3KooWLB3RR8frLAmaK4ntHC2dwrAjyGzQgyUzWxAum1FxyyqD
|
||||
/dns4/bootstrap-1-fra.fil-test.net/tcp/1347/p2p/12D3KooWGPDJAw3HW4uVU3JEQBfFaZ1kdpg4HvvwRMVpUYbzhsLQ
|
||||
/ip4/136.144.49.131/tcp/1347/p2p/12D3KooWGPDJAw3HW4uVU3JEQBfFaZ1kdpg4HvvwRMVpUYbzhsLQ
|
||||
/dns4/bootstrap-0-sin.fil-test.net/tcp/1347/p2p/12D3KooWPdUquftaQvoQEtEdsRBAhwD6jopbF2oweVTzR59VbHEd
|
||||
/ip4/86.109.15.57/tcp/1347/p2p/12D3KooWPdUquftaQvoQEtEdsRBAhwD6jopbF2oweVTzR59VbHEd
|
||||
/dns4/bootstrap-0-dfw.fil-test.net/tcp/1347/p2p/12D3KooWQSCkHCzosEyrh8FgYfLejKgEPM5VB6qWzZE3yDAuXn8d
|
||||
/ip4/139.178.84.45/tcp/1347/p2p/12D3KooWQSCkHCzosEyrh8FgYfLejKgEPM5VB6qWzZE3yDAuXn8d
|
||||
/dns4/bootstrap-0-fra.fil-test.net/tcp/1347/p2p/12D3KooWEXN2eQmoyqnNjde9PBAQfQLHN67jcEdWU6JougWrgXJK
|
||||
/ip4/136.144.49.17/tcp/1347/p2p/12D3KooWEXN2eQmoyqnNjde9PBAQfQLHN67jcEdWU6JougWrgXJK
|
||||
/dns4/bootstrap-1-sin.fil-test.net/tcp/1347/p2p/12D3KooWLmJkZd33mJhjg5RrpJ6NFep9SNLXWc4uVngV4TXKwzYw
|
||||
/ip4/86.109.15.123/tcp/1347/p2p/12D3KooWLmJkZd33mJhjg5RrpJ6NFep9SNLXWc4uVngV4TXKwzYw
|
||||
/dns4/bootstrap-1-dfw.fil-test.net/tcp/1347/p2p/12D3KooWGXLHjiz6pTRu7x2pkgTVCoxcCiVxcNLpMnWcJ3JiNEy5
|
||||
/ip4/139.178.86.3/tcp/1347/p2p/12D3KooWGXLHjiz6pTRu7x2pkgTVCoxcCiVxcNLpMnWcJ3JiNEy5
|
||||
/dns4/bootstrap-1-fra.fil-test.net/tcp/1347/p2p/12D3KooW9szZmKttS9A1FafH3Zc2pxKwwmvCWCGKkRP4KmbhhC4R
|
||||
/ip4/136.144.49.131/tcp/1347/p2p/12D3KooW9szZmKttS9A1FafH3Zc2pxKwwmvCWCGKkRP4KmbhhC4R
|
||||
|
10
build/clock.go
Normal file
10
build/clock.go
Normal file
@ -0,0 +1,10 @@
|
||||
package build
|
||||
|
||||
import "github.com/raulk/clock"
|
||||
|
||||
// Clock is the global clock for the system. In standard builds,
|
||||
// we use a real-time clock, which maps to the `time` package.
|
||||
//
|
||||
// Tests that need control of time can replace this variable with
|
||||
// clock.NewMock().
|
||||
var Clock = clock.New()
|
15
build/flags.go
Normal file
15
build/flags.go
Normal file
@ -0,0 +1,15 @@
|
||||
package build
|
||||
|
||||
// DisableBuiltinAssets disables the resolution of go.rice boxes that store
|
||||
// built-in assets, such as proof parameters, bootstrap peers, genesis blocks,
|
||||
// etc.
|
||||
//
|
||||
// When this value is set to true, it is expected that the user will
|
||||
// provide any such configurations through the Lotus API itself.
|
||||
//
|
||||
// This is useful when you're using Lotus as a library, such as to orchestrate
|
||||
// test scenarios, or for other purposes where you don't need to use the
|
||||
// defaults shipped with the binary.
|
||||
//
|
||||
// For this flag to be effective, it must be enabled _before_ instantiating Lotus.
|
||||
var DisableBuiltinAssets = false
|
Binary file not shown.
@ -12,18 +12,17 @@ import (
|
||||
|
||||
func init() {
|
||||
power.ConsensusMinerMinPower = big.NewInt(2048)
|
||||
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
|
||||
abi.RegisteredProof_StackedDRG2KiBSeal: {},
|
||||
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||
}
|
||||
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
||||
|
||||
BuildType |= Build2k
|
||||
}
|
||||
|
||||
// Seconds
|
||||
const BlockDelay = 2
|
||||
const BlockDelaySecs = uint64(2)
|
||||
|
||||
const PropagationDelay = 3
|
||||
const PropagationDelaySecs = uint64(3)
|
||||
|
||||
// SlashablePowerDelay is the number of epochs after ElectionPeriodStart, after
|
||||
// which the miner is slashed
|
||||
|
38
build/params_shared_funcs.go
Normal file
38
build/params_shared_funcs.go
Normal file
@ -0,0 +1,38 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/protocol"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
)
|
||||
|
||||
func DefaultSectorSize() abi.SectorSize {
|
||||
szs := make([]abi.SectorSize, 0, len(miner.SupportedProofTypes))
|
||||
for spt := range miner.SupportedProofTypes {
|
||||
ss, err := spt.SectorSize()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
szs = append(szs, ss)
|
||||
}
|
||||
|
||||
sort.Slice(szs, func(i, j int) bool {
|
||||
return szs[i] < szs[j]
|
||||
})
|
||||
|
||||
return szs[0]
|
||||
}
|
||||
|
||||
// Core network constants
|
||||
|
||||
func BlocksTopic(netName dtypes.NetworkName) string { return "/fil/blocks/" + string(netName) }
|
||||
func MessagesTopic(netName dtypes.NetworkName) string { return "/fil/msgs/" + string(netName) }
|
||||
func DhtProtocolName(netName dtypes.NetworkName) protocol.ID {
|
||||
return protocol.ID("/fil/kad/" + string(netName))
|
||||
}
|
@ -1,10 +1,9 @@
|
||||
// +build !testground
|
||||
|
||||
package build
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"sort"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/protocol"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
@ -13,32 +12,6 @@ import (
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
)
|
||||
|
||||
func DefaultSectorSize() abi.SectorSize {
|
||||
szs := make([]abi.SectorSize, 0, len(miner.SupportedProofTypes))
|
||||
for spt := range miner.SupportedProofTypes {
|
||||
ss, err := spt.SectorSize()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
szs = append(szs, ss)
|
||||
}
|
||||
|
||||
sort.Slice(szs, func(i, j int) bool {
|
||||
return szs[i] < szs[j]
|
||||
})
|
||||
|
||||
return szs[0]
|
||||
}
|
||||
|
||||
// Core network constants
|
||||
|
||||
func BlocksTopic(netName dtypes.NetworkName) string { return "/fil/blocks/" + string(netName) }
|
||||
func MessagesTopic(netName dtypes.NetworkName) string { return "/fil/msgs/" + string(netName) }
|
||||
func DhtProtocolName(netName dtypes.NetworkName) protocol.ID {
|
||||
return protocol.ID("/fil/kad/" + string(netName))
|
||||
}
|
||||
|
||||
// /////
|
||||
// Storage
|
||||
|
||||
@ -48,8 +21,7 @@ const UnixfsLinksPerLevel = 1024
|
||||
// /////
|
||||
// Consensus / Network
|
||||
|
||||
// Seconds
|
||||
const AllowableClockDrift = 1
|
||||
const AllowableClockDriftSecs = uint64(1)
|
||||
|
||||
// Epochs
|
||||
const ForkLengthThreshold = Finality
|
||||
@ -58,13 +30,13 @@ const ForkLengthThreshold = Finality
|
||||
var BlocksPerEpoch = uint64(builtin.ExpectedLeadersPerEpoch)
|
||||
|
||||
// Epochs
|
||||
const Finality = miner.ChainFinalityish
|
||||
const MessageConfidence = 5
|
||||
const Finality = miner.ChainFinality
|
||||
const MessageConfidence = uint64(5)
|
||||
|
||||
// constants for Weight calculation
|
||||
// The ratio of weight contributed by short-term vs long-term factors in a given round
|
||||
const WRatioNum = int64(1)
|
||||
const WRatioDen = 2
|
||||
const WRatioDen = uint64(2)
|
||||
|
||||
// /////
|
||||
// Proofs
|
||||
@ -82,25 +54,25 @@ const MaxSealLookback = SealRandomnessLookbackLimit + 2000 // TODO: Get from spe
|
||||
// Mining
|
||||
|
||||
// Epochs
|
||||
const TicketRandomnessLookback = 1
|
||||
const TicketRandomnessLookback = abi.ChainEpoch(1)
|
||||
|
||||
const WinningPoStSectorSetLookback = 10
|
||||
const WinningPoStSectorSetLookback = abi.ChainEpoch(10)
|
||||
|
||||
// /////
|
||||
// Devnet settings
|
||||
|
||||
const TotalFilecoin = 2_000_000_000
|
||||
const MiningRewardTotal = 1_400_000_000
|
||||
const TotalFilecoin = uint64(2_000_000_000)
|
||||
const MiningRewardTotal = uint64(1_900_000_000)
|
||||
|
||||
const FilecoinPrecision = 1_000_000_000_000_000_000
|
||||
const FilecoinPrecision = uint64(1_000_000_000_000_000_000)
|
||||
|
||||
var InitialRewardBalance *big.Int
|
||||
|
||||
// TODO: Move other important consts here
|
||||
|
||||
func init() {
|
||||
InitialRewardBalance = big.NewInt(MiningRewardTotal)
|
||||
InitialRewardBalance = InitialRewardBalance.Mul(InitialRewardBalance, big.NewInt(FilecoinPrecision))
|
||||
InitialRewardBalance = big.NewInt(int64(MiningRewardTotal))
|
||||
InitialRewardBalance = InitialRewardBalance.Mul(InitialRewardBalance, big.NewInt(int64(FilecoinPrecision)))
|
||||
}
|
||||
|
||||
// Sync
|
||||
@ -119,6 +91,13 @@ const VerifSigCacheSize = 32000
|
||||
|
||||
// TODO: If this is gonna stay, it should move to specs-actors
|
||||
const BlockMessageLimit = 512
|
||||
const BlockGasLimit = 100_000_000_000
|
||||
const BlockGasLimit = 7_500_000_000
|
||||
|
||||
var DrandChain = `{"public_key":"922a2e93828ff83345bae533f5172669a26c02dc76d6bf59c80892e12ab1455c229211886f35bb56af6d5bea981024df","period":25,"genesis_time":1590445175,"hash":"138a324aa6540f93d0dad002aa89454b1bec2b6e948682cde6bd4db40f4b7c9b"}`
|
||||
var DrandConfig = dtypes.DrandConfig{
|
||||
Servers: []string{
|
||||
"https://pl-eu.testnet.drand.sh",
|
||||
"https://pl-us.testnet.drand.sh",
|
||||
"https://pl-sin.testnet.drand.sh",
|
||||
},
|
||||
ChainInfoJSON: `{"public_key":"922a2e93828ff83345bae533f5172669a26c02dc76d6bf59c80892e12ab1455c229211886f35bb56af6d5bea981024df","period":25,"genesis_time":1590445175,"hash":"84b2234fb34e835dccd048255d7ad3194b81af7d978c3bf157e3469592ae4e02","groupHash":"4dd408e5fdff9323c76a9b6f087ba8fdc5a6da907bd9217d9d10f2287d081957"}`,
|
||||
}
|
73
build/params_testground.go
Normal file
73
build/params_testground.go
Normal file
@ -0,0 +1,73 @@
|
||||
// +build testground
|
||||
|
||||
// This file makes hardcoded parameters (const) configurable as vars.
|
||||
//
|
||||
// Its purpose is to unlock various degrees of flexibility and parametrization
|
||||
// when writing Testground plans for Lotus.
|
||||
//
|
||||
package build
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
)
|
||||
|
||||
var (
|
||||
UnixfsChunkSize = uint64(1 << 20)
|
||||
UnixfsLinksPerLevel = 1024
|
||||
|
||||
BlocksPerEpoch = uint64(builtin.ExpectedLeadersPerEpoch)
|
||||
BlockMessageLimit = 512
|
||||
BlockGasLimit = int64(100_000_000_000)
|
||||
BlockDelaySecs = uint64(builtin.EpochDurationSeconds)
|
||||
PropagationDelaySecs = uint64(6)
|
||||
|
||||
AllowableClockDriftSecs = uint64(1)
|
||||
|
||||
Finality = miner.ChainFinality
|
||||
ForkLengthThreshold = Finality
|
||||
|
||||
SlashablePowerDelay = 20
|
||||
InteractivePoRepConfidence = 6
|
||||
|
||||
MessageConfidence uint64 = 5
|
||||
|
||||
WRatioNum = int64(1)
|
||||
WRatioDen = uint64(2)
|
||||
|
||||
BadBlockCacheSize = 1 << 15
|
||||
BlsSignatureCacheSize = 40000
|
||||
VerifSigCacheSize = 32000
|
||||
|
||||
SealRandomnessLookback = Finality
|
||||
SealRandomnessLookbackLimit = SealRandomnessLookback + 2000
|
||||
MaxSealLookback = SealRandomnessLookbackLimit + 2000
|
||||
|
||||
TicketRandomnessLookback = abi.ChainEpoch(1)
|
||||
WinningPoStSectorSetLookback = abi.ChainEpoch(10)
|
||||
|
||||
TotalFilecoin uint64 = 2_000_000_000
|
||||
MiningRewardTotal uint64 = 1_400_000_000
|
||||
|
||||
FilecoinPrecision uint64 = 1_000_000_000_000_000_000
|
||||
|
||||
InitialRewardBalance = func() *big.Int {
|
||||
v := big.NewInt(int64(MiningRewardTotal))
|
||||
v = v.Mul(v, big.NewInt(int64(FilecoinPrecision)))
|
||||
return v
|
||||
}()
|
||||
|
||||
DrandConfig = dtypes.DrandConfig{
|
||||
Servers: []string{
|
||||
"https://pl-eu.testnet.drand.sh",
|
||||
"https://pl-us.testnet.drand.sh",
|
||||
"https://pl-sin.testnet.drand.sh",
|
||||
},
|
||||
ChainInfoJSON: `{"public_key":"922a2e93828ff83345bae533f5172669a26c02dc76d6bf59c80892e12ab1455c229211886f35bb56af6d5bea981024df","period":25,"genesis_time":1590445175,"hash":"138a324aa6540f93d0dad002aa89454b1bec2b6e948682cde6bd4db40f4b7c9b"}`,
|
||||
}
|
||||
)
|
@ -1,5 +1,6 @@
|
||||
// +build !debug
|
||||
// +build !2k
|
||||
// +build !testground
|
||||
|
||||
package build
|
||||
|
||||
@ -12,15 +13,13 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
power.ConsensusMinerMinPower = big.NewInt(1024 << 20)
|
||||
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
|
||||
abi.RegisteredProof_StackedDRG512MiBSeal: {},
|
||||
abi.RegisteredProof_StackedDRG32GiBSeal: {},
|
||||
abi.RegisteredProof_StackedDRG64GiBSeal: {},
|
||||
power.ConsensusMinerMinPower = big.NewInt(1024 << 30)
|
||||
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg32GiBV1: {},
|
||||
abi.RegisteredSealProof_StackedDrg64GiBV1: {},
|
||||
}
|
||||
}
|
||||
|
||||
// Seconds
|
||||
const BlockDelay = builtin.EpochDurationSeconds
|
||||
const BlockDelaySecs = uint64(builtin.EpochDurationSeconds)
|
||||
|
||||
const PropagationDelay = 6
|
||||
const PropagationDelaySecs = uint64(6)
|
||||
|
@ -25,7 +25,7 @@ func buildType() string {
|
||||
}
|
||||
|
||||
// BuildVersion is the local build version, set by build system
|
||||
const BuildVersion = "0.4.0"
|
||||
const BuildVersion = "0.4.1"
|
||||
|
||||
func UserVersion() string {
|
||||
return BuildVersion + buildType() + CurrentCommit
|
||||
@ -53,7 +53,7 @@ func (ve Version) EqMajorMinor(v2 Version) bool {
|
||||
}
|
||||
|
||||
// APIVersion is a semver version of the rpc api exposed
|
||||
var APIVersion Version = newVer(0, 3, 0)
|
||||
var APIVersion Version = newVer(0, 8, 1)
|
||||
|
||||
//nolint:varcheck,deadcode
|
||||
const (
|
||||
|
@ -1,6 +1,8 @@
|
||||
package chain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/ipfs/go-cid"
|
||||
@ -10,6 +12,35 @@ type BadBlockCache struct {
|
||||
badBlocks *lru.ARCCache
|
||||
}
|
||||
|
||||
type BadBlockReason struct {
|
||||
Reason string
|
||||
TipSet []cid.Cid
|
||||
OriginalReason *BadBlockReason
|
||||
}
|
||||
|
||||
func NewBadBlockReason(cid []cid.Cid, format string, i ...interface{}) BadBlockReason {
|
||||
return BadBlockReason{
|
||||
TipSet: cid,
|
||||
Reason: fmt.Sprintf(format, i...),
|
||||
}
|
||||
}
|
||||
|
||||
func (bbr BadBlockReason) Linked(reason string, i ...interface{}) BadBlockReason {
|
||||
or := &bbr
|
||||
if bbr.OriginalReason != nil {
|
||||
or = bbr.OriginalReason
|
||||
}
|
||||
return BadBlockReason{Reason: fmt.Sprintf(reason, i...), OriginalReason: or}
|
||||
}
|
||||
|
||||
func (bbr BadBlockReason) String() string {
|
||||
res := bbr.Reason
|
||||
if bbr.OriginalReason != nil {
|
||||
res += " caused by: " + fmt.Sprintf("%s %s", bbr.OriginalReason.TipSet, bbr.OriginalReason.String())
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func NewBadBlockCache() *BadBlockCache {
|
||||
cache, err := lru.NewARC(build.BadBlockCacheSize)
|
||||
if err != nil {
|
||||
@ -21,15 +52,15 @@ func NewBadBlockCache() *BadBlockCache {
|
||||
}
|
||||
}
|
||||
|
||||
func (bts *BadBlockCache) Add(c cid.Cid, reason string) {
|
||||
bts.badBlocks.Add(c, reason)
|
||||
func (bts *BadBlockCache) Add(c cid.Cid, bbr BadBlockReason) {
|
||||
bts.badBlocks.Add(c, bbr)
|
||||
}
|
||||
|
||||
func (bts *BadBlockCache) Has(c cid.Cid) (string, bool) {
|
||||
func (bts *BadBlockCache) Has(c cid.Cid) (BadBlockReason, bool) {
|
||||
rval, ok := bts.badBlocks.Get(c)
|
||||
if !ok {
|
||||
return "", false
|
||||
return BadBlockReason{}, false
|
||||
}
|
||||
|
||||
return rval.(string), true
|
||||
return rval.(BadBlockReason), true
|
||||
}
|
||||
|
@ -2,12 +2,13 @@ package beacon
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
logging "github.com/ipfs/go-log"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
var log = logging.Logger("beacon")
|
||||
@ -17,6 +18,10 @@ type Response struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
// RandomBeacon represents a system that provides randomness to Lotus.
|
||||
// Other components interrogate the RandomBeacon to acquire randomness that's
|
||||
// valid for a specific chain epoch. Also to verify beacon entries that have
|
||||
// been posted on chain.
|
||||
type RandomBeacon interface {
|
||||
Entry(context.Context, uint64) <-chan Response
|
||||
VerifyEntry(types.BeaconEntry, types.BeaconEntry) error
|
||||
@ -48,7 +53,7 @@ func ValidateBlockValues(b RandomBeacon, h *types.BlockHeader, prevEntry types.B
|
||||
}
|
||||
|
||||
func BeaconEntriesForBlock(ctx context.Context, beacon RandomBeacon, round abi.ChainEpoch, prev types.BeaconEntry) ([]types.BeaconEntry, error) {
|
||||
start := time.Now()
|
||||
start := build.Clock.Now()
|
||||
|
||||
maxRound := beacon.MaxBeaconRoundForEpoch(round, prev)
|
||||
if maxRound == prev.Round {
|
||||
@ -77,7 +82,7 @@ func BeaconEntriesForBlock(ctx context.Context, beacon RandomBeacon, round abi.C
|
||||
}
|
||||
}
|
||||
|
||||
log.Debugw("fetching beacon entries", "took", time.Since(start), "numEntries", len(out))
|
||||
log.Debugw("fetching beacon entries", "took", build.Clock.Since(start), "numEntries", len(out))
|
||||
reverse(out)
|
||||
return out, nil
|
||||
}
|
||||
|
@ -8,8 +8,9 @@ import (
|
||||
|
||||
dchain "github.com/drand/drand/chain"
|
||||
dclient "github.com/drand/drand/client"
|
||||
gclient "github.com/drand/drand/cmd/relay-gossip/client"
|
||||
hclient "github.com/drand/drand/client/http"
|
||||
dlog "github.com/drand/drand/log"
|
||||
gclient "github.com/drand/drand/lp2p/client"
|
||||
"github.com/drand/kyber"
|
||||
kzap "github.com/go-kit/kit/log/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
@ -18,31 +19,16 @@ import (
|
||||
logging "github.com/ipfs/go-log"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/beacon"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
)
|
||||
|
||||
var log = logging.Logger("drand")
|
||||
|
||||
var drandServers = []string{
|
||||
"https://pl-eu.testnet.drand.sh",
|
||||
"https://pl-us.testnet.drand.sh",
|
||||
"https://pl-sin.testnet.drand.sh",
|
||||
}
|
||||
|
||||
var drandChain *dchain.Info
|
||||
|
||||
func init() {
|
||||
|
||||
var err error
|
||||
drandChain, err = dchain.InfoFromJSON(bytes.NewReader([]byte(build.DrandChain)))
|
||||
if err != nil {
|
||||
panic("could not unmarshal chain info: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
type drandPeer struct {
|
||||
addr string
|
||||
tls bool
|
||||
@ -56,6 +42,13 @@ func (dp *drandPeer) IsTLS() bool {
|
||||
return dp.tls
|
||||
}
|
||||
|
||||
// DrandBeacon connects Lotus with a drand network in order to provide
|
||||
// randomness to the system in a way that's aligned with Filecoin rounds/epochs.
|
||||
//
|
||||
// We connect to drand peers via their public HTTP endpoints. The peers are
|
||||
// enumerated in the drandServers variable.
|
||||
//
|
||||
// The root trust for the Drand chain is configured from build.DrandChain.
|
||||
type DrandBeacon struct {
|
||||
client dclient.Client
|
||||
|
||||
@ -72,18 +65,34 @@ type DrandBeacon struct {
|
||||
localCache map[uint64]types.BeaconEntry
|
||||
}
|
||||
|
||||
func NewDrandBeacon(genesisTs, interval uint64, ps *pubsub.PubSub) (*DrandBeacon, error) {
|
||||
func NewDrandBeacon(genesisTs, interval uint64, ps *pubsub.PubSub, config dtypes.DrandConfig) (*DrandBeacon, error) {
|
||||
if genesisTs == 0 {
|
||||
panic("what are you doing this cant be zero")
|
||||
}
|
||||
|
||||
drandChain, err := dchain.InfoFromJSON(bytes.NewReader([]byte(config.ChainInfoJSON)))
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("unable to unmarshal drand chain info: %w", err)
|
||||
}
|
||||
|
||||
dlogger := dlog.NewKitLoggerFrom(kzap.NewZapSugarLogger(
|
||||
log.SugaredLogger.Desugar(), zapcore.InfoLevel))
|
||||
|
||||
var clients []dclient.Client
|
||||
for _, url := range config.Servers {
|
||||
hc, err := hclient.NewWithInfo(url, drandChain, nil)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("could not create http drand client: %w", err)
|
||||
}
|
||||
clients = append(clients, hc)
|
||||
|
||||
}
|
||||
|
||||
opts := []dclient.Option{
|
||||
dclient.WithChainInfo(drandChain),
|
||||
dclient.WithHTTPEndpoints(drandServers),
|
||||
dclient.WithCacheSize(1024),
|
||||
dclient.WithLogger(dlogger),
|
||||
dclient.WithAutoWatch(),
|
||||
}
|
||||
|
||||
if ps != nil {
|
||||
@ -92,19 +101,11 @@ func NewDrandBeacon(genesisTs, interval uint64, ps *pubsub.PubSub) (*DrandBeacon
|
||||
log.Info("drand beacon without pubsub")
|
||||
}
|
||||
|
||||
client, err := dclient.New(opts...)
|
||||
client, err := dclient.Wrap(clients, opts...)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("creating drand client")
|
||||
}
|
||||
|
||||
go func() {
|
||||
// Explicitly Watch until that is fixed in drand
|
||||
ch := client.Watch(context.Background())
|
||||
for range ch {
|
||||
}
|
||||
log.Error("dranch Watch bork")
|
||||
}()
|
||||
|
||||
db := &DrandBeacon{
|
||||
client: client,
|
||||
localCache: make(map[uint64]types.BeaconEntry),
|
||||
@ -131,7 +132,7 @@ func (db *DrandBeacon) Entry(ctx context.Context, round uint64) <-chan beacon.Re
|
||||
}
|
||||
|
||||
go func() {
|
||||
start := time.Now()
|
||||
start := build.Clock.Now()
|
||||
log.Infow("start fetching randomness", "round", round)
|
||||
resp, err := db.client.Get(ctx, round)
|
||||
|
||||
@ -142,7 +143,7 @@ func (db *DrandBeacon) Entry(ctx context.Context, round uint64) <-chan beacon.Re
|
||||
br.Entry.Round = resp.Round()
|
||||
br.Entry.Data = resp.Signature()
|
||||
}
|
||||
log.Infow("done fetching randomness", "round", round, "took", time.Since(start))
|
||||
log.Infow("done fetching randomness", "round", round, "took", build.Clock.Since(start))
|
||||
out <- br
|
||||
close(out)
|
||||
}()
|
||||
|
@ -5,12 +5,15 @@ import (
|
||||
"testing"
|
||||
|
||||
dchain "github.com/drand/drand/chain"
|
||||
dclient "github.com/drand/drand/client"
|
||||
hclient "github.com/drand/drand/client/http"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
)
|
||||
|
||||
func TestPrintGroupInfo(t *testing.T) {
|
||||
c, err := dclient.NewHTTPClient(drandServers[0], nil, nil)
|
||||
server := build.DrandConfig.Servers[0]
|
||||
c, err := hclient.New(server, nil, nil)
|
||||
assert.NoError(t, err)
|
||||
cg := c.(interface {
|
||||
FetchChainInfo(groupHash []byte) (*dchain.Info, error)
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/hashicorp/golang-lru"
|
||||
peer "github.com/libp2p/go-libp2p-core/peer"
|
||||
@ -37,14 +38,14 @@ func (brt *blockReceiptTracker) Add(p peer.ID, ts *types.TipSet) {
|
||||
if !ok {
|
||||
pset := &peerSet{
|
||||
peers: map[peer.ID]time.Time{
|
||||
p: time.Now(),
|
||||
p: build.Clock.Now(),
|
||||
},
|
||||
}
|
||||
brt.cache.Add(ts.Key(), pset)
|
||||
return
|
||||
}
|
||||
|
||||
val.(*peerSet).peers[p] = time.Now()
|
||||
val.(*peerSet).peers[p] = build.Clock.Now()
|
||||
}
|
||||
|
||||
func (brt *blockReceiptTracker) GetPeers(ts *types.TipSet) []peer.ID {
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
cborutil "github.com/filecoin-project/go-cbor-util"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
@ -27,6 +28,24 @@ const BlockSyncProtocolID = "/fil/sync/blk/0.0.1"
|
||||
|
||||
const BlockSyncMaxRequestLength = 800
|
||||
|
||||
// BlockSyncService is the component that services BlockSync requests from
|
||||
// peers.
|
||||
//
|
||||
// BlockSync is the basic chain synchronization protocol of Filecoin. BlockSync
|
||||
// is an RPC-oriented protocol, with a single operation to request blocks.
|
||||
//
|
||||
// A request contains a start anchor block (referred to with a CID), and a
|
||||
// amount of blocks requested beyond the anchor (including the anchor itself).
|
||||
//
|
||||
// A client can also pass options, encoded as a 64-bit bitfield. Lotus supports
|
||||
// two options at the moment:
|
||||
//
|
||||
// - include block contents
|
||||
// - include block messages
|
||||
//
|
||||
// The response will include a status code, an optional message, and the
|
||||
// response payload in case of success. The payload is a slice of serialized
|
||||
// tipsets.
|
||||
type BlockSyncService struct {
|
||||
cs *store.ChainStore
|
||||
}
|
||||
@ -107,7 +126,7 @@ func (bss *BlockSyncService) HandleStream(s inet.Stream) {
|
||||
}
|
||||
|
||||
writeDeadline := 60 * time.Second
|
||||
_ = s.SetDeadline(time.Now().Add(writeDeadline))
|
||||
_ = s.SetDeadline(time.Now().Add(writeDeadline)) // always use real time for socket/stream deadlines.
|
||||
if err := cborutil.WriteCborRPC(s, resp); err != nil {
|
||||
log.Warnw("failed to write back response for handle stream", "err", err, "peer", s.Conn().RemotePeer())
|
||||
return
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
cborutil "github.com/filecoin-project/go-cbor-util"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
incrt "github.com/filecoin-project/lotus/lib/increadtimeout"
|
||||
@ -64,6 +65,11 @@ func (bs *BlockSync) processStatus(req *BlockSyncRequest, res *BlockSyncResponse
|
||||
}
|
||||
}
|
||||
|
||||
// GetBlocks fetches count blocks from the network, from the provided tipset
|
||||
// *backwards*, returning as many tipsets as count.
|
||||
//
|
||||
// {hint/usage}: This is used by the Syncer during normal chain syncing and when
|
||||
// resolving forks.
|
||||
func (bs *BlockSync) GetBlocks(ctx context.Context, tsk types.TipSetKey, count int) ([]*types.TipSet, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "bsync.GetBlocks")
|
||||
defer span.End()
|
||||
@ -80,11 +86,13 @@ func (bs *BlockSync) GetBlocks(ctx context.Context, tsk types.TipSetKey, count i
|
||||
Options: BSOptBlocks,
|
||||
}
|
||||
|
||||
// this peerset is sorted by latency and failure counting.
|
||||
peers := bs.getPeers()
|
||||
|
||||
// randomize the first few peers so we don't always pick the same peer
|
||||
shufflePrefix(peers)
|
||||
|
||||
start := time.Now()
|
||||
start := build.Clock.Now()
|
||||
var oerr error
|
||||
|
||||
for _, p := range peers {
|
||||
@ -110,7 +118,7 @@ func (bs *BlockSync) GetBlocks(ctx context.Context, tsk types.TipSetKey, count i
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("success response from peer failed to process: %w", err)
|
||||
}
|
||||
bs.syncPeers.logGlobalSuccess(time.Since(start))
|
||||
bs.syncPeers.logGlobalSuccess(build.Clock.Since(start))
|
||||
bs.host.ConnManager().TagPeer(p, "bsync", 25)
|
||||
return resp, nil
|
||||
}
|
||||
@ -190,7 +198,7 @@ func (bs *BlockSync) GetChainMessages(ctx context.Context, h *types.TipSet, coun
|
||||
}
|
||||
|
||||
var err error
|
||||
start := time.Now()
|
||||
start := build.Clock.Now()
|
||||
|
||||
for _, p := range peers {
|
||||
res, rerr := bs.sendRequestToPeer(ctx, p, req)
|
||||
@ -201,7 +209,7 @@ func (bs *BlockSync) GetChainMessages(ctx context.Context, h *types.TipSet, coun
|
||||
}
|
||||
|
||||
if res.Status == StatusOK {
|
||||
bs.syncPeers.logGlobalSuccess(time.Since(start))
|
||||
bs.syncPeers.logGlobalSuccess(build.Clock.Since(start))
|
||||
return res.Chain, nil
|
||||
}
|
||||
|
||||
@ -277,17 +285,17 @@ func (bs *BlockSync) fetchBlocksBlockSync(ctx context.Context, p peer.ID, req *B
|
||||
ctx, span := trace.StartSpan(ctx, "blockSyncFetch")
|
||||
defer span.End()
|
||||
|
||||
start := time.Now()
|
||||
start := build.Clock.Now()
|
||||
s, err := bs.host.NewStream(inet.WithNoDial(ctx, "should already have connection"), p, BlockSyncProtocolID)
|
||||
if err != nil {
|
||||
bs.RemovePeer(p)
|
||||
return nil, xerrors.Errorf("failed to open stream to peer: %w", err)
|
||||
}
|
||||
_ = s.SetWriteDeadline(time.Now().Add(5 * time.Second))
|
||||
_ = s.SetWriteDeadline(time.Now().Add(5 * time.Second)) // always use real time for socket/stream deadlines.
|
||||
|
||||
if err := cborutil.WriteCborRPC(s, req); err != nil {
|
||||
_ = s.SetWriteDeadline(time.Time{})
|
||||
bs.syncPeers.logFailure(p, time.Since(start))
|
||||
bs.syncPeers.logFailure(p, build.Clock.Since(start))
|
||||
return nil, err
|
||||
}
|
||||
_ = s.SetWriteDeadline(time.Time{})
|
||||
@ -295,7 +303,7 @@ func (bs *BlockSync) fetchBlocksBlockSync(ctx context.Context, p peer.ID, req *B
|
||||
var res BlockSyncResponse
|
||||
r := incrt.New(s, 50<<10, 5*time.Second)
|
||||
if err := cborutil.ReadCborRPC(bufio.NewReader(r), &res); err != nil {
|
||||
bs.syncPeers.logFailure(p, time.Since(start))
|
||||
bs.syncPeers.logFailure(p, build.Clock.Since(start))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -307,7 +315,7 @@ func (bs *BlockSync) fetchBlocksBlockSync(ctx context.Context, p peer.ID, req *B
|
||||
)
|
||||
}
|
||||
|
||||
bs.syncPeers.logSuccess(p, time.Since(start))
|
||||
bs.syncPeers.logSuccess(p, build.Clock.Since(start))
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
@ -356,6 +364,7 @@ func (bs *BlockSync) RemovePeer(p peer.ID) {
|
||||
bs.syncPeers.removePeer(p)
|
||||
}
|
||||
|
||||
// getPeers returns a preference-sorted set of peers to query.
|
||||
func (bs *BlockSync) getPeers() []peer.ID {
|
||||
return bs.syncPeers.prefSortedPeers()
|
||||
}
|
||||
@ -467,7 +476,7 @@ func (bpt *bsPeerTracker) addPeer(p peer.ID) {
|
||||
return
|
||||
}
|
||||
bpt.peers[p] = &peerStats{
|
||||
firstSeen: time.Now(),
|
||||
firstSeen: build.Clock.Now(),
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/ipfs/go-cid"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
xerrors "golang.org/x/xerrors"
|
||||
)
|
||||
@ -57,6 +57,8 @@ func (t *BlockSyncRequest) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *BlockSyncRequest) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = BlockSyncRequest{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@ -179,6 +181,8 @@ func (t *BlockSyncResponse) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *BlockSyncResponse) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = BlockSyncResponse{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@ -354,6 +358,8 @@ func (t *BSTipSet) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *BSTipSet) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = BSTipSet{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
|
@ -51,7 +51,7 @@ type Events struct {
|
||||
readyOnce sync.Once
|
||||
|
||||
heightEvents
|
||||
calledEvents
|
||||
*hcEvents
|
||||
}
|
||||
|
||||
func NewEvents(ctx context.Context, api eventAPI) *Events {
|
||||
@ -74,18 +74,7 @@ func NewEvents(ctx context.Context, api eventAPI) *Events {
|
||||
htHeights: map[abi.ChainEpoch][]uint64{},
|
||||
},
|
||||
|
||||
calledEvents: calledEvents{
|
||||
cs: api,
|
||||
tsc: tsc,
|
||||
ctx: ctx,
|
||||
gcConfidence: uint64(gcConfidence),
|
||||
|
||||
confQueue: map[triggerH]map[msgH][]*queuedEvent{},
|
||||
revertQueue: map[msgH][]triggerH{},
|
||||
triggers: map[triggerID]*callHandler{},
|
||||
matchers: map[triggerID][]MatchFunc{},
|
||||
timeouts: map[abi.ChainEpoch]map[triggerID]int{},
|
||||
},
|
||||
hcEvents: newHCEvents(ctx, api, tsc, uint64(gcConfidence)),
|
||||
}
|
||||
|
||||
e.ready.Add(1)
|
||||
@ -110,7 +99,7 @@ func (e *Events) listenHeadChanges(ctx context.Context) {
|
||||
log.Warnf("not restarting listenHeadChanges: context error: %s", ctx.Err())
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
build.Clock.Sleep(time.Second)
|
||||
log.Info("restarting listenHeadChanges")
|
||||
}
|
||||
}
|
||||
@ -143,7 +132,7 @@ func (e *Events) listenHeadChangesOnce(ctx context.Context) error {
|
||||
}
|
||||
|
||||
e.readyOnce.Do(func() {
|
||||
e.at = cur[0].Val.Height()
|
||||
e.lastTs = cur[0].Val
|
||||
|
||||
e.ready.Done()
|
||||
})
|
||||
@ -186,5 +175,5 @@ func (e *Events) headChange(rev, app []*types.TipSet) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return e.headChangeCalled(rev, app)
|
||||
return e.processHeadChangeEvent(rev, app)
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
)
|
||||
|
||||
const NoTimeout = math.MaxInt64
|
||||
const NoHeight = abi.ChainEpoch(-1)
|
||||
|
||||
type triggerID = uint64
|
||||
|
||||
@ -23,54 +24,60 @@ type msgH = abi.ChainEpoch
|
||||
// message (msgH+confidence)
|
||||
type triggerH = abi.ChainEpoch
|
||||
|
||||
// CalledHandler arguments:
|
||||
// `ts` is the tipset, in which the `msg` is included.
|
||||
type eventData interface{}
|
||||
|
||||
// EventHandler arguments:
|
||||
// `prevTs` is the previous tipset, eg the "from" tipset for a state change.
|
||||
// `ts` is the event tipset, eg the tipset in which the `msg` is included.
|
||||
// `curH`-`ts.Height` = `confidence`
|
||||
type CalledHandler func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (more bool, err error)
|
||||
type EventHandler func(data eventData, prevTs, ts *types.TipSet, curH abi.ChainEpoch) (more bool, err error)
|
||||
|
||||
// CheckFunc is used for atomicity guarantees. If the condition the callbacks
|
||||
// wait for has already happened in tipset `ts`
|
||||
//
|
||||
// If `done` is true, timeout won't be triggered
|
||||
// If `more` is false, no messages will be sent to CalledHandler (RevertHandler
|
||||
// If `more` is false, no messages will be sent to EventHandler (RevertHandler
|
||||
// may still be called)
|
||||
type CheckFunc func(ts *types.TipSet) (done bool, more bool, err error)
|
||||
|
||||
type MatchFunc func(msg *types.Message) (bool, error)
|
||||
|
||||
type callHandler struct {
|
||||
// Keep track of information for an event handler
|
||||
type handlerInfo struct {
|
||||
confidence int
|
||||
timeout abi.ChainEpoch
|
||||
|
||||
disabled bool // TODO: GC after gcConfidence reached
|
||||
|
||||
handle CalledHandler
|
||||
handle EventHandler
|
||||
revert RevertHandler
|
||||
}
|
||||
|
||||
// When a change occurs, a queuedEvent is created and put into a queue
|
||||
// until the required confidence is reached
|
||||
type queuedEvent struct {
|
||||
trigger triggerID
|
||||
|
||||
h abi.ChainEpoch
|
||||
msg *types.Message
|
||||
prevH abi.ChainEpoch
|
||||
h abi.ChainEpoch
|
||||
data eventData
|
||||
|
||||
called bool
|
||||
}
|
||||
|
||||
type calledEvents struct {
|
||||
// Manages chain head change events, which may be forward (new tipset added to
|
||||
// chain) or backward (chain branch discarded in favour of heavier branch)
|
||||
type hcEvents struct {
|
||||
cs eventAPI
|
||||
tsc *tipSetCache
|
||||
ctx context.Context
|
||||
gcConfidence uint64
|
||||
|
||||
at abi.ChainEpoch
|
||||
lastTs *types.TipSet
|
||||
|
||||
lk sync.Mutex
|
||||
|
||||
ctr triggerID
|
||||
|
||||
triggers map[triggerID]*callHandler
|
||||
matchers map[triggerID][]MatchFunc
|
||||
triggers map[triggerID]*handlerInfo
|
||||
|
||||
// maps block heights to events
|
||||
// [triggerH][msgH][event]
|
||||
@ -81,27 +88,79 @@ type calledEvents struct {
|
||||
|
||||
// [timeoutH+confidence][triggerID]{calls}
|
||||
timeouts map[abi.ChainEpoch]map[triggerID]int
|
||||
|
||||
messageEvents
|
||||
watcherEvents
|
||||
}
|
||||
|
||||
func (e *calledEvents) headChangeCalled(rev, app []*types.TipSet) error {
|
||||
func newHCEvents(ctx context.Context, cs eventAPI, tsc *tipSetCache, gcConfidence uint64) *hcEvents {
|
||||
e := hcEvents{
|
||||
ctx: ctx,
|
||||
cs: cs,
|
||||
tsc: tsc,
|
||||
gcConfidence: gcConfidence,
|
||||
|
||||
confQueue: map[triggerH]map[msgH][]*queuedEvent{},
|
||||
revertQueue: map[msgH][]triggerH{},
|
||||
triggers: map[triggerID]*handlerInfo{},
|
||||
timeouts: map[abi.ChainEpoch]map[triggerID]int{},
|
||||
}
|
||||
|
||||
e.messageEvents = newMessageEvents(ctx, &e, cs)
|
||||
e.watcherEvents = newWatcherEvents(ctx, &e, cs)
|
||||
|
||||
return &e
|
||||
}
|
||||
|
||||
// Called when there is a change to the head with tipsets to be
|
||||
// reverted / applied
|
||||
func (e *hcEvents) processHeadChangeEvent(rev, app []*types.TipSet) error {
|
||||
e.lk.Lock()
|
||||
defer e.lk.Unlock()
|
||||
|
||||
for _, ts := range rev {
|
||||
e.handleReverts(ts)
|
||||
e.at = ts.Height()
|
||||
e.lastTs = ts
|
||||
}
|
||||
|
||||
for _, ts := range app {
|
||||
// called triggers
|
||||
e.checkNewCalls(ts)
|
||||
for ; e.at <= ts.Height(); e.at++ {
|
||||
e.applyWithConfidence(ts, e.at)
|
||||
// Check if the head change caused any state changes that we were
|
||||
// waiting for
|
||||
stateChanges := e.watcherEvents.checkStateChanges(e.lastTs, ts)
|
||||
|
||||
// Queue up calls until there have been enough blocks to reach
|
||||
// confidence on the state changes
|
||||
for tid, data := range stateChanges {
|
||||
e.queueForConfidence(tid, data, e.lastTs, ts)
|
||||
}
|
||||
|
||||
// Check if the head change included any new message calls
|
||||
newCalls, err := e.messageEvents.checkNewCalls(ts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Queue up calls until there have been enough blocks to reach
|
||||
// confidence on the message calls
|
||||
for tid, data := range newCalls {
|
||||
e.queueForConfidence(tid, data, nil, ts)
|
||||
}
|
||||
|
||||
for at := e.lastTs.Height(); at <= ts.Height(); at++ {
|
||||
// Apply any queued events and timeouts that were targeted at the
|
||||
// current chain height
|
||||
e.applyWithConfidence(ts, at)
|
||||
e.applyTimeouts(ts)
|
||||
}
|
||||
|
||||
// Update the latest known tipset
|
||||
e.lastTs = ts
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *calledEvents) handleReverts(ts *types.TipSet) {
|
||||
func (e *hcEvents) handleReverts(ts *types.TipSet) {
|
||||
reverts, ok := e.revertQueue[ts.Height()]
|
||||
if !ok {
|
||||
return // nothing to do
|
||||
@ -117,7 +176,7 @@ func (e *calledEvents) handleReverts(ts *types.TipSet) {
|
||||
trigger := e.triggers[event.trigger]
|
||||
|
||||
if err := trigger.revert(e.ctx, ts); err != nil {
|
||||
log.Errorf("reverting chain trigger (call %s.%d() @H %d, called @ %d) failed: %s", event.msg.To, event.msg.Method, ts.Height(), triggerH, err)
|
||||
log.Errorf("reverting chain trigger (@H %d, triggered @ %d) failed: %s", ts.Height(), triggerH, err)
|
||||
}
|
||||
}
|
||||
delete(e.confQueue[triggerH], ts.Height())
|
||||
@ -125,42 +184,15 @@ func (e *calledEvents) handleReverts(ts *types.TipSet) {
|
||||
delete(e.revertQueue, ts.Height())
|
||||
}
|
||||
|
||||
func (e *calledEvents) checkNewCalls(ts *types.TipSet) {
|
||||
pts, err := e.cs.ChainGetTipSet(e.ctx, ts.Parents()) // we actually care about messages in the parent tipset here
|
||||
if err != nil {
|
||||
log.Errorf("getting parent tipset in checkNewCalls: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
e.messagesForTs(pts, func(msg *types.Message) {
|
||||
// TODO: provide receipts
|
||||
|
||||
for tid, matchFns := range e.matchers {
|
||||
var matched bool
|
||||
for _, matchFn := range matchFns {
|
||||
ok, err := matchFn(msg)
|
||||
if err != nil {
|
||||
log.Errorf("event matcher failed: %s", err)
|
||||
continue
|
||||
}
|
||||
matched = ok
|
||||
|
||||
if matched {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if matched {
|
||||
e.queueForConfidence(tid, msg, ts)
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (e *calledEvents) queueForConfidence(trigID uint64, msg *types.Message, ts *types.TipSet) {
|
||||
// Queue up events until the chain has reached a height that reflects the
|
||||
// desired confidence
|
||||
func (e *hcEvents) queueForConfidence(trigID uint64, data eventData, prevTs, ts *types.TipSet) {
|
||||
trigger := e.triggers[trigID]
|
||||
|
||||
prevH := NoHeight
|
||||
if prevTs != nil {
|
||||
prevH = prevTs.Height()
|
||||
}
|
||||
appliedH := ts.Height()
|
||||
|
||||
triggerH := appliedH + abi.ChainEpoch(trigger.confidence)
|
||||
@ -173,17 +205,19 @@ func (e *calledEvents) queueForConfidence(trigID uint64, msg *types.Message, ts
|
||||
|
||||
byOrigH[appliedH] = append(byOrigH[appliedH], &queuedEvent{
|
||||
trigger: trigID,
|
||||
prevH: prevH,
|
||||
h: appliedH,
|
||||
msg: msg,
|
||||
data: data,
|
||||
})
|
||||
|
||||
e.revertQueue[appliedH] = append(e.revertQueue[appliedH], triggerH)
|
||||
}
|
||||
|
||||
func (e *calledEvents) applyWithConfidence(ts *types.TipSet, height abi.ChainEpoch) {
|
||||
// Apply any events that were waiting for this chain height for confidence
|
||||
func (e *hcEvents) applyWithConfidence(ts *types.TipSet, height abi.ChainEpoch) {
|
||||
byOrigH, ok := e.confQueue[height]
|
||||
if !ok {
|
||||
return // no triggers at thin height
|
||||
return // no triggers at this height
|
||||
}
|
||||
|
||||
for origH, events := range byOrigH {
|
||||
@ -202,15 +236,20 @@ func (e *calledEvents) applyWithConfidence(ts *types.TipSet, height abi.ChainEpo
|
||||
continue
|
||||
}
|
||||
|
||||
rec, err := e.cs.StateGetReceipt(e.ctx, event.msg.Cid(), ts.Key())
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
// Previous tipset - this is relevant for example in a state change
|
||||
// from one tipset to another
|
||||
var prevTs *types.TipSet
|
||||
if event.prevH != NoHeight {
|
||||
prevTs, err = e.tsc.get(event.prevH)
|
||||
if err != nil {
|
||||
log.Errorf("events: applyWithConfidence didn't find tipset for previous event; wanted %d; current %d", event.prevH, height)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
more, err := trigger.handle(event.msg, rec, triggerTs, height)
|
||||
more, err := trigger.handle(event.data, prevTs, triggerTs, height)
|
||||
if err != nil {
|
||||
log.Errorf("chain trigger (call %s.%d() @H %d, called @ %d) failed: %s", event.msg.To, event.msg.Method, origH, height, err)
|
||||
log.Errorf("chain trigger (@H %d, triggered @ %d) failed: %s", origH, height, err)
|
||||
continue // don't revert failed calls
|
||||
}
|
||||
|
||||
@ -226,7 +265,8 @@ func (e *calledEvents) applyWithConfidence(ts *types.TipSet, height abi.ChainEpo
|
||||
}
|
||||
}
|
||||
|
||||
func (e *calledEvents) applyTimeouts(ts *types.TipSet) {
|
||||
// Apply any timeouts that expire at this height
|
||||
func (e *hcEvents) applyTimeouts(ts *types.TipSet) {
|
||||
triggers, ok := e.timeouts[ts.Height()]
|
||||
if !ok {
|
||||
return // nothing to do
|
||||
@ -256,12 +296,229 @@ func (e *calledEvents) applyTimeouts(ts *types.TipSet) {
|
||||
}
|
||||
}
|
||||
|
||||
func (e *calledEvents) messagesForTs(ts *types.TipSet, consume func(*types.Message)) {
|
||||
// Listen for an event
|
||||
// - CheckFunc: immediately checks if the event already occurred
|
||||
// - EventHandler: called when the event has occurred, after confidence tipsets
|
||||
// - RevertHandler: called if the chain head changes causing the event to revert
|
||||
// - confidence: wait this many tipsets before calling EventHandler
|
||||
// - timeout: at this chain height, timeout on waiting for this event
|
||||
func (e *hcEvents) onHeadChanged(check CheckFunc, hnd EventHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch) (triggerID, error) {
|
||||
e.lk.Lock()
|
||||
defer e.lk.Unlock()
|
||||
|
||||
// Check if the event has already occurred
|
||||
ts := e.tsc.best()
|
||||
done, more, err := check(ts)
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("called check error (h: %d): %w", ts.Height(), err)
|
||||
}
|
||||
if done {
|
||||
timeout = NoTimeout
|
||||
}
|
||||
|
||||
// Create a trigger for the event
|
||||
id := e.ctr
|
||||
e.ctr++
|
||||
|
||||
e.triggers[id] = &handlerInfo{
|
||||
confidence: confidence,
|
||||
timeout: timeout + abi.ChainEpoch(confidence),
|
||||
|
||||
disabled: !more,
|
||||
|
||||
handle: hnd,
|
||||
revert: rev,
|
||||
}
|
||||
|
||||
// If there's a timeout, set up a timeout check at that height
|
||||
if timeout != NoTimeout {
|
||||
if e.timeouts[timeout+abi.ChainEpoch(confidence)] == nil {
|
||||
e.timeouts[timeout+abi.ChainEpoch(confidence)] = map[uint64]int{}
|
||||
}
|
||||
e.timeouts[timeout+abi.ChainEpoch(confidence)][id] = 0
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// headChangeAPI is used to allow the composed event APIs to call back to hcEvents
|
||||
// to listen for changes
|
||||
type headChangeAPI interface {
|
||||
onHeadChanged(check CheckFunc, hnd EventHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch) (triggerID, error)
|
||||
}
|
||||
|
||||
// watcherEvents watches for a state change
|
||||
type watcherEvents struct {
|
||||
ctx context.Context
|
||||
cs eventAPI
|
||||
hcAPI headChangeAPI
|
||||
|
||||
lk sync.RWMutex
|
||||
matchers map[triggerID]StateMatchFunc
|
||||
}
|
||||
|
||||
func newWatcherEvents(ctx context.Context, hcAPI headChangeAPI, cs eventAPI) watcherEvents {
|
||||
return watcherEvents{
|
||||
ctx: ctx,
|
||||
cs: cs,
|
||||
hcAPI: hcAPI,
|
||||
matchers: make(map[triggerID]StateMatchFunc),
|
||||
}
|
||||
}
|
||||
|
||||
// Run each of the matchers against the previous and current state to see if
|
||||
// there's a change
|
||||
func (we *watcherEvents) checkStateChanges(oldState, newState *types.TipSet) map[triggerID]eventData {
|
||||
we.lk.RLock()
|
||||
defer we.lk.RUnlock()
|
||||
|
||||
res := make(map[triggerID]eventData)
|
||||
for tid, matchFn := range we.matchers {
|
||||
ok, data, err := matchFn(oldState, newState)
|
||||
if err != nil {
|
||||
log.Errorf("event diff fn failed: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if ok {
|
||||
res[tid] = data
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// StateChange represents a change in state
|
||||
type StateChange interface{}
|
||||
|
||||
// StateChangeHandler arguments:
|
||||
// `oldTs` is the state "from" tipset
|
||||
// `newTs` is the state "to" tipset
|
||||
// `states` is the change in state
|
||||
// `curH`-`ts.Height` = `confidence`
|
||||
type StateChangeHandler func(oldTs, newTs *types.TipSet, states StateChange, curH abi.ChainEpoch) (more bool, err error)
|
||||
|
||||
type StateMatchFunc func(oldTs, newTs *types.TipSet) (bool, StateChange, error)
|
||||
|
||||
// StateChanged registers a callback which is triggered when a specified state
|
||||
// change occurs or a timeout is reached.
|
||||
//
|
||||
// * `CheckFunc` callback is invoked immediately with a recent tipset, it
|
||||
// returns two booleans - `done`, and `more`.
|
||||
//
|
||||
// * `done` should be true when some on-chain state change we are waiting
|
||||
// for has happened. When `done` is set to true, timeout trigger is disabled.
|
||||
//
|
||||
// * `more` should be false when we don't want to receive new notifications
|
||||
// through StateChangeHandler. Note that notifications may still be delivered to
|
||||
// RevertHandler
|
||||
//
|
||||
// * `StateChangeHandler` is called when the specified state change was observed
|
||||
// on-chain, and a confidence threshold was reached, or the specified `timeout`
|
||||
// height was reached with no state change observed. When this callback is
|
||||
// invoked on a timeout, `oldState` and `newState` are set to nil.
|
||||
// This callback returns a boolean specifying whether further notifications
|
||||
// should be sent, like `more` return param from `CheckFunc` above.
|
||||
//
|
||||
// * `RevertHandler` is called after apply handler, when we drop the tipset
|
||||
// containing the message. The tipset passed as the argument is the tipset
|
||||
// that is being dropped. Note that the event dropped may be re-applied
|
||||
// in a different tipset in small amount of time.
|
||||
//
|
||||
// * `StateMatchFunc` is called against each tipset state. If there is a match,
|
||||
// the state change is queued up until the confidence interval has elapsed (and
|
||||
// `StateChangeHandler` is called)
|
||||
func (we *watcherEvents) StateChanged(check CheckFunc, scHnd StateChangeHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, mf StateMatchFunc) error {
|
||||
hnd := func(data eventData, prevTs, ts *types.TipSet, height abi.ChainEpoch) (bool, error) {
|
||||
states, ok := data.(StateChange)
|
||||
if data != nil && !ok {
|
||||
panic("expected StateChange")
|
||||
}
|
||||
|
||||
return scHnd(prevTs, ts, states, height)
|
||||
}
|
||||
|
||||
id, err := we.hcAPI.onHeadChanged(check, hnd, rev, confidence, timeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
we.lk.Lock()
|
||||
defer we.lk.Unlock()
|
||||
we.matchers[id] = mf
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// messageEvents watches for message calls to actors
|
||||
type messageEvents struct {
|
||||
ctx context.Context
|
||||
cs eventAPI
|
||||
hcAPI headChangeAPI
|
||||
|
||||
lk sync.RWMutex
|
||||
matchers map[triggerID][]MsgMatchFunc
|
||||
}
|
||||
|
||||
func newMessageEvents(ctx context.Context, hcAPI headChangeAPI, cs eventAPI) messageEvents {
|
||||
return messageEvents{
|
||||
ctx: ctx,
|
||||
cs: cs,
|
||||
hcAPI: hcAPI,
|
||||
matchers: map[triggerID][]MsgMatchFunc{},
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there are any new actor calls
|
||||
func (me *messageEvents) checkNewCalls(ts *types.TipSet) (map[triggerID]eventData, error) {
|
||||
pts, err := me.cs.ChainGetTipSet(me.ctx, ts.Parents()) // we actually care about messages in the parent tipset here
|
||||
if err != nil {
|
||||
log.Errorf("getting parent tipset in checkNewCalls: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
me.lk.RLock()
|
||||
defer me.lk.RUnlock()
|
||||
|
||||
res := make(map[triggerID]eventData)
|
||||
me.messagesForTs(pts, func(msg *types.Message) {
|
||||
// TODO: provide receipts
|
||||
|
||||
for tid, matchFns := range me.matchers {
|
||||
var matched bool
|
||||
var once bool
|
||||
for _, matchFn := range matchFns {
|
||||
matchOne, ok, err := matchFn(msg)
|
||||
if err != nil {
|
||||
log.Errorf("event matcher failed: %s", err)
|
||||
continue
|
||||
}
|
||||
matched = ok
|
||||
once = matchOne
|
||||
|
||||
if matched {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if matched {
|
||||
res[tid] = msg
|
||||
if once {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Get the messages in a tipset
|
||||
func (me *messageEvents) messagesForTs(ts *types.TipSet, consume func(*types.Message)) {
|
||||
seen := map[cid.Cid]struct{}{}
|
||||
|
||||
for _, tsb := range ts.Blocks() {
|
||||
|
||||
msgs, err := e.cs.ChainGetBlockMessages(context.TODO(), tsb.Cid())
|
||||
msgs, err := me.cs.ChainGetBlockMessages(context.TODO(), tsb.Cid())
|
||||
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
|
||||
@ -290,20 +547,27 @@ func (e *calledEvents) messagesForTs(ts *types.TipSet, consume func(*types.Messa
|
||||
}
|
||||
}
|
||||
|
||||
// Called registers a callbacks which are triggered when a specified method is
|
||||
// MsgHandler arguments:
|
||||
// `ts` is the tipset, in which the `msg` is included.
|
||||
// `curH`-`ts.Height` = `confidence`
|
||||
type MsgHandler func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (more bool, err error)
|
||||
|
||||
type MsgMatchFunc func(msg *types.Message) (matchOnce bool, matched bool, err error)
|
||||
|
||||
// Called registers a callback which is triggered when a specified method is
|
||||
// called on an actor, or a timeout is reached.
|
||||
//
|
||||
// * `CheckFunc` callback is invoked immediately with a recent tipset, it
|
||||
// returns two booleans - `done`, and `more`.
|
||||
//
|
||||
// * `done` should be true when some on-chain action we are waiting for has
|
||||
// happened. When `done` is set to true, timeout trigger is disabled.
|
||||
// * `done` should be true when some on-chain action we are waiting for has
|
||||
// happened. When `done` is set to true, timeout trigger is disabled.
|
||||
//
|
||||
// * `more` should be false when we don't want to receive new notifications
|
||||
// through CalledHandler. Note that notifications may still be delivered to
|
||||
// RevertHandler
|
||||
// * `more` should be false when we don't want to receive new notifications
|
||||
// through MsgHandler. Note that notifications may still be delivered to
|
||||
// RevertHandler
|
||||
//
|
||||
// * `CalledHandler` is called when the specified event was observed on-chain,
|
||||
// * `MsgHandler` is called when the specified event was observed on-chain,
|
||||
// and a confidence threshold was reached, or the specified `timeout` height
|
||||
// was reached with no events observed. When this callback is invoked on a
|
||||
// timeout, `msg` is set to nil. This callback returns a boolean specifying
|
||||
@ -314,44 +578,38 @@ func (e *calledEvents) messagesForTs(ts *types.TipSet, consume func(*types.Messa
|
||||
// containing the message. The tipset passed as the argument is the tipset
|
||||
// that is being dropped. Note that the message dropped may be re-applied
|
||||
// in a different tipset in small amount of time.
|
||||
func (e *calledEvents) Called(check CheckFunc, hnd CalledHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, mf MatchFunc) error {
|
||||
e.lk.Lock()
|
||||
defer e.lk.Unlock()
|
||||
|
||||
ts := e.tsc.best()
|
||||
done, more, err := check(ts)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("called check error (h: %d): %w", ts.Height(), err)
|
||||
}
|
||||
if done {
|
||||
timeout = NoTimeout
|
||||
}
|
||||
|
||||
id := e.ctr
|
||||
e.ctr++
|
||||
|
||||
e.triggers[id] = &callHandler{
|
||||
confidence: confidence,
|
||||
timeout: timeout + abi.ChainEpoch(confidence),
|
||||
|
||||
disabled: !more,
|
||||
|
||||
handle: hnd,
|
||||
revert: rev,
|
||||
}
|
||||
|
||||
e.matchers[id] = append(e.matchers[id], mf)
|
||||
|
||||
if timeout != NoTimeout {
|
||||
if e.timeouts[timeout+abi.ChainEpoch(confidence)] == nil {
|
||||
e.timeouts[timeout+abi.ChainEpoch(confidence)] = map[uint64]int{}
|
||||
//
|
||||
// * `MsgMatchFunc` is called against each message. If there is a match, the
|
||||
// message is queued up until the confidence interval has elapsed (and
|
||||
// `MsgHandler` is called)
|
||||
func (me *messageEvents) Called(check CheckFunc, msgHnd MsgHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, mf MsgMatchFunc) error {
|
||||
hnd := func(data eventData, prevTs, ts *types.TipSet, height abi.ChainEpoch) (bool, error) {
|
||||
msg, ok := data.(*types.Message)
|
||||
if data != nil && !ok {
|
||||
panic("expected msg")
|
||||
}
|
||||
e.timeouts[timeout+abi.ChainEpoch(confidence)][id] = 0
|
||||
|
||||
rec, err := me.cs.StateGetReceipt(me.ctx, msg.Cid(), ts.Key())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return msgHnd(msg, rec, ts, height)
|
||||
}
|
||||
|
||||
id, err := me.hcAPI.onHeadChanged(check, hnd, rev, confidence, timeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
me.lk.Lock()
|
||||
defer me.lk.Unlock()
|
||||
me.matchers[id] = append(me.matchers[id], mf)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *calledEvents) CalledMsg(ctx context.Context, hnd CalledHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, msg types.ChainMsg) error {
|
||||
return e.Called(e.CheckMsg(ctx, msg, hnd), hnd, rev, confidence, timeout, e.MatchMsg(msg.VMMessage()))
|
||||
// Convenience function for checking and matching messages
|
||||
func (me *messageEvents) CalledMsg(ctx context.Context, hnd MsgHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, msg types.ChainMsg) error {
|
||||
return me.Called(me.CheckMsg(ctx, msg, hnd), hnd, rev, confidence, timeout, me.MatchMsg(msg.VMMessage()))
|
||||
}
|
||||
|
@ -26,12 +26,15 @@ type heightEvents struct {
|
||||
}
|
||||
|
||||
func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error {
|
||||
|
||||
ctx, span := trace.StartSpan(e.ctx, "events.HeightHeadChange")
|
||||
defer span.End()
|
||||
span.AddAttributes(trace.Int64Attribute("endHeight", int64(app[0].Height())))
|
||||
span.AddAttributes(trace.Int64Attribute("reverts", int64(len(rev))))
|
||||
span.AddAttributes(trace.Int64Attribute("applies", int64(len(app))))
|
||||
|
||||
e.lk.Lock()
|
||||
defer e.lk.Unlock()
|
||||
for _, ts := range rev {
|
||||
// TODO: log error if h below gcconfidence
|
||||
// revert height-based triggers
|
||||
@ -40,7 +43,10 @@ func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error {
|
||||
for _, tid := range e.htHeights[h] {
|
||||
ctx, span := trace.StartSpan(ctx, "events.HeightRevert")
|
||||
|
||||
err := e.heightTriggers[tid].revert(ctx, ts)
|
||||
rev := e.heightTriggers[tid].revert
|
||||
e.lk.Unlock()
|
||||
err := rev(ctx, ts)
|
||||
e.lk.Lock()
|
||||
e.heightTriggers[tid].called = false
|
||||
|
||||
span.End()
|
||||
@ -87,7 +93,6 @@ func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error {
|
||||
if hnd.called {
|
||||
return nil
|
||||
}
|
||||
hnd.called = true
|
||||
|
||||
triggerH := h - abi.ChainEpoch(hnd.confidence)
|
||||
|
||||
@ -98,8 +103,11 @@ func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error {
|
||||
|
||||
ctx, span := trace.StartSpan(ctx, "events.HeightApply")
|
||||
span.AddAttributes(trace.BoolAttribute("immediate", false))
|
||||
|
||||
err = hnd.handle(ctx, incTs, h)
|
||||
handle := hnd.handle
|
||||
e.lk.Unlock()
|
||||
err = handle(ctx, incTs, h)
|
||||
e.lk.Lock()
|
||||
hnd.called = true
|
||||
span.End()
|
||||
|
||||
if err != nil {
|
||||
|
@ -561,9 +561,9 @@ func TestAtChainedConfidenceNull(t *testing.T) {
|
||||
require.Equal(t, false, reverted)
|
||||
}
|
||||
|
||||
func matchAddrMethod(to address.Address, m abi.MethodNum) func(msg *types.Message) (bool, error) {
|
||||
return func(msg *types.Message) (bool, error) {
|
||||
return to == msg.To && m == msg.Method, nil
|
||||
func matchAddrMethod(to address.Address, m abi.MethodNum) func(msg *types.Message) (matchOnce bool, matched bool, err error) {
|
||||
return func(msg *types.Message) (matchOnce bool, matched bool, err error) {
|
||||
return true, to == msg.To && m == msg.Method, nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -1004,8 +1004,6 @@ func TestRemoveTriggersOnMessage(t *testing.T) {
|
||||
return false, true, nil
|
||||
}, func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (bool, error) {
|
||||
require.Equal(t, false, applied)
|
||||
fmt.Println(msg == nil)
|
||||
fmt.Println(curH)
|
||||
applied = true
|
||||
return more, nil
|
||||
}, func(_ context.Context, ts *types.TipSet) error {
|
||||
@ -1067,3 +1065,250 @@ func TestRemoveTriggersOnMessage(t *testing.T) {
|
||||
require.Equal(t, true, applied)
|
||||
require.Equal(t, false, reverted)
|
||||
}
|
||||
|
||||
type testStateChange struct {
|
||||
from string
|
||||
to string
|
||||
}
|
||||
|
||||
func TestStateChanged(t *testing.T) {
|
||||
fcs := &fakeCS{
|
||||
t: t,
|
||||
h: 1,
|
||||
|
||||
msgs: map[cid.Cid]fakeMsg{},
|
||||
blkMsgs: map[cid.Cid]cid.Cid{},
|
||||
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||
}
|
||||
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||
|
||||
events := NewEvents(context.Background(), fcs)
|
||||
|
||||
more := true
|
||||
var applied, reverted bool
|
||||
var appliedData StateChange
|
||||
var appliedOldTs *types.TipSet
|
||||
var appliedNewTs *types.TipSet
|
||||
var appliedH abi.ChainEpoch
|
||||
var matchData StateChange
|
||||
|
||||
confidence := 3
|
||||
timeout := abi.ChainEpoch(20)
|
||||
|
||||
err := events.StateChanged(func(ts *types.TipSet) (d bool, m bool, e error) {
|
||||
return false, true, nil
|
||||
}, func(oldTs, newTs *types.TipSet, data StateChange, curH abi.ChainEpoch) (bool, error) {
|
||||
require.Equal(t, false, applied)
|
||||
applied = true
|
||||
appliedData = data
|
||||
appliedOldTs = oldTs
|
||||
appliedNewTs = newTs
|
||||
appliedH = curH
|
||||
return more, nil
|
||||
}, func(_ context.Context, ts *types.TipSet) error {
|
||||
reverted = true
|
||||
return nil
|
||||
}, confidence, timeout, func(oldTs, newTs *types.TipSet) (bool, StateChange, error) {
|
||||
if matchData == nil {
|
||||
return false, matchData, nil
|
||||
}
|
||||
|
||||
d := matchData
|
||||
matchData = nil
|
||||
return true, d, nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// create few blocks to make sure nothing get's randomly called
|
||||
|
||||
fcs.advance(0, 4, nil) // H=5
|
||||
require.Equal(t, false, applied)
|
||||
require.Equal(t, false, reverted)
|
||||
|
||||
// create state change (but below confidence threshold)
|
||||
matchData = testStateChange{from: "a", to: "b"}
|
||||
fcs.advance(0, 3, nil)
|
||||
|
||||
require.Equal(t, false, applied)
|
||||
require.Equal(t, false, reverted)
|
||||
|
||||
// create additional block so we are above confidence threshold
|
||||
|
||||
fcs.advance(0, 2, nil) // H=10 (confidence=3, apply)
|
||||
|
||||
require.Equal(t, true, applied)
|
||||
require.Equal(t, false, reverted)
|
||||
applied = false
|
||||
|
||||
// dip below confidence (should not apply again)
|
||||
fcs.advance(2, 2, nil) // H=10 (confidence=3, apply)
|
||||
|
||||
require.Equal(t, false, applied)
|
||||
require.Equal(t, false, reverted)
|
||||
|
||||
// Change happens from 5 -> 6
|
||||
require.Equal(t, abi.ChainEpoch(5), appliedOldTs.Height())
|
||||
require.Equal(t, abi.ChainEpoch(6), appliedNewTs.Height())
|
||||
|
||||
// Actually applied (with confidence) at 9
|
||||
require.Equal(t, abi.ChainEpoch(9), appliedH)
|
||||
|
||||
// Make sure the state change was correctly passed through
|
||||
rcvd := appliedData.(testStateChange)
|
||||
require.Equal(t, "a", rcvd.from)
|
||||
require.Equal(t, "b", rcvd.to)
|
||||
}
|
||||
|
||||
func TestStateChangedRevert(t *testing.T) {
|
||||
fcs := &fakeCS{
|
||||
t: t,
|
||||
h: 1,
|
||||
|
||||
msgs: map[cid.Cid]fakeMsg{},
|
||||
blkMsgs: map[cid.Cid]cid.Cid{},
|
||||
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||
}
|
||||
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||
|
||||
events := NewEvents(context.Background(), fcs)
|
||||
|
||||
more := true
|
||||
var applied, reverted bool
|
||||
var matchData StateChange
|
||||
|
||||
confidence := 1
|
||||
timeout := abi.ChainEpoch(20)
|
||||
|
||||
err := events.StateChanged(func(ts *types.TipSet) (d bool, m bool, e error) {
|
||||
return false, true, nil
|
||||
}, func(oldTs, newTs *types.TipSet, data StateChange, curH abi.ChainEpoch) (bool, error) {
|
||||
require.Equal(t, false, applied)
|
||||
applied = true
|
||||
return more, nil
|
||||
}, func(_ context.Context, ts *types.TipSet) error {
|
||||
reverted = true
|
||||
return nil
|
||||
}, confidence, timeout, func(oldTs, newTs *types.TipSet) (bool, StateChange, error) {
|
||||
if matchData == nil {
|
||||
return false, matchData, nil
|
||||
}
|
||||
|
||||
d := matchData
|
||||
matchData = nil
|
||||
return true, d, nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
fcs.advance(0, 2, nil) // H=3
|
||||
|
||||
// Make a state change from TS at height 3 to TS at height 4
|
||||
matchData = testStateChange{from: "a", to: "b"}
|
||||
fcs.advance(0, 1, nil) // H=4
|
||||
|
||||
// Haven't yet reached confidence
|
||||
require.Equal(t, false, applied)
|
||||
require.Equal(t, false, reverted)
|
||||
|
||||
// Advance to reach confidence level
|
||||
fcs.advance(0, 1, nil) // H=5
|
||||
|
||||
// Should now have called the handler
|
||||
require.Equal(t, true, applied)
|
||||
require.Equal(t, false, reverted)
|
||||
applied = false
|
||||
|
||||
// Advance 3 more TS
|
||||
fcs.advance(0, 3, nil) // H=8
|
||||
|
||||
require.Equal(t, false, applied)
|
||||
require.Equal(t, false, reverted)
|
||||
|
||||
// Regress but not so far as to cause a revert
|
||||
fcs.advance(3, 1, nil) // H=6
|
||||
|
||||
require.Equal(t, false, applied)
|
||||
require.Equal(t, false, reverted)
|
||||
|
||||
// Regress back to state where change happened
|
||||
fcs.advance(3, 1, nil) // H=4
|
||||
|
||||
// Expect revert to have happened
|
||||
require.Equal(t, false, applied)
|
||||
require.Equal(t, true, reverted)
|
||||
}
|
||||
|
||||
func TestStateChangedTimeout(t *testing.T) {
|
||||
fcs := &fakeCS{
|
||||
t: t,
|
||||
h: 1,
|
||||
|
||||
msgs: map[cid.Cid]fakeMsg{},
|
||||
blkMsgs: map[cid.Cid]cid.Cid{},
|
||||
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||
}
|
||||
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||
|
||||
events := NewEvents(context.Background(), fcs)
|
||||
|
||||
called := false
|
||||
|
||||
err := events.StateChanged(func(ts *types.TipSet) (d bool, m bool, e error) {
|
||||
return false, true, nil
|
||||
}, func(oldTs, newTs *types.TipSet, data StateChange, curH abi.ChainEpoch) (bool, error) {
|
||||
called = true
|
||||
require.Nil(t, data)
|
||||
require.Equal(t, abi.ChainEpoch(20), newTs.Height())
|
||||
require.Equal(t, abi.ChainEpoch(23), curH)
|
||||
return false, nil
|
||||
}, func(_ context.Context, ts *types.TipSet) error {
|
||||
t.Fatal("revert on timeout")
|
||||
return nil
|
||||
}, 3, 20, func(oldTs, newTs *types.TipSet) (bool, StateChange, error) {
|
||||
return false, nil, nil
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
fcs.advance(0, 21, nil)
|
||||
require.False(t, called)
|
||||
|
||||
fcs.advance(0, 5, nil)
|
||||
require.True(t, called)
|
||||
called = false
|
||||
|
||||
// with check func reporting done
|
||||
|
||||
fcs = &fakeCS{
|
||||
t: t,
|
||||
h: 1,
|
||||
|
||||
msgs: map[cid.Cid]fakeMsg{},
|
||||
blkMsgs: map[cid.Cid]cid.Cid{},
|
||||
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||
}
|
||||
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||
|
||||
events = NewEvents(context.Background(), fcs)
|
||||
|
||||
err = events.StateChanged(func(ts *types.TipSet) (d bool, m bool, e error) {
|
||||
return true, true, nil
|
||||
}, func(oldTs, newTs *types.TipSet, data StateChange, curH abi.ChainEpoch) (bool, error) {
|
||||
called = true
|
||||
require.Nil(t, data)
|
||||
require.Equal(t, abi.ChainEpoch(20), newTs.Height())
|
||||
require.Equal(t, abi.ChainEpoch(23), curH)
|
||||
return false, nil
|
||||
}, func(_ context.Context, ts *types.TipSet) error {
|
||||
t.Fatal("revert on timeout")
|
||||
return nil
|
||||
}, 3, 20, func(oldTs, newTs *types.TipSet) (bool, StateChange, error) {
|
||||
return false, nil, nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
fcs.advance(0, 21, nil)
|
||||
require.False(t, called)
|
||||
|
||||
fcs.advance(0, 5, nil)
|
||||
require.False(t, called)
|
||||
}
|
||||
|
25
chain/events/state/ctxstore.go
Normal file
25
chain/events/state/ctxstore.go
Normal file
@ -0,0 +1,25 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
)
|
||||
|
||||
type contextStore struct {
|
||||
ctx context.Context
|
||||
cst *cbor.BasicIpldStore
|
||||
}
|
||||
|
||||
func (cs *contextStore) Context() context.Context {
|
||||
return cs.ctx
|
||||
}
|
||||
|
||||
func (cs *contextStore) Get(ctx context.Context, c cid.Cid, out interface{}) error {
|
||||
return cs.cst.Get(ctx, c, out)
|
||||
}
|
||||
|
||||
func (cs *contextStore) Put(ctx context.Context, v interface{}) (cid.Cid, error) {
|
||||
return cs.cst.Put(ctx, v)
|
||||
}
|
106
chain/events/state/diff_adt.go
Normal file
106
chain/events/state/diff_adt.go
Normal file
@ -0,0 +1,106 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
typegen "github.com/whyrusleeping/cbor-gen"
|
||||
)
|
||||
|
||||
// AdtArrayDiff generalizes adt.Array diffing by accepting a Deferred type that can unmarshalled to its corresponding struct
|
||||
// in an interface implantation.
|
||||
// Add should be called when a new k,v is added to the array
|
||||
// Modify should be called when a value is modified in the array
|
||||
// Remove should be called when a value is removed from the array
|
||||
type AdtArrayDiff interface {
|
||||
Add(key uint64, val *typegen.Deferred) error
|
||||
Modify(key uint64, from, to *typegen.Deferred) error
|
||||
Remove(key uint64, val *typegen.Deferred) error
|
||||
}
|
||||
|
||||
// TODO Performance can be improved by diffing the underlying IPLD graph, e.g. https://github.com/ipfs/go-merkledag/blob/749fd8717d46b4f34c9ce08253070079c89bc56d/dagutils/diff.go#L104
|
||||
// CBOR Marshaling will likely be the largest performance bottleneck here.
|
||||
|
||||
// DiffAdtArray accepts two *adt.Array's and an AdtArrayDiff implementation. It does the following:
|
||||
// - All values that exist in preArr and not in curArr are passed to AdtArrayDiff.Remove()
|
||||
// - All values that exist in curArr nnd not in prevArr are passed to adtArrayDiff.Add()
|
||||
// - All values that exist in preArr and in curArr are passed to AdtArrayDiff.Modify()
|
||||
// - It is the responsibility of AdtArrayDiff.Modify() to determine if the values it was passed have been modified.
|
||||
func DiffAdtArray(preArr, curArr *adt.Array, out AdtArrayDiff) error {
|
||||
prevVal := new(typegen.Deferred)
|
||||
if err := preArr.ForEach(prevVal, func(i int64) error {
|
||||
curVal := new(typegen.Deferred)
|
||||
found, err := curArr.Get(uint64(i), curVal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !found {
|
||||
if err := out.Remove(uint64(i), prevVal); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := out.Modify(uint64(i), prevVal, curVal); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return curArr.Delete(uint64(i))
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
curVal := new(typegen.Deferred)
|
||||
return curArr.ForEach(curVal, func(i int64) error {
|
||||
return out.Add(uint64(i), curVal)
|
||||
})
|
||||
}
|
||||
|
||||
// TODO Performance can be improved by diffing the underlying IPLD graph, e.g. https://github.com/ipfs/go-merkledag/blob/749fd8717d46b4f34c9ce08253070079c89bc56d/dagutils/diff.go#L104
|
||||
// CBOR Marshaling will likely be the largest performance bottleneck here.
|
||||
|
||||
// AdtMapDiff generalizes adt.Map diffing by accepting a Deferred type that can unmarshalled to its corresponding struct
|
||||
// in an interface implantation.
|
||||
// AsKey should return the Keyer implementation specific to the map
|
||||
// Add should be called when a new k,v is added to the map
|
||||
// Modify should be called when a value is modified in the map
|
||||
// Remove should be called when a value is removed from the map
|
||||
type AdtMapDiff interface {
|
||||
AsKey(key string) (adt.Keyer, error)
|
||||
Add(key string, val *typegen.Deferred) error
|
||||
Modify(key string, from, to *typegen.Deferred) error
|
||||
Remove(key string, val *typegen.Deferred) error
|
||||
}
|
||||
|
||||
func DiffAdtMap(preMap, curMap *adt.Map, out AdtMapDiff) error {
|
||||
prevVal := new(typegen.Deferred)
|
||||
if err := preMap.ForEach(prevVal, func(key string) error {
|
||||
curVal := new(typegen.Deferred)
|
||||
k, err := out.AsKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
found, err := curMap.Get(k, curVal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !found {
|
||||
if err := out.Remove(key, prevVal); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := out.Modify(key, prevVal, curVal); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return curMap.Delete(k)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
curVal := new(typegen.Deferred)
|
||||
return curMap.ForEach(curVal, func(key string) error {
|
||||
return out.Add(key, curVal)
|
||||
})
|
||||
}
|
155
chain/events/state/diff_adt_test.go
Normal file
155
chain/events/state/diff_adt_test.go
Normal file
@ -0,0 +1,155 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
ds "github.com/ipfs/go-datastore"
|
||||
ds_sync "github.com/ipfs/go-datastore/sync"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
cbornode "github.com/ipfs/go-ipld-cbor"
|
||||
typegen "github.com/whyrusleeping/cbor-gen"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
)
|
||||
|
||||
func TestDiffAdtArray(t *testing.T) {
|
||||
ctxstoreA := newContextStore()
|
||||
ctxstoreB := newContextStore()
|
||||
|
||||
arrA := adt.MakeEmptyArray(ctxstoreA)
|
||||
arrB := adt.MakeEmptyArray(ctxstoreB)
|
||||
|
||||
require.NoError(t, arrA.Set(0, runtime.CBORBytes([]byte{0}))) // delete
|
||||
|
||||
require.NoError(t, arrA.Set(1, runtime.CBORBytes([]byte{0}))) // modify
|
||||
require.NoError(t, arrB.Set(1, runtime.CBORBytes([]byte{1})))
|
||||
|
||||
require.NoError(t, arrA.Set(2, runtime.CBORBytes([]byte{1}))) // delete
|
||||
|
||||
require.NoError(t, arrA.Set(3, runtime.CBORBytes([]byte{0}))) // noop
|
||||
require.NoError(t, arrB.Set(3, runtime.CBORBytes([]byte{0})))
|
||||
|
||||
require.NoError(t, arrA.Set(4, runtime.CBORBytes([]byte{0}))) // modify
|
||||
require.NoError(t, arrB.Set(4, runtime.CBORBytes([]byte{6})))
|
||||
|
||||
require.NoError(t, arrB.Set(5, runtime.CBORBytes{8})) // add
|
||||
require.NoError(t, arrB.Set(6, runtime.CBORBytes{9})) // add
|
||||
|
||||
changes := new(TestAdtDiff)
|
||||
|
||||
assert.NoError(t, DiffAdtArray(arrA, arrB, changes))
|
||||
assert.NotNil(t, changes)
|
||||
|
||||
assert.Equal(t, 2, len(changes.Added))
|
||||
// keys 5 and 6 were added
|
||||
assert.EqualValues(t, uint64(5), changes.Added[0].key)
|
||||
assert.EqualValues(t, []byte{8}, changes.Added[0].val)
|
||||
assert.EqualValues(t, uint64(6), changes.Added[1].key)
|
||||
assert.EqualValues(t, []byte{9}, changes.Added[1].val)
|
||||
|
||||
assert.Equal(t, 2, len(changes.Modified))
|
||||
// keys 1 and 4 were modified
|
||||
assert.EqualValues(t, uint64(1), changes.Modified[0].From.key)
|
||||
assert.EqualValues(t, []byte{0}, changes.Modified[0].From.val)
|
||||
assert.EqualValues(t, uint64(1), changes.Modified[0].To.key)
|
||||
assert.EqualValues(t, []byte{1}, changes.Modified[0].To.val)
|
||||
assert.EqualValues(t, uint64(4), changes.Modified[1].From.key)
|
||||
assert.EqualValues(t, []byte{0}, changes.Modified[1].From.val)
|
||||
assert.EqualValues(t, uint64(4), changes.Modified[1].To.key)
|
||||
assert.EqualValues(t, []byte{6}, changes.Modified[1].To.val)
|
||||
|
||||
assert.Equal(t, 2, len(changes.Removed))
|
||||
// keys 0 and 2 were deleted
|
||||
assert.EqualValues(t, uint64(0), changes.Removed[0].key)
|
||||
assert.EqualValues(t, []byte{0}, changes.Removed[0].val)
|
||||
assert.EqualValues(t, uint64(2), changes.Removed[1].key)
|
||||
assert.EqualValues(t, []byte{1}, changes.Removed[1].val)
|
||||
}
|
||||
|
||||
type adtDiffResult struct {
|
||||
key uint64
|
||||
val runtime.CBORBytes
|
||||
}
|
||||
|
||||
type TestAdtDiff struct {
|
||||
Added []adtDiffResult
|
||||
Modified []TestAdtDiffModified
|
||||
Removed []adtDiffResult
|
||||
}
|
||||
|
||||
var _ AdtArrayDiff = &TestAdtDiff{}
|
||||
|
||||
type TestAdtDiffModified struct {
|
||||
From adtDiffResult
|
||||
To adtDiffResult
|
||||
}
|
||||
|
||||
func (t *TestAdtDiff) Add(key uint64, val *typegen.Deferred) error {
|
||||
v := new(runtime.CBORBytes)
|
||||
err := v.UnmarshalCBOR(bytes.NewReader(val.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Added = append(t.Added, adtDiffResult{
|
||||
key: key,
|
||||
val: *v,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TestAdtDiff) Modify(key uint64, from, to *typegen.Deferred) error {
|
||||
vFrom := new(runtime.CBORBytes)
|
||||
err := vFrom.UnmarshalCBOR(bytes.NewReader(from.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vTo := new(runtime.CBORBytes)
|
||||
err = vTo.UnmarshalCBOR(bytes.NewReader(to.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !bytes.Equal(*vFrom, *vTo) {
|
||||
t.Modified = append(t.Modified, TestAdtDiffModified{
|
||||
From: adtDiffResult{
|
||||
key: key,
|
||||
val: *vFrom,
|
||||
},
|
||||
To: adtDiffResult{
|
||||
key: key,
|
||||
val: *vTo,
|
||||
},
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TestAdtDiff) Remove(key uint64, val *typegen.Deferred) error {
|
||||
v := new(runtime.CBORBytes)
|
||||
err := v.UnmarshalCBOR(bytes.NewReader(val.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Removed = append(t.Removed, adtDiffResult{
|
||||
key: key,
|
||||
val: *v,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func newContextStore() *contextStore {
|
||||
ctx := context.Background()
|
||||
bs := bstore.NewBlockstore(ds_sync.MutexWrap(ds.NewMapDatastore()))
|
||||
store := cbornode.NewCborStore(bs)
|
||||
return &contextStore{
|
||||
ctx: ctx,
|
||||
cst: store,
|
||||
}
|
||||
}
|
495
chain/events/state/predicates.go
Normal file
495
chain/events/state/predicates.go
Normal file
@ -0,0 +1,495 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
typegen "github.com/whyrusleeping/cbor-gen"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/api/apibstore"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
// UserData is the data returned from the DiffTipSetKeyFunc
|
||||
type UserData interface{}
|
||||
|
||||
// ChainAPI abstracts out calls made by this class to external APIs
|
||||
type ChainAPI interface {
|
||||
apibstore.ChainIO
|
||||
StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error)
|
||||
}
|
||||
|
||||
// StatePredicates has common predicates for responding to state changes
|
||||
type StatePredicates struct {
|
||||
api ChainAPI
|
||||
cst *cbor.BasicIpldStore
|
||||
}
|
||||
|
||||
func NewStatePredicates(api ChainAPI) *StatePredicates {
|
||||
return &StatePredicates{
|
||||
api: api,
|
||||
cst: cbor.NewCborStore(apibstore.NewAPIBlockstore(api)),
|
||||
}
|
||||
}
|
||||
|
||||
// DiffTipSetKeyFunc check if there's a change form oldState to newState, and returns
|
||||
// - changed: was there a change
|
||||
// - user: user-defined data representing the state change
|
||||
// - err
|
||||
type DiffTipSetKeyFunc func(ctx context.Context, oldState, newState types.TipSetKey) (changed bool, user UserData, err error)
|
||||
|
||||
type DiffActorStateFunc func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error)
|
||||
|
||||
// OnActorStateChanged calls diffStateFunc when the state changes for the given actor
|
||||
func (sp *StatePredicates) OnActorStateChanged(addr address.Address, diffStateFunc DiffActorStateFunc) DiffTipSetKeyFunc {
|
||||
return func(ctx context.Context, oldState, newState types.TipSetKey) (changed bool, user UserData, err error) {
|
||||
oldActor, err := sp.api.StateGetActor(ctx, addr, oldState)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
newActor, err := sp.api.StateGetActor(ctx, addr, newState)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
if oldActor.Head.Equals(newActor.Head) {
|
||||
return false, nil, nil
|
||||
}
|
||||
return diffStateFunc(ctx, oldActor.Head, newActor.Head)
|
||||
}
|
||||
}
|
||||
|
||||
type DiffStorageMarketStateFunc func(ctx context.Context, oldState *market.State, newState *market.State) (changed bool, user UserData, err error)
|
||||
|
||||
// OnStorageMarketActorChanged calls diffStorageMarketState when the state changes for the market actor
|
||||
func (sp *StatePredicates) OnStorageMarketActorChanged(diffStorageMarketState DiffStorageMarketStateFunc) DiffTipSetKeyFunc {
|
||||
return sp.OnActorStateChanged(builtin.StorageMarketActorAddr, func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error) {
|
||||
var oldState market.State
|
||||
if err := sp.cst.Get(ctx, oldActorStateHead, &oldState); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
var newState market.State
|
||||
if err := sp.cst.Get(ctx, newActorStateHead, &newState); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
return diffStorageMarketState(ctx, &oldState, &newState)
|
||||
})
|
||||
}
|
||||
|
||||
type DiffAdtArraysFunc func(ctx context.Context, oldDealStateRoot, newDealStateRoot *adt.Array) (changed bool, user UserData, err error)
|
||||
|
||||
// OnDealStateChanged calls diffDealStates when the market deal state changes
|
||||
func (sp *StatePredicates) OnDealStateChanged(diffDealStates DiffAdtArraysFunc) DiffStorageMarketStateFunc {
|
||||
return func(ctx context.Context, oldState *market.State, newState *market.State) (changed bool, user UserData, err error) {
|
||||
if oldState.States.Equals(newState.States) {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
ctxStore := &contextStore{
|
||||
ctx: ctx,
|
||||
cst: sp.cst,
|
||||
}
|
||||
|
||||
oldRoot, err := adt.AsArray(ctxStore, oldState.States)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
newRoot, err := adt.AsArray(ctxStore, newState.States)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
return diffDealStates(ctx, oldRoot, newRoot)
|
||||
}
|
||||
}
|
||||
|
||||
// OnDealProposalChanged calls diffDealProps when the market proposal state changes
|
||||
func (sp *StatePredicates) OnDealProposalChanged(diffDealProps DiffAdtArraysFunc) DiffStorageMarketStateFunc {
|
||||
return func(ctx context.Context, oldState *market.State, newState *market.State) (changed bool, user UserData, err error) {
|
||||
if oldState.Proposals.Equals(newState.Proposals) {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
ctxStore := &contextStore{
|
||||
ctx: ctx,
|
||||
cst: sp.cst,
|
||||
}
|
||||
|
||||
oldRoot, err := adt.AsArray(ctxStore, oldState.Proposals)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
newRoot, err := adt.AsArray(ctxStore, newState.Proposals)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
return diffDealProps(ctx, oldRoot, newRoot)
|
||||
}
|
||||
}
|
||||
|
||||
var _ AdtArrayDiff = &MarketDealProposalChanges{}
|
||||
|
||||
type MarketDealProposalChanges struct {
|
||||
Added []ProposalIDState
|
||||
Removed []ProposalIDState
|
||||
}
|
||||
|
||||
type ProposalIDState struct {
|
||||
ID abi.DealID
|
||||
Proposal market.DealProposal
|
||||
}
|
||||
|
||||
func (m *MarketDealProposalChanges) Add(key uint64, val *typegen.Deferred) error {
|
||||
dp := new(market.DealProposal)
|
||||
err := dp.UnmarshalCBOR(bytes.NewReader(val.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.Added = append(m.Added, ProposalIDState{abi.DealID(key), *dp})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MarketDealProposalChanges) Modify(key uint64, from, to *typegen.Deferred) error {
|
||||
// short circuit, DealProposals are static
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MarketDealProposalChanges) Remove(key uint64, val *typegen.Deferred) error {
|
||||
dp := new(market.DealProposal)
|
||||
err := dp.UnmarshalCBOR(bytes.NewReader(val.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.Removed = append(m.Removed, ProposalIDState{abi.DealID(key), *dp})
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnDealProposalAmtChanged detects changes in the deal proposal AMT for all deal proposals and returns a MarketProposalsChanges structure containing:
|
||||
// - Added Proposals
|
||||
// - Modified Proposals
|
||||
// - Removed Proposals
|
||||
func (sp *StatePredicates) OnDealProposalAmtChanged() DiffAdtArraysFunc {
|
||||
return func(ctx context.Context, oldDealProps, newDealProps *adt.Array) (changed bool, user UserData, err error) {
|
||||
proposalChanges := new(MarketDealProposalChanges)
|
||||
if err := DiffAdtArray(oldDealProps, newDealProps, proposalChanges); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
if len(proposalChanges.Added)+len(proposalChanges.Removed) == 0 {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
return true, proposalChanges, nil
|
||||
}
|
||||
}
|
||||
|
||||
var _ AdtArrayDiff = &MarketDealStateChanges{}
|
||||
|
||||
type MarketDealStateChanges struct {
|
||||
Added []DealIDState
|
||||
Modified []DealStateChange
|
||||
Removed []DealIDState
|
||||
}
|
||||
|
||||
type DealIDState struct {
|
||||
ID abi.DealID
|
||||
Deal market.DealState
|
||||
}
|
||||
|
||||
func (m *MarketDealStateChanges) Add(key uint64, val *typegen.Deferred) error {
|
||||
ds := new(market.DealState)
|
||||
err := ds.UnmarshalCBOR(bytes.NewReader(val.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.Added = append(m.Added, DealIDState{abi.DealID(key), *ds})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MarketDealStateChanges) Modify(key uint64, from, to *typegen.Deferred) error {
|
||||
dsFrom := new(market.DealState)
|
||||
if err := dsFrom.UnmarshalCBOR(bytes.NewReader(from.Raw)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dsTo := new(market.DealState)
|
||||
if err := dsTo.UnmarshalCBOR(bytes.NewReader(to.Raw)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if *dsFrom != *dsTo {
|
||||
m.Modified = append(m.Modified, DealStateChange{abi.DealID(key), dsFrom, dsTo})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MarketDealStateChanges) Remove(key uint64, val *typegen.Deferred) error {
|
||||
ds := new(market.DealState)
|
||||
err := ds.UnmarshalCBOR(bytes.NewReader(val.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.Removed = append(m.Removed, DealIDState{abi.DealID(key), *ds})
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnDealStateAmtChanged detects changes in the deal state AMT for all deal states and returns a MarketDealStateChanges structure containing:
|
||||
// - Added Deals
|
||||
// - Modified Deals
|
||||
// - Removed Deals
|
||||
func (sp *StatePredicates) OnDealStateAmtChanged() DiffAdtArraysFunc {
|
||||
return func(ctx context.Context, oldDealStates, newDealStates *adt.Array) (changed bool, user UserData, err error) {
|
||||
dealStateChanges := new(MarketDealStateChanges)
|
||||
if err := DiffAdtArray(oldDealStates, newDealStates, dealStateChanges); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
if len(dealStateChanges.Added)+len(dealStateChanges.Modified)+len(dealStateChanges.Removed) == 0 {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
return true, dealStateChanges, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ChangedDeals is a set of changes to deal state
|
||||
type ChangedDeals map[abi.DealID]DealStateChange
|
||||
|
||||
// DealStateChange is a change in deal state from -> to
|
||||
type DealStateChange struct {
|
||||
ID abi.DealID
|
||||
From *market.DealState
|
||||
To *market.DealState
|
||||
}
|
||||
|
||||
// DealStateChangedForIDs detects changes in the deal state AMT for the given deal IDs
|
||||
func (sp *StatePredicates) DealStateChangedForIDs(dealIds []abi.DealID) DiffAdtArraysFunc {
|
||||
return func(ctx context.Context, oldDealStateArray, newDealStateArray *adt.Array) (changed bool, user UserData, err error) {
|
||||
changedDeals := make(ChangedDeals)
|
||||
for _, dealID := range dealIds {
|
||||
var oldDealPtr, newDealPtr *market.DealState
|
||||
var oldDeal, newDeal market.DealState
|
||||
|
||||
// If the deal has been removed, we just set it to nil
|
||||
found, err := oldDealStateArray.Get(uint64(dealID), &oldDeal)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
if found {
|
||||
oldDealPtr = &oldDeal
|
||||
}
|
||||
|
||||
found, err = newDealStateArray.Get(uint64(dealID), &newDeal)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
if found {
|
||||
newDealPtr = &newDeal
|
||||
}
|
||||
|
||||
if oldDeal != newDeal {
|
||||
changedDeals[dealID] = DealStateChange{dealID, oldDealPtr, newDealPtr}
|
||||
}
|
||||
}
|
||||
if len(changedDeals) > 0 {
|
||||
return true, changedDeals, nil
|
||||
}
|
||||
return false, nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
type DiffMinerActorStateFunc func(ctx context.Context, oldState *miner.State, newState *miner.State) (changed bool, user UserData, err error)
|
||||
|
||||
func (sp *StatePredicates) OnMinerActorChange(minerAddr address.Address, diffMinerActorState DiffMinerActorStateFunc) DiffTipSetKeyFunc {
|
||||
return sp.OnActorStateChanged(minerAddr, func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error) {
|
||||
var oldState miner.State
|
||||
if err := sp.cst.Get(ctx, oldActorStateHead, &oldState); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
var newState miner.State
|
||||
if err := sp.cst.Get(ctx, newActorStateHead, &newState); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
return diffMinerActorState(ctx, &oldState, &newState)
|
||||
})
|
||||
}
|
||||
|
||||
type MinerSectorChanges struct {
|
||||
Added []miner.SectorOnChainInfo
|
||||
Extended []SectorExtensions
|
||||
Removed []miner.SectorOnChainInfo
|
||||
}
|
||||
|
||||
var _ AdtArrayDiff = &MinerSectorChanges{}
|
||||
|
||||
type SectorExtensions struct {
|
||||
From miner.SectorOnChainInfo
|
||||
To miner.SectorOnChainInfo
|
||||
}
|
||||
|
||||
func (m *MinerSectorChanges) Add(key uint64, val *typegen.Deferred) error {
|
||||
si := new(miner.SectorOnChainInfo)
|
||||
err := si.UnmarshalCBOR(bytes.NewReader(val.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.Added = append(m.Added, *si)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MinerSectorChanges) Modify(key uint64, from, to *typegen.Deferred) error {
|
||||
siFrom := new(miner.SectorOnChainInfo)
|
||||
err := siFrom.UnmarshalCBOR(bytes.NewReader(from.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
siTo := new(miner.SectorOnChainInfo)
|
||||
err = siTo.UnmarshalCBOR(bytes.NewReader(to.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if siFrom.Expiration != siTo.Expiration {
|
||||
m.Extended = append(m.Extended, SectorExtensions{
|
||||
From: *siFrom,
|
||||
To: *siTo,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MinerSectorChanges) Remove(key uint64, val *typegen.Deferred) error {
|
||||
si := new(miner.SectorOnChainInfo)
|
||||
err := si.UnmarshalCBOR(bytes.NewReader(val.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.Removed = append(m.Removed, *si)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sp *StatePredicates) OnMinerSectorChange() DiffMinerActorStateFunc {
|
||||
return func(ctx context.Context, oldState, newState *miner.State) (changed bool, user UserData, err error) {
|
||||
ctxStore := &contextStore{
|
||||
ctx: ctx,
|
||||
cst: sp.cst,
|
||||
}
|
||||
|
||||
sectorChanges := &MinerSectorChanges{
|
||||
Added: []miner.SectorOnChainInfo{},
|
||||
Extended: []SectorExtensions{},
|
||||
Removed: []miner.SectorOnChainInfo{},
|
||||
}
|
||||
|
||||
// no sector changes
|
||||
if oldState.Sectors.Equals(newState.Sectors) {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
oldSectors, err := adt.AsArray(ctxStore, oldState.Sectors)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
newSectors, err := adt.AsArray(ctxStore, newState.Sectors)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
if err := DiffAdtArray(oldSectors, newSectors, sectorChanges); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
// nothing changed
|
||||
if len(sectorChanges.Added)+len(sectorChanges.Extended)+len(sectorChanges.Removed) == 0 {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
return true, sectorChanges, nil
|
||||
}
|
||||
}
|
||||
|
||||
type MinerPreCommitChanges struct {
|
||||
Added []miner.SectorPreCommitOnChainInfo
|
||||
Removed []miner.SectorPreCommitOnChainInfo
|
||||
}
|
||||
|
||||
func (m *MinerPreCommitChanges) AsKey(key string) (adt.Keyer, error) {
|
||||
sector, err := adt.ParseUIntKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return miner.SectorKey(abi.SectorNumber(sector)), nil
|
||||
}
|
||||
|
||||
func (m *MinerPreCommitChanges) Add(key string, val *typegen.Deferred) error {
|
||||
sp := new(miner.SectorPreCommitOnChainInfo)
|
||||
err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.Added = append(m.Added, *sp)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MinerPreCommitChanges) Modify(key string, from, to *typegen.Deferred) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MinerPreCommitChanges) Remove(key string, val *typegen.Deferred) error {
|
||||
sp := new(miner.SectorPreCommitOnChainInfo)
|
||||
err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.Removed = append(m.Removed, *sp)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sp *StatePredicates) OnMinerPreCommitChange() DiffMinerActorStateFunc {
|
||||
return func(ctx context.Context, oldState, newState *miner.State) (changed bool, user UserData, err error) {
|
||||
ctxStore := &contextStore{
|
||||
ctx: ctx,
|
||||
cst: sp.cst,
|
||||
}
|
||||
|
||||
precommitChanges := &MinerPreCommitChanges{
|
||||
Added: []miner.SectorPreCommitOnChainInfo{},
|
||||
Removed: []miner.SectorPreCommitOnChainInfo{},
|
||||
}
|
||||
|
||||
if oldState.PreCommittedSectors.Equals(newState.PreCommittedSectors) {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
oldPrecommits, err := adt.AsMap(ctxStore, oldState.PreCommittedSectors)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
newPrecommits, err := adt.AsMap(ctxStore, newState.PreCommittedSectors)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
if err := DiffAdtMap(oldPrecommits, newPrecommits, precommitChanges); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
if len(precommitChanges.Added)+len(precommitChanges.Removed) == 0 {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
return true, precommitChanges, nil
|
||||
}
|
||||
}
|
503
chain/events/state/predicates_test.go
Normal file
503
chain/events/state/predicates_test.go
Normal file
@ -0,0 +1,503 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
ds "github.com/ipfs/go-datastore"
|
||||
ds_sync "github.com/ipfs/go-datastore/sync"
|
||||
"github.com/ipfs/go-hamt-ipld"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
cbornode "github.com/ipfs/go-ipld-cbor"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-amt-ipld/v2"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
tutils "github.com/filecoin-project/specs-actors/support/testing"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
var dummyCid cid.Cid
|
||||
|
||||
func init() {
|
||||
dummyCid, _ = cid.Parse("bafkqaaa")
|
||||
}
|
||||
|
||||
type mockAPI struct {
|
||||
ts map[types.TipSetKey]*types.Actor
|
||||
bs bstore.Blockstore
|
||||
}
|
||||
|
||||
func newMockAPI(bs bstore.Blockstore) *mockAPI {
|
||||
return &mockAPI{
|
||||
bs: bs,
|
||||
ts: make(map[types.TipSetKey]*types.Actor),
|
||||
}
|
||||
}
|
||||
|
||||
func (m mockAPI) ChainHasObj(ctx context.Context, c cid.Cid) (bool, error) {
|
||||
return m.bs.Has(c)
|
||||
}
|
||||
|
||||
func (m mockAPI) ChainReadObj(ctx context.Context, c cid.Cid) ([]byte, error) {
|
||||
blk, err := m.bs.Get(c)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("blockstore get: %w", err)
|
||||
}
|
||||
|
||||
return blk.RawData(), nil
|
||||
}
|
||||
|
||||
func (m mockAPI) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) {
|
||||
return m.ts[tsk], nil
|
||||
}
|
||||
|
||||
func (m mockAPI) setActor(tsk types.TipSetKey, act *types.Actor) {
|
||||
m.ts[tsk] = act
|
||||
}
|
||||
|
||||
func TestMarketPredicates(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
bs := bstore.NewBlockstore(ds_sync.MutexWrap(ds.NewMapDatastore()))
|
||||
store := cbornode.NewCborStore(bs)
|
||||
|
||||
oldDeal1 := &market.DealState{
|
||||
SectorStartEpoch: 1,
|
||||
LastUpdatedEpoch: 2,
|
||||
SlashEpoch: 0,
|
||||
}
|
||||
oldDeal2 := &market.DealState{
|
||||
SectorStartEpoch: 4,
|
||||
LastUpdatedEpoch: 5,
|
||||
SlashEpoch: 0,
|
||||
}
|
||||
oldDeals := map[abi.DealID]*market.DealState{
|
||||
abi.DealID(1): oldDeal1,
|
||||
abi.DealID(2): oldDeal2,
|
||||
}
|
||||
|
||||
oldProp1 := &market.DealProposal{
|
||||
PieceCID: dummyCid,
|
||||
PieceSize: 0,
|
||||
VerifiedDeal: false,
|
||||
Client: tutils.NewIDAddr(t, 1),
|
||||
Provider: tutils.NewIDAddr(t, 1),
|
||||
StartEpoch: 1,
|
||||
EndEpoch: 2,
|
||||
StoragePricePerEpoch: big.Zero(),
|
||||
ProviderCollateral: big.Zero(),
|
||||
ClientCollateral: big.Zero(),
|
||||
}
|
||||
oldProp2 := &market.DealProposal{
|
||||
PieceCID: dummyCid,
|
||||
PieceSize: 0,
|
||||
VerifiedDeal: false,
|
||||
Client: tutils.NewIDAddr(t, 1),
|
||||
Provider: tutils.NewIDAddr(t, 1),
|
||||
StartEpoch: 2,
|
||||
EndEpoch: 3,
|
||||
StoragePricePerEpoch: big.Zero(),
|
||||
ProviderCollateral: big.Zero(),
|
||||
ClientCollateral: big.Zero(),
|
||||
}
|
||||
oldProps := map[abi.DealID]*market.DealProposal{
|
||||
abi.DealID(1): oldProp1,
|
||||
abi.DealID(2): oldProp2,
|
||||
}
|
||||
|
||||
oldStateC := createMarketState(ctx, t, store, oldDeals, oldProps)
|
||||
|
||||
newDeal1 := &market.DealState{
|
||||
SectorStartEpoch: 1,
|
||||
LastUpdatedEpoch: 3,
|
||||
SlashEpoch: 0,
|
||||
}
|
||||
|
||||
// deal 2 removed
|
||||
|
||||
// added
|
||||
newDeal3 := &market.DealState{
|
||||
SectorStartEpoch: 1,
|
||||
LastUpdatedEpoch: 2,
|
||||
SlashEpoch: 3,
|
||||
}
|
||||
newDeals := map[abi.DealID]*market.DealState{
|
||||
abi.DealID(1): newDeal1,
|
||||
// deal 2 was removed
|
||||
abi.DealID(3): newDeal3,
|
||||
}
|
||||
|
||||
// added
|
||||
newProp3 := &market.DealProposal{
|
||||
PieceCID: dummyCid,
|
||||
PieceSize: 0,
|
||||
VerifiedDeal: false,
|
||||
Client: tutils.NewIDAddr(t, 1),
|
||||
Provider: tutils.NewIDAddr(t, 1),
|
||||
StartEpoch: 4,
|
||||
EndEpoch: 4,
|
||||
StoragePricePerEpoch: big.Zero(),
|
||||
ProviderCollateral: big.Zero(),
|
||||
ClientCollateral: big.Zero(),
|
||||
}
|
||||
newProps := map[abi.DealID]*market.DealProposal{
|
||||
abi.DealID(1): oldProp1, // 1 was persisted
|
||||
// prop 2 was removed
|
||||
abi.DealID(3): newProp3, // new
|
||||
// NB: DealProposals cannot be modified, so don't test that case.
|
||||
}
|
||||
newStateC := createMarketState(ctx, t, store, newDeals, newProps)
|
||||
|
||||
minerAddr, err := address.NewFromString("t00")
|
||||
require.NoError(t, err)
|
||||
oldState, err := mockTipset(minerAddr, 1)
|
||||
require.NoError(t, err)
|
||||
newState, err := mockTipset(minerAddr, 2)
|
||||
require.NoError(t, err)
|
||||
|
||||
api := newMockAPI(bs)
|
||||
api.setActor(oldState.Key(), &types.Actor{Head: oldStateC})
|
||||
api.setActor(newState.Key(), &types.Actor{Head: newStateC})
|
||||
|
||||
t.Run("deal ID predicate", func(t *testing.T) {
|
||||
preds := NewStatePredicates(api)
|
||||
|
||||
dealIds := []abi.DealID{abi.DealID(1), abi.DealID(2)}
|
||||
diffIDFn := preds.OnStorageMarketActorChanged(preds.OnDealStateChanged(preds.DealStateChangedForIDs(dealIds)))
|
||||
|
||||
// Diff a state against itself: expect no change
|
||||
changed, _, err := diffIDFn(ctx, oldState.Key(), oldState.Key())
|
||||
require.NoError(t, err)
|
||||
require.False(t, changed)
|
||||
|
||||
// Diff old state against new state
|
||||
changed, valIDs, err := diffIDFn(ctx, oldState.Key(), newState.Key())
|
||||
require.NoError(t, err)
|
||||
require.True(t, changed)
|
||||
|
||||
changedDealIDs, ok := valIDs.(ChangedDeals)
|
||||
require.True(t, ok)
|
||||
require.Len(t, changedDealIDs, 2)
|
||||
require.Contains(t, changedDealIDs, abi.DealID(1))
|
||||
require.Contains(t, changedDealIDs, abi.DealID(2))
|
||||
deal1 := changedDealIDs[abi.DealID(1)]
|
||||
if deal1.From.LastUpdatedEpoch != 2 || deal1.To.LastUpdatedEpoch != 3 {
|
||||
t.Fatal("Unexpected change to LastUpdatedEpoch")
|
||||
}
|
||||
deal2 := changedDealIDs[abi.DealID(2)]
|
||||
if deal2.From.LastUpdatedEpoch != 5 || deal2.To != nil {
|
||||
t.Fatal("Expected To to be nil")
|
||||
}
|
||||
|
||||
// Diff with non-existent deal.
|
||||
noDeal := []abi.DealID{4}
|
||||
diffNoDealFn := preds.OnStorageMarketActorChanged(preds.OnDealStateChanged(preds.DealStateChangedForIDs(noDeal)))
|
||||
changed, _, err = diffNoDealFn(ctx, oldState.Key(), newState.Key())
|
||||
require.NoError(t, err)
|
||||
require.False(t, changed)
|
||||
|
||||
// Test that OnActorStateChanged does not call the callback if the state has not changed
|
||||
mockAddr, err := address.NewFromString("t01")
|
||||
require.NoError(t, err)
|
||||
actorDiffFn := preds.OnActorStateChanged(mockAddr, func(context.Context, cid.Cid, cid.Cid) (bool, UserData, error) {
|
||||
t.Fatal("No state change so this should not be called")
|
||||
return false, nil, nil
|
||||
})
|
||||
changed, _, err = actorDiffFn(ctx, oldState.Key(), oldState.Key())
|
||||
require.NoError(t, err)
|
||||
require.False(t, changed)
|
||||
|
||||
// Test that OnDealStateChanged does not call the callback if the state has not changed
|
||||
diffDealStateFn := preds.OnDealStateChanged(func(context.Context, *adt.Array, *adt.Array) (bool, UserData, error) {
|
||||
t.Fatal("No state change so this should not be called")
|
||||
return false, nil, nil
|
||||
})
|
||||
marketState := createEmptyMarketState(t, store)
|
||||
changed, _, err = diffDealStateFn(ctx, marketState, marketState)
|
||||
require.NoError(t, err)
|
||||
require.False(t, changed)
|
||||
})
|
||||
|
||||
t.Run("deal state array predicate", func(t *testing.T) {
|
||||
preds := NewStatePredicates(api)
|
||||
diffArrFn := preds.OnStorageMarketActorChanged(preds.OnDealStateChanged(preds.OnDealStateAmtChanged()))
|
||||
|
||||
changed, _, err := diffArrFn(ctx, oldState.Key(), oldState.Key())
|
||||
require.NoError(t, err)
|
||||
require.False(t, changed)
|
||||
|
||||
changed, valArr, err := diffArrFn(ctx, oldState.Key(), newState.Key())
|
||||
require.NoError(t, err)
|
||||
require.True(t, changed)
|
||||
|
||||
changedDeals, ok := valArr.(*MarketDealStateChanges)
|
||||
require.True(t, ok)
|
||||
require.Len(t, changedDeals.Added, 1)
|
||||
require.Equal(t, abi.DealID(3), changedDeals.Added[0].ID)
|
||||
require.Equal(t, *newDeal3, changedDeals.Added[0].Deal)
|
||||
|
||||
require.Len(t, changedDeals.Removed, 1)
|
||||
|
||||
require.Len(t, changedDeals.Modified, 1)
|
||||
require.Equal(t, abi.DealID(1), changedDeals.Modified[0].ID)
|
||||
require.Equal(t, newDeal1, changedDeals.Modified[0].To)
|
||||
require.Equal(t, oldDeal1, changedDeals.Modified[0].From)
|
||||
|
||||
require.Equal(t, abi.DealID(2), changedDeals.Removed[0].ID)
|
||||
})
|
||||
|
||||
t.Run("deal proposal array predicate", func(t *testing.T) {
|
||||
preds := NewStatePredicates(api)
|
||||
diffArrFn := preds.OnStorageMarketActorChanged(preds.OnDealProposalChanged(preds.OnDealProposalAmtChanged()))
|
||||
changed, _, err := diffArrFn(ctx, oldState.Key(), oldState.Key())
|
||||
require.NoError(t, err)
|
||||
require.False(t, changed)
|
||||
|
||||
changed, valArr, err := diffArrFn(ctx, oldState.Key(), newState.Key())
|
||||
require.NoError(t, err)
|
||||
require.True(t, changed)
|
||||
|
||||
changedProps, ok := valArr.(*MarketDealProposalChanges)
|
||||
require.True(t, ok)
|
||||
require.Len(t, changedProps.Added, 1)
|
||||
require.Equal(t, abi.DealID(3), changedProps.Added[0].ID)
|
||||
require.Equal(t, *newProp3, changedProps.Added[0].Proposal)
|
||||
|
||||
// proposals cannot be modified -- no modified testing
|
||||
|
||||
require.Len(t, changedProps.Removed, 1)
|
||||
require.Equal(t, abi.DealID(2), changedProps.Removed[0].ID)
|
||||
require.Equal(t, *oldProp2, changedProps.Removed[0].Proposal)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMinerSectorChange(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
bs := bstore.NewBlockstore(ds_sync.MutexWrap(ds.NewMapDatastore()))
|
||||
store := cbornode.NewCborStore(bs)
|
||||
|
||||
nextID := uint64(0)
|
||||
nextIDAddrF := func() address.Address {
|
||||
defer func() { nextID++ }()
|
||||
return tutils.NewIDAddr(t, nextID)
|
||||
}
|
||||
|
||||
owner, worker := nextIDAddrF(), nextIDAddrF()
|
||||
si0 := newSectorOnChainInfo(0, tutils.MakeCID("0", &miner.SealedCIDPrefix), big.NewInt(0), abi.ChainEpoch(0), abi.ChainEpoch(10))
|
||||
si1 := newSectorOnChainInfo(1, tutils.MakeCID("1", &miner.SealedCIDPrefix), big.NewInt(1), abi.ChainEpoch(1), abi.ChainEpoch(11))
|
||||
si2 := newSectorOnChainInfo(2, tutils.MakeCID("2", &miner.SealedCIDPrefix), big.NewInt(2), abi.ChainEpoch(2), abi.ChainEpoch(11))
|
||||
oldMinerC := createMinerState(ctx, t, store, owner, worker, []miner.SectorOnChainInfo{si0, si1, si2})
|
||||
|
||||
si3 := newSectorOnChainInfo(3, tutils.MakeCID("3", &miner.SealedCIDPrefix), big.NewInt(3), abi.ChainEpoch(3), abi.ChainEpoch(12))
|
||||
// 0 delete
|
||||
// 1 extend
|
||||
// 2 same
|
||||
// 3 added
|
||||
si1Ext := si1
|
||||
si1Ext.Expiration++
|
||||
newMinerC := createMinerState(ctx, t, store, owner, worker, []miner.SectorOnChainInfo{si1Ext, si2, si3})
|
||||
|
||||
minerAddr := nextIDAddrF()
|
||||
oldState, err := mockTipset(minerAddr, 1)
|
||||
require.NoError(t, err)
|
||||
newState, err := mockTipset(minerAddr, 2)
|
||||
require.NoError(t, err)
|
||||
|
||||
api := newMockAPI(bs)
|
||||
api.setActor(oldState.Key(), &types.Actor{Head: oldMinerC})
|
||||
api.setActor(newState.Key(), &types.Actor{Head: newMinerC})
|
||||
|
||||
preds := NewStatePredicates(api)
|
||||
|
||||
minerDiffFn := preds.OnMinerActorChange(minerAddr, preds.OnMinerSectorChange())
|
||||
change, val, err := minerDiffFn(ctx, oldState.Key(), newState.Key())
|
||||
require.NoError(t, err)
|
||||
require.True(t, change)
|
||||
require.NotNil(t, val)
|
||||
|
||||
sectorChanges, ok := val.(*MinerSectorChanges)
|
||||
require.True(t, ok)
|
||||
|
||||
require.Equal(t, len(sectorChanges.Added), 1)
|
||||
require.Equal(t, 1, len(sectorChanges.Added))
|
||||
require.Equal(t, si3, sectorChanges.Added[0])
|
||||
|
||||
require.Equal(t, 1, len(sectorChanges.Removed))
|
||||
require.Equal(t, si0, sectorChanges.Removed[0])
|
||||
|
||||
require.Equal(t, 1, len(sectorChanges.Extended))
|
||||
require.Equal(t, si1, sectorChanges.Extended[0].From)
|
||||
require.Equal(t, si1Ext, sectorChanges.Extended[0].To)
|
||||
|
||||
change, val, err = minerDiffFn(ctx, oldState.Key(), oldState.Key())
|
||||
require.NoError(t, err)
|
||||
require.False(t, change)
|
||||
require.Nil(t, val)
|
||||
|
||||
change, val, err = minerDiffFn(ctx, newState.Key(), oldState.Key())
|
||||
require.NoError(t, err)
|
||||
require.True(t, change)
|
||||
require.NotNil(t, val)
|
||||
|
||||
sectorChanges, ok = val.(*MinerSectorChanges)
|
||||
require.True(t, ok)
|
||||
|
||||
require.Equal(t, 1, len(sectorChanges.Added))
|
||||
require.Equal(t, si0, sectorChanges.Added[0])
|
||||
|
||||
require.Equal(t, 1, len(sectorChanges.Removed))
|
||||
require.Equal(t, si3, sectorChanges.Removed[0])
|
||||
|
||||
require.Equal(t, 1, len(sectorChanges.Extended))
|
||||
require.Equal(t, si1, sectorChanges.Extended[0].To)
|
||||
require.Equal(t, si1Ext, sectorChanges.Extended[0].From)
|
||||
}
|
||||
|
||||
func mockTipset(minerAddr address.Address, timestamp uint64) (*types.TipSet, error) {
|
||||
return types.NewTipSet([]*types.BlockHeader{{
|
||||
Miner: minerAddr,
|
||||
Height: 5,
|
||||
ParentStateRoot: dummyCid,
|
||||
Messages: dummyCid,
|
||||
ParentMessageReceipts: dummyCid,
|
||||
BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS},
|
||||
BLSAggregate: &crypto.Signature{Type: crypto.SigTypeBLS},
|
||||
Timestamp: timestamp,
|
||||
}})
|
||||
}
|
||||
|
||||
func createMarketState(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, deals map[abi.DealID]*market.DealState, props map[abi.DealID]*market.DealProposal) cid.Cid {
|
||||
dealRootCid := createDealAMT(ctx, t, store, deals)
|
||||
propRootCid := createProposalAMT(ctx, t, store, props)
|
||||
|
||||
state := createEmptyMarketState(t, store)
|
||||
state.States = dealRootCid
|
||||
state.Proposals = propRootCid
|
||||
|
||||
stateC, err := store.Put(ctx, state)
|
||||
require.NoError(t, err)
|
||||
return stateC
|
||||
}
|
||||
|
||||
func createEmptyMarketState(t *testing.T, store *cbornode.BasicIpldStore) *market.State {
|
||||
emptyArrayCid, err := amt.NewAMT(store).Flush(context.TODO())
|
||||
require.NoError(t, err)
|
||||
emptyMap, err := store.Put(context.TODO(), hamt.NewNode(store, hamt.UseTreeBitWidth(5)))
|
||||
require.NoError(t, err)
|
||||
return market.ConstructState(emptyArrayCid, emptyMap, emptyMap)
|
||||
}
|
||||
|
||||
func createDealAMT(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, deals map[abi.DealID]*market.DealState) cid.Cid {
|
||||
root := amt.NewAMT(store)
|
||||
for dealID, dealState := range deals {
|
||||
err := root.Set(ctx, uint64(dealID), dealState)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
rootCid, err := root.Flush(ctx)
|
||||
require.NoError(t, err)
|
||||
return rootCid
|
||||
}
|
||||
|
||||
func createProposalAMT(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, props map[abi.DealID]*market.DealProposal) cid.Cid {
|
||||
root := amt.NewAMT(store)
|
||||
for dealID, prop := range props {
|
||||
err := root.Set(ctx, uint64(dealID), prop)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
rootCid, err := root.Flush(ctx)
|
||||
require.NoError(t, err)
|
||||
return rootCid
|
||||
}
|
||||
|
||||
func createMinerState(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, owner, worker address.Address, sectors []miner.SectorOnChainInfo) cid.Cid {
|
||||
rootCid := createSectorsAMT(ctx, t, store, sectors)
|
||||
|
||||
state := createEmptyMinerState(ctx, t, store, owner, worker)
|
||||
state.Sectors = rootCid
|
||||
|
||||
stateC, err := store.Put(ctx, state)
|
||||
require.NoError(t, err)
|
||||
return stateC
|
||||
}
|
||||
|
||||
func createEmptyMinerState(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, owner, worker address.Address) *miner.State {
|
||||
emptyArrayCid, err := amt.NewAMT(store).Flush(context.TODO())
|
||||
require.NoError(t, err)
|
||||
emptyMap, err := store.Put(context.TODO(), hamt.NewNode(store, hamt.UseTreeBitWidth(5)))
|
||||
require.NoError(t, err)
|
||||
|
||||
emptyDeadline, err := store.Put(context.TODO(), &miner.Deadline{
|
||||
Partitions: emptyArrayCid,
|
||||
ExpirationsEpochs: emptyArrayCid,
|
||||
PostSubmissions: abi.NewBitField(),
|
||||
EarlyTerminations: abi.NewBitField(),
|
||||
LiveSectors: 0,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
emptyDeadlines := miner.ConstructDeadlines(emptyDeadline)
|
||||
emptyDeadlinesCid, err := store.Put(context.Background(), emptyDeadlines)
|
||||
require.NoError(t, err)
|
||||
|
||||
minerInfo := emptyMap
|
||||
|
||||
state, err := miner.ConstructState(minerInfo, 123, emptyArrayCid, emptyMap, emptyDeadlinesCid)
|
||||
require.NoError(t, err)
|
||||
return state
|
||||
|
||||
}
|
||||
|
||||
func createSectorsAMT(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, sectors []miner.SectorOnChainInfo) cid.Cid {
|
||||
root := amt.NewAMT(store)
|
||||
for _, sector := range sectors {
|
||||
sector := sector
|
||||
err := root.Set(ctx, uint64(sector.SectorNumber), §or)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
rootCid, err := root.Flush(ctx)
|
||||
require.NoError(t, err)
|
||||
return rootCid
|
||||
}
|
||||
|
||||
// returns a unique SectorOnChainInfo with each invocation with SectorNumber set to `sectorNo`.
|
||||
func newSectorOnChainInfo(sectorNo abi.SectorNumber, sealed cid.Cid, weight big.Int, activation, expiration abi.ChainEpoch) miner.SectorOnChainInfo {
|
||||
info := newSectorPreCommitInfo(sectorNo, sealed, expiration)
|
||||
return miner.SectorOnChainInfo{
|
||||
SectorNumber: info.SectorNumber,
|
||||
SealProof: info.SealProof,
|
||||
SealedCID: info.SealedCID,
|
||||
DealIDs: info.DealIDs,
|
||||
Expiration: info.Expiration,
|
||||
|
||||
Activation: activation,
|
||||
DealWeight: weight,
|
||||
VerifiedDealWeight: weight,
|
||||
InitialPledge: big.Zero(),
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
sectorSealRandEpochValue = abi.ChainEpoch(1)
|
||||
)
|
||||
|
||||
// returns a unique SectorPreCommitInfo with each invocation with SectorNumber set to `sectorNo`.
|
||||
func newSectorPreCommitInfo(sectorNo abi.SectorNumber, sealed cid.Cid, expiration abi.ChainEpoch) *miner.SectorPreCommitInfo {
|
||||
return &miner.SectorPreCommitInfo{
|
||||
SealProof: abi.RegisteredSealProof_StackedDrg32GiBV1,
|
||||
SectorNumber: sectorNo,
|
||||
SealedCID: sealed,
|
||||
SealRandEpoch: sectorSealRandEpochValue,
|
||||
DealIDs: nil,
|
||||
Expiration: expiration,
|
||||
}
|
||||
}
|
@ -8,11 +8,11 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
func (e *calledEvents) CheckMsg(ctx context.Context, smsg types.ChainMsg, hnd CalledHandler) CheckFunc {
|
||||
func (me *messageEvents) CheckMsg(ctx context.Context, smsg types.ChainMsg, hnd MsgHandler) CheckFunc {
|
||||
msg := smsg.VMMessage()
|
||||
|
||||
return func(ts *types.TipSet) (done bool, more bool, err error) {
|
||||
fa, err := e.cs.StateGetActor(ctx, msg.From, ts.Key())
|
||||
fa, err := me.cs.StateGetActor(ctx, msg.From, ts.Key())
|
||||
if err != nil {
|
||||
return false, true, err
|
||||
}
|
||||
@ -22,7 +22,7 @@ func (e *calledEvents) CheckMsg(ctx context.Context, smsg types.ChainMsg, hnd Ca
|
||||
return false, true, nil
|
||||
}
|
||||
|
||||
rec, err := e.cs.StateGetReceipt(ctx, smsg.VMMessage().Cid(), ts.Key())
|
||||
rec, err := me.cs.StateGetReceipt(ctx, smsg.VMMessage().Cid(), ts.Key())
|
||||
if err != nil {
|
||||
return false, true, xerrors.Errorf("getting receipt in CheckMsg: %w", err)
|
||||
}
|
||||
@ -33,12 +33,12 @@ func (e *calledEvents) CheckMsg(ctx context.Context, smsg types.ChainMsg, hnd Ca
|
||||
}
|
||||
}
|
||||
|
||||
func (e *calledEvents) MatchMsg(inmsg *types.Message) MatchFunc {
|
||||
return func(msg *types.Message) (bool, error) {
|
||||
func (me *messageEvents) MatchMsg(inmsg *types.Message) MsgMatchFunc {
|
||||
return func(msg *types.Message) (matchOnce bool, matched bool, err error) {
|
||||
if msg.From == inmsg.From && msg.Nonce == inmsg.Nonce && !inmsg.Equals(msg) {
|
||||
return false, xerrors.Errorf("matching msg %s from %s, nonce %d: got duplicate origin/nonce msg %d", inmsg.Cid(), inmsg.From, inmsg.Nonce, msg.Nonce)
|
||||
return true, false, xerrors.Errorf("matching msg %s from %s, nonce %d: got duplicate origin/nonce msg %d", inmsg.Cid(), inmsg.From, inmsg.Nonce, msg.Nonce)
|
||||
}
|
||||
|
||||
return inmsg.Equals(msg), nil
|
||||
return true, inmsg.Equals(msg), nil
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
commcid "github.com/filecoin-project/go-fil-commcid"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
saminer "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
@ -45,6 +44,10 @@ var log = logging.Logger("gen")
|
||||
|
||||
const msgsPerBlock = 20
|
||||
|
||||
var ValidWpostForTesting = []abi.PoStProof{{
|
||||
ProofBytes: []byte("valid proof"),
|
||||
}}
|
||||
|
||||
type ChainGen struct {
|
||||
msgsPerBlock int
|
||||
|
||||
@ -89,8 +92,8 @@ func (m mybs) Get(c cid.Cid) (block.Block, error) {
|
||||
}
|
||||
|
||||
func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
saminer.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
|
||||
abi.RegisteredProof_StackedDRG2KiBSeal: {},
|
||||
saminer.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||
}
|
||||
|
||||
mr := repo.NewMemory(nil)
|
||||
@ -141,7 +144,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
genm1, k1, err := seed.PreSeal(maddr1, abi.RegisteredProof_StackedDRG2KiBPoSt, 0, numSectors, m1temp, []byte("some randomness"), nil)
|
||||
genm1, k1, err := seed.PreSeal(maddr1, abi.RegisteredSealProof_StackedDrg2KiBV1, 0, numSectors, m1temp, []byte("some randomness"), nil, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -153,7 +156,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
genm2, k2, err := seed.PreSeal(maddr2, abi.RegisteredProof_StackedDRG2KiBPoSt, 0, numSectors, m2temp, []byte("some randomness"), nil)
|
||||
genm2, k2, err := seed.PreSeal(maddr2, abi.RegisteredSealProof_StackedDrg2KiBV1, 0, numSectors, m2temp, []byte("some randomness"), nil, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -173,12 +176,12 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
Accounts: []genesis.Actor{
|
||||
{
|
||||
Type: genesis.TAccount,
|
||||
Balance: types.FromFil(40000),
|
||||
Balance: types.FromFil(20_000_000),
|
||||
Meta: (&genesis.AccountMeta{Owner: mk1}).ActorMeta(),
|
||||
},
|
||||
{
|
||||
Type: genesis.TAccount,
|
||||
Balance: types.FromFil(40000),
|
||||
Balance: types.FromFil(20_000_000),
|
||||
Meta: (&genesis.AccountMeta{Owner: mk2}).ActorMeta(),
|
||||
},
|
||||
{
|
||||
@ -192,7 +195,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
*genm2,
|
||||
},
|
||||
NetworkName: "",
|
||||
Timestamp: uint64(time.Now().Add(-500 * build.BlockDelay * time.Second).Unix()),
|
||||
Timestamp: uint64(build.Clock.Now().Add(-500 * time.Duration(build.BlockDelaySecs) * time.Second).Unix()),
|
||||
}
|
||||
|
||||
genb, err := genesis2.MakeGenesisBlock(context.TODO(), bs, sys, tpl)
|
||||
@ -219,7 +222,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
miners := []address.Address{maddr1, maddr2}
|
||||
|
||||
beac := beacon.NewMockBeacon(time.Second)
|
||||
//beac, err := drand.NewDrandBeacon(tpl.Timestamp, build.BlockDelay)
|
||||
//beac, err := drand.NewDrandBeacon(tpl.Timestamp, build.BlockDelaySecs)
|
||||
//if err != nil {
|
||||
//return nil, xerrors.Errorf("creating drand beacon: %w", err)
|
||||
//}
|
||||
@ -280,7 +283,7 @@ func (cg *ChainGen) GenesisCar() ([]byte, error) {
|
||||
|
||||
func CarWalkFunc(nd format.Node) (out []*format.Link, err error) {
|
||||
for _, link := range nd.Links() {
|
||||
if link.Cid.Prefix().MhType == uint64(commcid.FC_SEALED_V1) || link.Cid.Prefix().MhType == uint64(commcid.FC_UNSEALED_V1) {
|
||||
if link.Cid.Prefix().Codec == cid.FilCommitmentSealed || link.Cid.Prefix().Codec == cid.FilCommitmentUnsealed {
|
||||
continue
|
||||
}
|
||||
out = append(out, link)
|
||||
@ -410,7 +413,7 @@ func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, vrfticke
|
||||
if cg.Timestamper != nil {
|
||||
ts = cg.Timestamper(parents, height-parents.Height())
|
||||
} else {
|
||||
ts = parents.MinTimestamp() + uint64((height-parents.Height())*build.BlockDelay)
|
||||
ts = parents.MinTimestamp() + uint64(height-parents.Height())*build.BlockDelaySecs
|
||||
}
|
||||
|
||||
fblk, err := MinerCreateBlock(context.TODO(), cg.sm, cg.w, &api.BlockTemplate{
|
||||
@ -434,7 +437,8 @@ func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, vrfticke
|
||||
// ResyncBankerNonce is used for dealing with messages made when
|
||||
// simulating forks
|
||||
func (cg *ChainGen) ResyncBankerNonce(ts *types.TipSet) error {
|
||||
act, err := cg.sm.GetActor(cg.banker, ts)
|
||||
var act types.Actor
|
||||
err := cg.sm.WithParentState(ts, cg.sm.WithActor(cg.banker, stmgr.GetActor(&act)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -464,7 +468,7 @@ func getRandomMessages(cg *ChainGen) ([]*types.SignedMessage, error) {
|
||||
|
||||
Method: 0,
|
||||
|
||||
GasLimit: 10000,
|
||||
GasLimit: 100_000_000,
|
||||
GasPrice: types.NewInt(0),
|
||||
}
|
||||
|
||||
@ -533,9 +537,7 @@ func (wpp *wppProvider) GenerateCandidates(ctx context.Context, _ abi.PoStRandom
|
||||
}
|
||||
|
||||
func (wpp *wppProvider) ComputeProof(context.Context, []abi.SectorInfo, abi.PoStRandomness) ([]abi.PoStProof, error) {
|
||||
return []abi.PoStProof{{
|
||||
ProofBytes: []byte("valid proof"),
|
||||
}}, nil
|
||||
return ValidWpostForTesting, nil
|
||||
}
|
||||
|
||||
func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch,
|
||||
@ -556,12 +558,14 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch,
|
||||
return nil, xerrors.Errorf("failed to compute VRF: %w", err)
|
||||
}
|
||||
|
||||
// TODO: wire in real power
|
||||
if !types.IsTicketWinner(vrfout, mbi.MinerPower, mbi.NetworkPower) {
|
||||
ep := &types.ElectionProof{VRFProof: vrfout}
|
||||
j := ep.ComputeWinCount(mbi.MinerPower, mbi.NetworkPower)
|
||||
ep.WinCount = j
|
||||
if j < 1 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &types.ElectionProof{VRFProof: vrfout}, nil
|
||||
return ep, nil
|
||||
}
|
||||
|
||||
type SignFunc func(context.Context, address.Address, []byte) (*crypto.Signature, error)
|
||||
@ -611,6 +615,6 @@ func (m genFakeVerifier) VerifyWindowPoSt(ctx context.Context, info abi.WindowPo
|
||||
panic("not supported")
|
||||
}
|
||||
|
||||
func (m genFakeVerifier) GenerateWinningPoStSectorChallenge(ctx context.Context, proof abi.RegisteredProof, id abi.ActorID, randomness abi.PoStRandomness, u uint64) ([]uint64, error) {
|
||||
func (m genFakeVerifier) GenerateWinningPoStSectorChallenge(ctx context.Context, proof abi.RegisteredPoStProof, id abi.ActorID, randomness abi.PoStRandomness, u uint64) ([]uint64, error) {
|
||||
panic("not supported")
|
||||
}
|
||||
|
@ -14,8 +14,8 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
|
||||
abi.RegisteredProof_StackedDRG2KiBSeal: {},
|
||||
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||
}
|
||||
power.ConsensusMinerMinPower = big.NewInt(2048)
|
||||
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
||||
@ -39,8 +39,8 @@ func testGeneration(t testing.TB, n int, msgs int, sectors int) {
|
||||
}
|
||||
|
||||
func TestChainGeneration(t *testing.T) {
|
||||
testGeneration(t, 10, 20, 1)
|
||||
testGeneration(t, 10, 20, 25)
|
||||
t.Run("10-20-1", func(t *testing.T) { testGeneration(t, 10, 20, 1) })
|
||||
t.Run("10-20-25", func(t *testing.T) { testGeneration(t, 10, 20, 25) })
|
||||
}
|
||||
|
||||
func BenchmarkChainGeneration(b *testing.B) {
|
||||
|
@ -6,10 +6,13 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-amt-ipld/v2"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/account"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
@ -59,8 +62,15 @@ The process:
|
||||
- power.CreateMiner, set msg value to PowerBalance
|
||||
- market.AddFunds with correct value
|
||||
- market.PublishDeals for related sectors
|
||||
- Set precommits
|
||||
- Commit presealed sectors
|
||||
- Set network power in the power actor to what we'll have after genesis creation
|
||||
- Recreate reward actor state with the right power
|
||||
- For each precommitted sector
|
||||
- Get deal weight
|
||||
- Calculate QA Power
|
||||
- Remove fake power from the power actor
|
||||
- Calculate pledge
|
||||
- Precommit
|
||||
- Confirm valid
|
||||
|
||||
Data Types:
|
||||
|
||||
@ -131,7 +141,8 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
||||
}
|
||||
|
||||
// Setup reward
|
||||
rewact, err := SetupRewardActor(bs)
|
||||
// RewardActor's state is overrwritten by SetupStorageMiners
|
||||
rewact, err := SetupRewardActor(bs, big.Zero())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("setup init actor: %w", err)
|
||||
}
|
||||
@ -189,8 +200,8 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
||||
|
||||
// Create accounts
|
||||
for id, info := range template.Accounts {
|
||||
if info.Type != genesis.TAccount {
|
||||
return nil, xerrors.New("unsupported account type") // TODO: msigs
|
||||
if info.Type != genesis.TAccount && info.Type != genesis.TMultisig {
|
||||
return nil, xerrors.New("unsupported account type")
|
||||
}
|
||||
|
||||
ida, err := address.NewIDAddress(uint64(AccountStart + id))
|
||||
@ -198,24 +209,57 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ainfo genesis.AccountMeta
|
||||
if err := json.Unmarshal(info.Meta, &ainfo); err != nil {
|
||||
return nil, xerrors.Errorf("unmarshaling account meta: %w", err)
|
||||
// var newAddress address.Address
|
||||
|
||||
if info.Type == genesis.TAccount {
|
||||
var ainfo genesis.AccountMeta
|
||||
if err := json.Unmarshal(info.Meta, &ainfo); err != nil {
|
||||
return nil, xerrors.Errorf("unmarshaling account meta: %w", err)
|
||||
}
|
||||
st, err := cst.Put(ctx, &account.State{Address: ainfo.Owner})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = state.SetActor(ida, &types.Actor{
|
||||
Code: builtin.AccountActorCodeID,
|
||||
Balance: info.Balance,
|
||||
Head: st,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("setting account from actmap: %w", err)
|
||||
}
|
||||
} else if info.Type == genesis.TMultisig {
|
||||
var ainfo genesis.MultisigMeta
|
||||
if err := json.Unmarshal(info.Meta, &ainfo); err != nil {
|
||||
return nil, xerrors.Errorf("unmarshaling account meta: %w", err)
|
||||
}
|
||||
|
||||
pending, err := adt.MakeEmptyMap(adt.WrapStore(ctx, cst)).Root()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to create empty map: %v", err)
|
||||
}
|
||||
|
||||
st, err := cst.Put(ctx, &multisig.State{
|
||||
Signers: ainfo.Signers,
|
||||
NumApprovalsThreshold: uint64(ainfo.Threshold),
|
||||
StartEpoch: abi.ChainEpoch(ainfo.VestingStart),
|
||||
UnlockDuration: abi.ChainEpoch(ainfo.VestingDuration),
|
||||
PendingTxns: pending,
|
||||
InitialBalance: info.Balance,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = state.SetActor(ida, &types.Actor{
|
||||
Code: builtin.MultisigActorCodeID,
|
||||
Balance: info.Balance,
|
||||
Head: st,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("setting account from actmap: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
st, err := cst.Put(ctx, &account.State{Address: ainfo.Owner})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = state.SetActor(ida, &types.Actor{
|
||||
Code: builtin.AccountActorCodeID,
|
||||
Balance: info.Balance,
|
||||
Head: st,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("setting account from actmap: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
vregroot, err := address.NewIDAddress(80)
|
||||
@ -281,7 +325,12 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci
|
||||
}
|
||||
}
|
||||
|
||||
return vm.Flush(ctx)
|
||||
st, err := vm.Flush(ctx)
|
||||
if err != nil {
|
||||
return cid.Cid{}, xerrors.Errorf("vm flush: %w", err)
|
||||
}
|
||||
|
||||
return st, nil
|
||||
}
|
||||
|
||||
func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys runtime.Syscalls, template genesis.Template) (*GenesisBootstrap, error) {
|
||||
@ -306,7 +355,7 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys runtime.Sys
|
||||
|
||||
stateroot, err = SetupStorageMiners(ctx, cs, stateroot, template.Miners)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("setup storage miners failed: %w", err)
|
||||
return nil, xerrors.Errorf("setup miners failed: %w", err)
|
||||
}
|
||||
|
||||
cst := cbor.NewCborStore(bs)
|
||||
|
@ -19,10 +19,10 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
@ -56,6 +56,14 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
return cid.Undef, xerrors.New("no genesis miners")
|
||||
}
|
||||
|
||||
minerInfos := make([]struct {
|
||||
maddr address.Address
|
||||
|
||||
presealExp abi.ChainEpoch
|
||||
|
||||
dealIDs []abi.DealID
|
||||
}, len(miners))
|
||||
|
||||
for i, m := range miners {
|
||||
// Create miner through power actor
|
||||
i := i
|
||||
@ -66,7 +74,6 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
var maddr address.Address
|
||||
{
|
||||
constructorParams := &power.CreateMinerParams{
|
||||
Owner: m.Worker,
|
||||
@ -90,13 +97,20 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
if ma.IDAddress != expma {
|
||||
return cid.Undef, xerrors.Errorf("miner assigned wrong address: %s != %s", ma.IDAddress, expma)
|
||||
}
|
||||
maddr = ma.IDAddress
|
||||
minerInfos[i].maddr = ma.IDAddress
|
||||
|
||||
err = vm.MutateState(ctx, minerInfos[i].maddr, func(cst cbor.IpldStore, st *miner.State) error {
|
||||
maxPeriods := miner.MaxSectorExpirationExtension / miner.WPoStProvingPeriod
|
||||
minerInfos[i].presealExp = (maxPeriods-1)*miner.WPoStProvingPeriod + st.ProvingPeriodStart - 1
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Add market funds
|
||||
|
||||
{
|
||||
params := mustEnc(&maddr)
|
||||
params := mustEnc(&minerInfos[i].maddr)
|
||||
_, err := doExecValue(ctx, vm, builtin.StorageMarketActorAddr, m.Worker, m.MarketBalance, builtin.MethodsMarket.AddBalance, params)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to create genesis miner: %w", err)
|
||||
@ -112,7 +126,6 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
|
||||
// Publish preseal deals
|
||||
|
||||
var dealIDs []abi.DealID
|
||||
{
|
||||
publish := func(params *market.PublishStorageDealsParams) error {
|
||||
fmt.Printf("publishing %d storage deals on miner %s with worker %s\n", len(params.Deals), params.Deals[0].Proposal.Provider, m.Worker)
|
||||
@ -126,13 +139,14 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
return xerrors.Errorf("unmarsahling publishStorageDeals result: %w", err)
|
||||
}
|
||||
|
||||
dealIDs = append(dealIDs, ids.IDs...)
|
||||
minerInfos[i].dealIDs = append(minerInfos[i].dealIDs, ids.IDs...)
|
||||
return nil
|
||||
}
|
||||
|
||||
params := &market.PublishStorageDealsParams{}
|
||||
for _, preseal := range m.Sectors {
|
||||
preseal.Deal.VerifiedDeal = true
|
||||
preseal.Deal.EndEpoch = minerInfos[i].presealExp
|
||||
params.Deals = append(params.Deals, market.ClientDealProposal{
|
||||
Proposal: preseal.Deal,
|
||||
ClientSignature: crypto.Signature{Type: crypto.SigTypeBLS}, // TODO: do we want to sign these? Or do we want to fake signatures for genesis setup?
|
||||
@ -153,95 +167,121 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Commit sectors
|
||||
for pi, preseal := range m.Sectors {
|
||||
preseal := preseal
|
||||
// TODO: Maybe check seal (Can just be snark inputs, doesn't go into the genesis file)
|
||||
// adjust total network power for equal pledge per sector
|
||||
rawPow, qaPow := big.NewInt(0), big.NewInt(0)
|
||||
{
|
||||
for i, m := range miners {
|
||||
for pi := range m.Sectors {
|
||||
rawPow = types.BigAdd(rawPow, types.NewInt(uint64(m.SectorSize)))
|
||||
|
||||
// check deals, get dealWeight
|
||||
var dealWeight market.VerifyDealsOnSectorProveCommitReturn
|
||||
{
|
||||
params := &market.VerifyDealsOnSectorProveCommitParams{
|
||||
DealIDs: []abi.DealID{dealIDs[pi]},
|
||||
SectorExpiry: preseal.Deal.EndEpoch,
|
||||
}
|
||||
|
||||
ret, err := doExecValue(ctx, vm, builtin.StorageMarketActorAddr, maddr, big.Zero(), builtin.MethodsMarket.VerifyDealsOnSectorProveCommit, mustEnc(params))
|
||||
dweight, err := dealWeight(ctx, vm, minerInfos[i].maddr, []abi.DealID{minerInfos[i].dealIDs[pi]}, 0, minerInfos[i].presealExp)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to verify preseal deals miner: %w", err)
|
||||
}
|
||||
if err := dealWeight.UnmarshalCBOR(bytes.NewReader(ret)); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("unmarshaling market onProveCommit result: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// update power claims
|
||||
{
|
||||
err = vm.MutateState(ctx, builtin.StoragePowerActorAddr, func(cst cbor.IpldStore, st *power.State) error {
|
||||
weight := &power.SectorStorageWeightDesc{
|
||||
SectorSize: m.SectorSize,
|
||||
Duration: preseal.Deal.Duration(),
|
||||
DealWeight: dealWeight.DealWeight,
|
||||
VerifiedDealWeight: dealWeight.VerifiedDealWeight,
|
||||
}
|
||||
|
||||
qapower := power.QAPowerForWeight(weight)
|
||||
|
||||
err := st.AddToClaim(&state.AdtStore{cst}, maddr, types.NewInt(uint64(weight.SectorSize)), qapower)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("add to claim: %w", err)
|
||||
}
|
||||
fmt.Println("Added weight to claim: ", st.TotalRawBytePower, st.TotalQualityAdjPower)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("register power claim in power actor: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Put sectors to miner sector sets
|
||||
{
|
||||
newSectorInfo := &miner.SectorOnChainInfo{
|
||||
Info: miner.SectorPreCommitInfo{
|
||||
RegisteredProof: preseal.ProofType,
|
||||
SectorNumber: preseal.SectorID,
|
||||
SealedCID: preseal.CommR,
|
||||
SealRandEpoch: 0,
|
||||
DealIDs: []abi.DealID{dealIDs[pi]},
|
||||
Expiration: preseal.Deal.EndEpoch,
|
||||
},
|
||||
ActivationEpoch: 0,
|
||||
DealWeight: dealWeight.DealWeight,
|
||||
VerifiedDealWeight: dealWeight.VerifiedDealWeight,
|
||||
return cid.Undef, xerrors.Errorf("getting deal weight: %w", err)
|
||||
}
|
||||
|
||||
err = vm.MutateState(ctx, maddr, func(cst cbor.IpldStore, st *miner.State) error {
|
||||
store := &state.AdtStore{cst}
|
||||
sectorWeight := miner.QAPowerForWeight(m.SectorSize, minerInfos[i].presealExp, dweight.DealWeight, dweight.VerifiedDealWeight)
|
||||
|
||||
if err = st.PutSector(store, newSectorInfo); err != nil {
|
||||
return xerrors.Errorf("failed to put sector: %v", err)
|
||||
}
|
||||
|
||||
if err := st.AddNewSectors(newSectorInfo.Info.SectorNumber); err != nil {
|
||||
return xerrors.Errorf("failed to add NewSector: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Cid{}, xerrors.Errorf("put to sset: %w", err)
|
||||
}
|
||||
qaPow = types.BigAdd(qaPow, sectorWeight)
|
||||
}
|
||||
}
|
||||
|
||||
err = vm.MutateState(ctx, builtin.StoragePowerActorAddr, func(cst cbor.IpldStore, st *power.State) error {
|
||||
st.TotalQualityAdjPower = qaPow
|
||||
st.TotalRawBytePower = rawPow
|
||||
|
||||
st.ThisEpochQualityAdjPower = qaPow
|
||||
st.ThisEpochRawBytePower = rawPow
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("mutating state: %w", err)
|
||||
}
|
||||
|
||||
err = vm.MutateState(ctx, builtin.RewardActorAddr, func(sct cbor.IpldStore, st *reward.State) error {
|
||||
st = reward.ConstructState(qaPow)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: to avoid division by zero, we set the initial power actor power to 1, this adjusts that back down so the accounting is accurate.
|
||||
for i, m := range miners {
|
||||
// Commit sectors
|
||||
{
|
||||
for pi, preseal := range m.Sectors {
|
||||
params := &miner.SectorPreCommitInfo{
|
||||
SealProof: preseal.ProofType,
|
||||
SectorNumber: preseal.SectorID,
|
||||
SealedCID: preseal.CommR,
|
||||
SealRandEpoch: -1,
|
||||
DealIDs: []abi.DealID{minerInfos[i].dealIDs[pi]},
|
||||
Expiration: minerInfos[i].presealExp, // TODO: Allow setting externally!
|
||||
}
|
||||
|
||||
dweight, err := dealWeight(ctx, vm, minerInfos[i].maddr, params.DealIDs, 0, minerInfos[i].presealExp)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting deal weight: %w", err)
|
||||
}
|
||||
|
||||
sectorWeight := miner.QAPowerForWeight(m.SectorSize, minerInfos[i].presealExp, dweight.DealWeight, dweight.VerifiedDealWeight)
|
||||
|
||||
// we've added fake power for this sector above, remove it now
|
||||
err = vm.MutateState(ctx, builtin.StoragePowerActorAddr, func(cst cbor.IpldStore, st *power.State) error {
|
||||
st.TotalQualityAdjPower = types.BigSub(st.TotalQualityAdjPower, sectorWeight)
|
||||
st.TotalRawBytePower = types.BigSub(st.TotalRawBytePower, types.NewInt(uint64(m.SectorSize)))
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("removing fake power: %w", err)
|
||||
}
|
||||
|
||||
epochReward, err := currentEpochBlockReward(ctx, vm, minerInfos[i].maddr)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting current epoch reward: %w", err)
|
||||
}
|
||||
|
||||
tpow, err := currentTotalPower(ctx, vm, minerInfos[i].maddr)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting current total power: %w", err)
|
||||
}
|
||||
|
||||
pledge := miner.InitialPledgeForPower(sectorWeight, tpow.QualityAdjPower, epochReward.ThisEpochBaselinePower, tpow.PledgeCollateral, epochReward.ThisEpochReward, circSupply(ctx, vm, minerInfos[i].maddr))
|
||||
fmt.Println(types.FIL(pledge))
|
||||
_, err = doExecValue(ctx, vm, minerInfos[i].maddr, m.Worker, pledge, builtin.MethodsMiner.PreCommitSector, mustEnc(params))
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to confirm presealed sectors: %w", err)
|
||||
}
|
||||
|
||||
// Commit one-by-one, otherwise pledge math tends to explode
|
||||
confirmParams := &builtin.ConfirmSectorProofsParams{
|
||||
Sectors: []abi.SectorNumber{preseal.SectorID},
|
||||
}
|
||||
|
||||
_, err = doExecValue(ctx, vm, minerInfos[i].maddr, builtin.StoragePowerActorAddr, big.Zero(), builtin.MethodsMiner.ConfirmSectorProofsValid, mustEnc(confirmParams))
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to confirm presealed sectors: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sanity-check total network power
|
||||
err = vm.MutateState(ctx, builtin.StoragePowerActorAddr, func(cst cbor.IpldStore, st *power.State) error {
|
||||
st.TotalQualityAdjPower = big.Sub(st.TotalQualityAdjPower, big.NewInt(1))
|
||||
if !st.TotalRawBytePower.Equals(rawPow) {
|
||||
return xerrors.Errorf("st.TotalRawBytePower doesn't match previously calculated rawPow")
|
||||
}
|
||||
|
||||
if !st.TotalQualityAdjPower.Equals(qaPow) {
|
||||
return xerrors.Errorf("st.TotalQualityAdjPower doesn't match previously calculated qaPow")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("mutating state: %w", err)
|
||||
}
|
||||
|
||||
// TODO: Should we re-ConstructState for the reward actor using rawPow as currRealizedPower here?
|
||||
|
||||
c, err := vm.Flush(ctx)
|
||||
if err != nil {
|
||||
@ -258,3 +298,65 @@ func (fr *fakeRand) GetRandomness(ctx context.Context, personalization crypto.Do
|
||||
_, _ = rand.New(rand.NewSource(int64(randEpoch))).Read(out)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func currentTotalPower(ctx context.Context, vm *vm.VM, maddr address.Address) (*power.CurrentTotalPowerReturn, error) {
|
||||
pwret, err := doExecValue(ctx, vm, builtin.StoragePowerActorAddr, maddr, big.Zero(), builtin.MethodsPower.CurrentTotalPower, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var pwr power.CurrentTotalPowerReturn
|
||||
if err := pwr.UnmarshalCBOR(bytes.NewReader(pwret)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pwr, nil
|
||||
}
|
||||
|
||||
func dealWeight(ctx context.Context, vm *vm.VM, maddr address.Address, dealIDs []abi.DealID, sectorStart, sectorExpiry abi.ChainEpoch) (market.VerifyDealsForActivationReturn, error) {
|
||||
params := &market.VerifyDealsForActivationParams{
|
||||
DealIDs: dealIDs,
|
||||
SectorStart: sectorStart,
|
||||
SectorExpiry: sectorExpiry,
|
||||
}
|
||||
|
||||
var dealWeights market.VerifyDealsForActivationReturn
|
||||
ret, err := doExecValue(ctx, vm,
|
||||
builtin.StorageMarketActorAddr,
|
||||
maddr,
|
||||
abi.NewTokenAmount(0),
|
||||
builtin.MethodsMarket.VerifyDealsForActivation,
|
||||
mustEnc(params),
|
||||
)
|
||||
if err != nil {
|
||||
return market.VerifyDealsForActivationReturn{}, err
|
||||
}
|
||||
if err := dealWeights.UnmarshalCBOR(bytes.NewReader(ret)); err != nil {
|
||||
return market.VerifyDealsForActivationReturn{}, err
|
||||
}
|
||||
|
||||
return dealWeights, nil
|
||||
}
|
||||
|
||||
func currentEpochBlockReward(ctx context.Context, vm *vm.VM, maddr address.Address) (*reward.ThisEpochRewardReturn, error) {
|
||||
rwret, err := doExecValue(ctx, vm, builtin.RewardActorAddr, maddr, big.Zero(), builtin.MethodsReward.ThisEpochReward, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var epochReward reward.ThisEpochRewardReturn
|
||||
if err := epochReward.UnmarshalCBOR(bytes.NewReader(rwret)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &epochReward, nil
|
||||
}
|
||||
|
||||
func circSupply(ctx context.Context, vmi *vm.VM, maddr address.Address) abi.TokenAmount {
|
||||
unsafeVM := &vm.UnsafeVM{VM: vmi}
|
||||
rt := unsafeVM.MakeRuntime(ctx, &types.Message{
|
||||
GasLimit: 1_000_000_000,
|
||||
From: maddr,
|
||||
}, maddr, 0, 0, 0)
|
||||
|
||||
return rt.TotalFilCircSupply()
|
||||
}
|
||||
|
@ -30,6 +30,10 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi
|
||||
amap := hamt.NewNode(cst, hamt.UseTreeBitWidth(5)) // TODO: use spec adt map
|
||||
|
||||
for i, a := range initialActors {
|
||||
if a.Type == genesis.TMultisig {
|
||||
continue
|
||||
}
|
||||
|
||||
if a.Type != genesis.TAccount {
|
||||
return nil, xerrors.Errorf("unsupported account type: %s", a.Type) // TODO: Support msig (skip here)
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package genesis
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
@ -11,11 +13,10 @@ import (
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
)
|
||||
|
||||
func SetupRewardActor(bs bstore.Blockstore) (*types.Actor, error) {
|
||||
func SetupRewardActor(bs bstore.Blockstore, qaPower big.Int) (*types.Actor, error) {
|
||||
cst := cbor.NewCborStore(bs)
|
||||
|
||||
st := reward.ConstructState()
|
||||
st.LastPerEpochReward = types.FromFil(100)
|
||||
st := reward.ConstructState(qaPower)
|
||||
|
||||
hcid, err := cst.Put(context.TODO(), st)
|
||||
if err != nil {
|
||||
|
@ -23,14 +23,17 @@ func SetupStoragePowerActor(bs bstore.Blockstore) (*types.Actor, error) {
|
||||
}
|
||||
|
||||
sms := &power.State{
|
||||
TotalRawBytePower: big.NewInt(0),
|
||||
TotalQualityAdjPower: big.NewInt(1), // TODO: has to be 1 initially to avoid div by zero. Kinda annoying, should find a way to fix
|
||||
TotalPledgeCollateral: big.NewInt(0),
|
||||
MinerCount: 0,
|
||||
CronEventQueue: emptyhamt,
|
||||
LastEpochTick: 0,
|
||||
Claims: emptyhamt,
|
||||
NumMinersMeetingMinPower: 0,
|
||||
TotalRawBytePower: big.NewInt(0),
|
||||
TotalBytesCommitted: big.NewInt(0),
|
||||
TotalQualityAdjPower: big.NewInt(0),
|
||||
TotalQABytesCommitted: big.NewInt(0),
|
||||
TotalPledgeCollateral: big.NewInt(0),
|
||||
MinerCount: 0,
|
||||
MinerAboveMinPowerCount: 0,
|
||||
CronEventQueue: emptyhamt,
|
||||
FirstCronEpoch: 0,
|
||||
Claims: emptyhamt,
|
||||
ProofValidationBatch: nil,
|
||||
}
|
||||
|
||||
stcid, err := cst.Put(ctx, sms)
|
||||
|
@ -150,6 +150,17 @@ func aggregateSignatures(sigs []crypto.Signature) (*crypto.Signature, error) {
|
||||
}
|
||||
|
||||
aggSig := bls.Aggregate(blsSigs)
|
||||
if aggSig == nil {
|
||||
if len(sigs) > 0 {
|
||||
return nil, xerrors.Errorf("bls.Aggregate returned nil with %d signatures", len(sigs))
|
||||
}
|
||||
|
||||
return &crypto.Signature{
|
||||
Type: crypto.SigTypeBLS,
|
||||
Data: new(bls.Signature)[:],
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &crypto.Signature{
|
||||
Type: crypto.SigTypeBLS,
|
||||
Data: aggSig[:],
|
||||
|
@ -66,13 +66,11 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
|
||||
}
|
||||
|
||||
smsg, err := fm.mpool.MpoolPushMessage(ctx, &types.Message{
|
||||
To: builtin.StorageMarketActorAddr,
|
||||
From: wallet,
|
||||
Value: toAdd,
|
||||
GasPrice: types.NewInt(0),
|
||||
GasLimit: 1000000,
|
||||
Method: builtin.MethodsMarket.AddBalance,
|
||||
Params: params,
|
||||
To: builtin.StorageMarketActorAddr,
|
||||
From: wallet,
|
||||
Value: toAdd,
|
||||
Method: builtin.MethodsMarket.AddBalance,
|
||||
Params: params,
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
|
@ -23,12 +23,15 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
|
||||
"github.com/raulk/clock"
|
||||
)
|
||||
|
||||
var log = logging.Logger("messagepool")
|
||||
@ -66,7 +69,7 @@ type MessagePool struct {
|
||||
lk sync.Mutex
|
||||
|
||||
closer chan struct{}
|
||||
repubTk *time.Ticker
|
||||
repubTk *clock.Ticker
|
||||
|
||||
localAddrs map[address.Address]struct{}
|
||||
|
||||
@ -162,7 +165,8 @@ func (mpp *mpoolProvider) PubSubPublish(k string, v []byte) error {
|
||||
}
|
||||
|
||||
func (mpp *mpoolProvider) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
|
||||
return mpp.sm.GetActor(addr, ts)
|
||||
var act types.Actor
|
||||
return &act, mpp.sm.WithParentState(ts, mpp.sm.WithActor(addr, stmgr.GetActor(&act)))
|
||||
}
|
||||
|
||||
func (mpp *mpoolProvider) StateAccountKey(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
@ -187,7 +191,7 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa
|
||||
|
||||
mp := &MessagePool{
|
||||
closer: make(chan struct{}),
|
||||
repubTk: time.NewTicker(build.BlockDelay * 10 * time.Second),
|
||||
repubTk: build.Clock.Ticker(time.Duration(build.BlockDelaySecs) * 10 * time.Second),
|
||||
localAddrs: make(map[address.Address]struct{}),
|
||||
pending: make(map[address.Address]*msgSet),
|
||||
minGasPrice: types.NewInt(0),
|
||||
@ -868,17 +872,3 @@ func (mp *MessagePool) loadLocal() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const MinGasPrice = 0
|
||||
|
||||
func (mp *MessagePool) EstimateGasPrice(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
// TODO: something smarter obviously
|
||||
switch nblocksincl {
|
||||
case 0:
|
||||
return types.NewInt(MinGasPrice + 2), nil
|
||||
case 1:
|
||||
return types.NewInt(MinGasPrice + 1), nil
|
||||
default:
|
||||
return types.NewInt(MinGasPrice), nil
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package metrics
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
@ -11,6 +10,7 @@ import (
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
"go.uber.org/fx"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/impl/full"
|
||||
"github.com/filecoin-project/lotus/node/modules/helpers"
|
||||
@ -89,7 +89,7 @@ func sendHeadNotifs(ctx context.Context, ps *pubsub.PubSub, topic string, chain
|
||||
}
|
||||
|
||||
// using unix nano time makes very sure we pick a nonce higher than previous restart
|
||||
nonce := uint64(time.Now().UnixNano())
|
||||
nonce := uint64(build.Clock.Now().UnixNano())
|
||||
|
||||
for {
|
||||
select {
|
||||
@ -107,7 +107,7 @@ func sendHeadNotifs(ctx context.Context, ps *pubsub.PubSub, topic string, chain
|
||||
Height: n.Val.Height(),
|
||||
Weight: w,
|
||||
NodeName: nickname,
|
||||
Time: uint64(time.Now().UnixNano() / 1000_000),
|
||||
Time: uint64(build.Clock.Now().UnixNano() / 1000_000),
|
||||
Nonce: nonce,
|
||||
}
|
||||
|
||||
|
@ -4,12 +4,15 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/ipfs/go-cid"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
@ -25,7 +28,7 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate
|
||||
}
|
||||
|
||||
if msg.GasLimit == 0 {
|
||||
msg.GasLimit = 10000000000
|
||||
msg.GasLimit = build.BlockGasLimit
|
||||
}
|
||||
if msg.GasPrice == types.EmptyInt {
|
||||
msg.GasPrice = types.NewInt(0)
|
||||
@ -83,6 +86,77 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.
|
||||
return sm.CallRaw(ctx, msg, state, r, ts.Height())
|
||||
}
|
||||
|
||||
func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "statemanager.CallWithGas")
|
||||
defer span.End()
|
||||
|
||||
if ts == nil {
|
||||
ts = sm.cs.GetHeaviestTipSet()
|
||||
}
|
||||
|
||||
state := ts.ParentState()
|
||||
|
||||
r := store.NewChainRand(sm.cs, ts.Cids(), ts.Height())
|
||||
|
||||
if span.IsRecordingEvents() {
|
||||
span.AddAttributes(
|
||||
trace.Int64Attribute("gas_limit", msg.GasLimit),
|
||||
trace.Int64Attribute("gas_price", int64(msg.GasPrice.Uint64())),
|
||||
trace.StringAttribute("value", msg.Value.String()),
|
||||
)
|
||||
}
|
||||
|
||||
vmi, err := vm.NewVM(state, ts.Height(), r, sm.cs.Blockstore(), sm.cs.VMSys())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to set up vm: %w", err)
|
||||
}
|
||||
fromActor, err := vmi.StateTree().GetActor(msg.From)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("call raw get actor: %s", err)
|
||||
}
|
||||
|
||||
msg.Nonce = fromActor.Nonce
|
||||
|
||||
fromKey, err := sm.ResolveToKeyAddress(ctx, msg.From, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("could not resolve key: %w", err)
|
||||
}
|
||||
|
||||
var msgApply types.ChainMsg
|
||||
|
||||
switch fromKey.Protocol() {
|
||||
case address.BLS:
|
||||
msgApply = msg
|
||||
case address.SECP256K1:
|
||||
msgApply = &types.SignedMessage{
|
||||
Message: *msg,
|
||||
Signature: crypto.Signature{
|
||||
Type: crypto.SigTypeSecp256k1,
|
||||
Data: make([]byte, 65),
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ret, err := vmi.ApplyMessage(ctx, msgApply)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("apply message failed: %w", err)
|
||||
}
|
||||
|
||||
var errs string
|
||||
if ret.ActorErr != nil {
|
||||
errs = ret.ActorErr.Error()
|
||||
}
|
||||
|
||||
return &api.InvocResult{
|
||||
Msg: msg,
|
||||
MsgRct: &ret.MessageReceipt,
|
||||
ExecutionTrace: ret.ExecutionTrace,
|
||||
Error: errs,
|
||||
Duration: ret.Duration,
|
||||
}, nil
|
||||
}
|
||||
|
||||
var errHaltExecution = fmt.Errorf("halt")
|
||||
|
||||
func (sm *StateManager) Replay(ctx context.Context, ts *types.TipSet, mcid cid.Cid) (*types.Message, *vm.ApplyRet, error) {
|
||||
|
@ -37,8 +37,8 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
|
||||
abi.RegisteredProof_StackedDRG2KiBSeal: {},
|
||||
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||
}
|
||||
power.ConsensusMinerMinPower = big.NewInt(2048)
|
||||
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
||||
@ -179,7 +179,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
To: builtin.InitActorAddr,
|
||||
Method: builtin.MethodsInit.Exec,
|
||||
Params: enc,
|
||||
GasLimit: 10000,
|
||||
GasLimit: types.TestGasLimit,
|
||||
GasPrice: types.NewInt(0),
|
||||
}
|
||||
sig, err := cg.Wallet().Sign(ctx, cg.Banker(), m.Cid().Bytes())
|
||||
@ -206,7 +206,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
Method: 2,
|
||||
Params: nil,
|
||||
Nonce: nonce,
|
||||
GasLimit: 10000,
|
||||
GasLimit: types.TestGasLimit,
|
||||
GasPrice: types.NewInt(0),
|
||||
}
|
||||
nonce++
|
||||
|
155
chain/stmgr/read.go
Normal file
155
chain/stmgr/read.go
Normal file
@ -0,0 +1,155 @@
|
||||
package stmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
)
|
||||
|
||||
type StateTreeCB func(state *state.StateTree) error
|
||||
|
||||
func (sm *StateManager) WithParentStateTsk(tsk types.TipSetKey, cb StateTreeCB) error {
|
||||
ts, err := sm.cs.GetTipSetFromKey(tsk)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
||||
}
|
||||
|
||||
cst := cbor.NewCborStore(sm.cs.Blockstore())
|
||||
state, err := state.LoadStateTree(cst, sm.parentState(ts))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("load state tree: %w", err)
|
||||
}
|
||||
|
||||
return cb(state)
|
||||
}
|
||||
|
||||
func (sm *StateManager) WithParentState(ts *types.TipSet, cb StateTreeCB) error {
|
||||
cst := cbor.NewCborStore(sm.cs.Blockstore())
|
||||
state, err := state.LoadStateTree(cst, sm.parentState(ts))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("load state tree: %w", err)
|
||||
}
|
||||
|
||||
return cb(state)
|
||||
}
|
||||
|
||||
func (sm *StateManager) WithStateTree(st cid.Cid, cb StateTreeCB) error {
|
||||
cst := cbor.NewCborStore(sm.cs.Blockstore())
|
||||
state, err := state.LoadStateTree(cst, st)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("load state tree: %w", err)
|
||||
}
|
||||
|
||||
return cb(state)
|
||||
}
|
||||
|
||||
type ActorCB func(act *types.Actor) error
|
||||
|
||||
func GetActor(out *types.Actor) ActorCB {
|
||||
return func(act *types.Actor) error {
|
||||
*out = *act
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *StateManager) WithActor(addr address.Address, cb ActorCB) StateTreeCB {
|
||||
return func(state *state.StateTree) error {
|
||||
act, err := state.GetActor(addr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get actor: %w", err)
|
||||
}
|
||||
|
||||
return cb(act)
|
||||
}
|
||||
}
|
||||
|
||||
// WithActorState usage:
|
||||
// Option 1: WithActorState(ctx, idAddr, func(store adt.Store, st *ActorStateType) error {...})
|
||||
// Option 2: WithActorState(ctx, idAddr, actorStatePtr)
|
||||
func (sm *StateManager) WithActorState(ctx context.Context, out interface{}) ActorCB {
|
||||
return func(act *types.Actor) error {
|
||||
store := sm.cs.Store(ctx)
|
||||
|
||||
outCallback := reflect.TypeOf(out).Kind() == reflect.Func
|
||||
|
||||
var st reflect.Value
|
||||
if outCallback {
|
||||
st = reflect.New(reflect.TypeOf(out).In(1).Elem())
|
||||
} else {
|
||||
st = reflect.ValueOf(out)
|
||||
}
|
||||
if err := store.Get(ctx, act.Head, st.Interface()); err != nil {
|
||||
return xerrors.Errorf("read actor head: %w", err)
|
||||
}
|
||||
|
||||
if outCallback {
|
||||
out := reflect.ValueOf(out).Call([]reflect.Value{reflect.ValueOf(store), st})
|
||||
if !out[0].IsNil() && out[0].Interface().(error) != nil {
|
||||
return out[0].Interface().(error)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
type DeadlinesCB func(store adt.Store, deadlines *miner.Deadlines) error
|
||||
|
||||
func (sm *StateManager) WithDeadlines(cb DeadlinesCB) func(store adt.Store, mas *miner.State) error {
|
||||
return func(store adt.Store, mas *miner.State) error {
|
||||
deadlines, err := mas.LoadDeadlines(store)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return cb(store, deadlines)
|
||||
}
|
||||
}
|
||||
|
||||
type DeadlineCB func(store adt.Store, idx uint64, deadline *miner.Deadline) error
|
||||
|
||||
func (sm *StateManager) WithDeadline(idx uint64, cb DeadlineCB) DeadlinesCB {
|
||||
return func(store adt.Store, deadlines *miner.Deadlines) error {
|
||||
d, err := deadlines.LoadDeadline(store, idx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return cb(store, idx, d)
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *StateManager) WithEachDeadline(cb DeadlineCB) DeadlinesCB {
|
||||
return func(store adt.Store, deadlines *miner.Deadlines) error {
|
||||
return deadlines.ForEach(store, func(dlIdx uint64, dl *miner.Deadline) error {
|
||||
return cb(store, dlIdx, dl)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type PartitionCB func(store adt.Store, idx uint64, partition *miner.Partition) error
|
||||
|
||||
func (sm *StateManager) WithEachPartition(cb PartitionCB) DeadlineCB {
|
||||
return func(store adt.Store, idx uint64, deadline *miner.Deadline) error {
|
||||
parts, err := deadline.PartitionsArray(store)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var partition miner.Partition
|
||||
return parts.ForEach(&partition, func(i int64) error {
|
||||
p := partition
|
||||
return cb(store, uint64(i), &p)
|
||||
})
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
amt "github.com/filecoin-project/go-amt-ipld/v2"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
@ -143,7 +144,7 @@ type BlockMessages struct {
|
||||
Miner address.Address
|
||||
BlsMessages []types.ChainMsg
|
||||
SecpkMessages []types.ChainMsg
|
||||
TicketCount int64
|
||||
WinCount int64
|
||||
}
|
||||
|
||||
type ExecCallback func(cid.Cid, *types.Message, *vm.ApplyRet) error
|
||||
@ -184,10 +185,10 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, pstate cid.Cid, bms []B
|
||||
|
||||
var err error
|
||||
params, err := actors.SerializeParams(&reward.AwardBlockRewardParams{
|
||||
Miner: b.Miner,
|
||||
Penalty: penalty,
|
||||
GasReward: gasReward,
|
||||
TicketCount: 1, // TODO: no longer need ticket count here.
|
||||
Miner: b.Miner,
|
||||
Penalty: penalty,
|
||||
GasReward: gasReward,
|
||||
WinCount: b.WinCount,
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to serialize award params: %w", err)
|
||||
@ -236,7 +237,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, pstate cid.Cid, bms []B
|
||||
Nonce: ca.Nonce,
|
||||
Value: types.NewInt(0),
|
||||
GasPrice: types.NewInt(0),
|
||||
GasLimit: 1 << 30, // Make super sure this is never too little
|
||||
GasLimit: build.BlockGasLimit * 10, // Make super sure this is never too little
|
||||
Method: builtin.MethodsCron.EpochTick,
|
||||
Params: nil,
|
||||
}
|
||||
@ -312,7 +313,7 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.Bl
|
||||
Miner: b.Miner,
|
||||
BlsMessages: make([]types.ChainMsg, 0, len(bms)),
|
||||
SecpkMessages: make([]types.ChainMsg, 0, len(sms)),
|
||||
TicketCount: 1, //int64(len(b.EPostProof.Proofs)), // TODO fix this
|
||||
WinCount: b.ElectionProof.WinCount,
|
||||
}
|
||||
|
||||
for _, m := range bms {
|
||||
@ -337,74 +338,10 @@ func (sm *StateManager) parentState(ts *types.TipSet) cid.Cid {
|
||||
return ts.ParentState()
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
|
||||
cst := cbor.NewCborStore(sm.cs.Blockstore())
|
||||
state, err := state.LoadStateTree(cst, sm.parentState(ts))
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("load state tree: %w", err)
|
||||
}
|
||||
|
||||
return state.GetActor(addr)
|
||||
}
|
||||
|
||||
func (sm *StateManager) getActorRaw(addr address.Address, st cid.Cid) (*types.Actor, error) {
|
||||
cst := cbor.NewCborStore(sm.cs.Blockstore())
|
||||
state, err := state.LoadStateTree(cst, st)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("load state tree: %w", err)
|
||||
}
|
||||
|
||||
return state.GetActor(addr)
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetBalance(addr address.Address, ts *types.TipSet) (types.BigInt, error) {
|
||||
act, err := sm.GetActor(addr, ts)
|
||||
if err != nil {
|
||||
if xerrors.Is(err, types.ErrActorNotFound) {
|
||||
return types.NewInt(0), nil
|
||||
}
|
||||
return types.EmptyInt, xerrors.Errorf("get actor: %w", err)
|
||||
}
|
||||
|
||||
return act.Balance, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) ChainStore() *store.ChainStore {
|
||||
return sm.cs
|
||||
}
|
||||
|
||||
func (sm *StateManager) LoadActorState(ctx context.Context, a address.Address, out interface{}, ts *types.TipSet) (*types.Actor, error) {
|
||||
act, err := sm.GetActor(a, ts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cst := cbor.NewCborStore(sm.cs.Blockstore())
|
||||
if err := cst.Get(ctx, act.Head, out); err != nil {
|
||||
var r cbg.Deferred
|
||||
_ = cst.Get(ctx, act.Head, &r)
|
||||
log.Errorw("bad actor head", "error", err, "raw", r.Raw, "address", a)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return act, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) LoadActorStateRaw(ctx context.Context, a address.Address, out interface{}, st cid.Cid) (*types.Actor, error) {
|
||||
act, err := sm.getActorRaw(a, st)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cst := cbor.NewCborStore(sm.cs.Blockstore())
|
||||
if err := cst.Get(ctx, act.Head, out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return act, nil
|
||||
}
|
||||
|
||||
// ResolveToKeyAddress is similar to `vm.ResolveToKeyAddr` but does not allow `Actor` type of addresses.
|
||||
// Uses the `TipSet` `ts` to generate the VM state.
|
||||
func (sm *StateManager) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
@ -636,7 +573,8 @@ func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet
|
||||
default:
|
||||
}
|
||||
|
||||
act, err := sm.GetActor(m.VMMessage().From, cur)
|
||||
var act types.Actor
|
||||
err := sm.WithParentState(cur, sm.WithActor(m.VMMessage().From, GetActor(&act)))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -759,7 +697,7 @@ func (sm *StateManager) MarketBalance(ctx context.Context, addr address.Address,
|
||||
return api.MarketBalance{}, err
|
||||
}
|
||||
if ehas {
|
||||
out.Escrow, err = et.Get(addr)
|
||||
out.Escrow, _, err = et.Get(addr)
|
||||
if err != nil {
|
||||
return api.MarketBalance{}, xerrors.Errorf("getting escrow balance: %w", err)
|
||||
}
|
||||
@ -776,7 +714,7 @@ func (sm *StateManager) MarketBalance(ctx context.Context, addr address.Address,
|
||||
return api.MarketBalance{}, err
|
||||
}
|
||||
if lhas {
|
||||
out.Locked, err = lt.Get(addr)
|
||||
out.Locked, _, err = lt.Get(addr)
|
||||
if err != nil {
|
||||
return api.MarketBalance{}, xerrors.Errorf("getting locked balance: %w", err)
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os"
|
||||
"reflect"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
@ -13,13 +14,21 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
amt "github.com/filecoin-project/go-amt-ipld/v2"
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
"github.com/filecoin-project/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/account"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/cron"
|
||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
@ -35,14 +44,38 @@ import (
|
||||
|
||||
func GetNetworkName(ctx context.Context, sm *StateManager, st cid.Cid) (dtypes.NetworkName, error) {
|
||||
var state init_.State
|
||||
_, err := sm.LoadActorStateRaw(ctx, builtin.InitActorAddr, &state, st)
|
||||
err := sm.WithStateTree(st, sm.WithActor(builtin.InitActorAddr, sm.WithActorState(ctx, &state)))
|
||||
if err != nil {
|
||||
return "", xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return dtypes.NetworkName(state.NetworkName), nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) LoadActorState(ctx context.Context, addr address.Address, out interface{}, ts *types.TipSet) (*types.Actor, error) {
|
||||
var a *types.Actor
|
||||
if err := sm.WithParentState(ts, sm.WithActor(addr, func(act *types.Actor) error {
|
||||
a = act
|
||||
return sm.WithActorState(ctx, out)(act)
|
||||
})); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) LoadActorStateRaw(ctx context.Context, addr address.Address, out interface{}, st cid.Cid) (*types.Actor, error) {
|
||||
var a *types.Actor
|
||||
if err := sm.WithStateTree(st, sm.WithActor(addr, func(act *types.Actor) error {
|
||||
a = act
|
||||
return sm.WithActorState(ctx, out)(act)
|
||||
})); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func GetMinerWorkerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (address.Address, error) {
|
||||
var mas miner.State
|
||||
_, err := sm.LoadActorStateRaw(ctx, maddr, &mas, st)
|
||||
@ -56,7 +89,12 @@ func GetMinerWorkerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr
|
||||
return address.Undef, xerrors.Errorf("load state tree: %w", err)
|
||||
}
|
||||
|
||||
return vm.ResolveToKeyAddr(state, cst, mas.Info.Worker)
|
||||
info, err := mas.GetInfo(sm.cs.Store(ctx))
|
||||
if err != nil {
|
||||
return address.Address{}, err
|
||||
}
|
||||
|
||||
return vm.ResolveToKeyAddr(state, cst, info.Worker)
|
||||
}
|
||||
|
||||
func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (power.Claim, power.Claim, error) {
|
||||
@ -91,35 +129,6 @@ func GetPowerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr addres
|
||||
}, nil
|
||||
}
|
||||
|
||||
func SectorSetSizes(ctx context.Context, sm *StateManager, maddr address.Address, ts *types.TipSet) (api.MinerSectors, error) {
|
||||
var mas miner.State
|
||||
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
|
||||
if err != nil {
|
||||
return api.MinerSectors{}, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
notProving, err := abi.BitFieldUnion(mas.Faults, mas.Recoveries)
|
||||
if err != nil {
|
||||
return api.MinerSectors{}, err
|
||||
}
|
||||
|
||||
npc, err := notProving.Count()
|
||||
if err != nil {
|
||||
return api.MinerSectors{}, err
|
||||
}
|
||||
|
||||
blks := cbor.NewCborStore(sm.ChainStore().Blockstore())
|
||||
ss, err := amt.LoadAMT(ctx, blks, mas.Sectors)
|
||||
if err != nil {
|
||||
return api.MinerSectors{}, err
|
||||
}
|
||||
|
||||
return api.MinerSectors{
|
||||
Sset: ss.Count,
|
||||
Pset: ss.Count - npc,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func PreCommitInfo(ctx context.Context, sm *StateManager, maddr address.Address, sid abi.SectorNumber, ts *types.TipSet) (miner.SectorPreCommitOnChainInfo, error) {
|
||||
var mas miner.State
|
||||
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
|
||||
@ -167,23 +176,64 @@ func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet,
|
||||
}
|
||||
|
||||
func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *StateManager, st cid.Cid, maddr address.Address, rand abi.PoStRandomness) ([]abi.SectorInfo, error) {
|
||||
var mas miner.State
|
||||
_, err := sm.LoadActorStateRaw(ctx, maddr, &mas, st)
|
||||
var partsProving []*abi.BitField
|
||||
var mas *miner.State
|
||||
var info *miner.MinerInfo
|
||||
|
||||
err := sm.WithStateTree(st, sm.WithActor(maddr, sm.WithActorState(ctx, func(store adt.Store, mst *miner.State) error {
|
||||
var err error
|
||||
|
||||
mas = mst
|
||||
|
||||
info, err = mas.GetInfo(store)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner info: %w", err)
|
||||
}
|
||||
|
||||
deadlines, err := mas.LoadDeadlines(store)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("loading deadlines: %w", err)
|
||||
}
|
||||
|
||||
return deadlines.ForEach(store, func(dlIdx uint64, deadline *miner.Deadline) error {
|
||||
partitions, err := deadline.PartitionsArray(store)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting partition array: %w", err)
|
||||
}
|
||||
|
||||
var partition miner.Partition
|
||||
return partitions.ForEach(&partition, func(partIdx int64) error {
|
||||
p, err := bitfield.SubtractBitField(partition.Sectors, partition.Faults)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("subtract faults from partition sectors: %w", err)
|
||||
}
|
||||
|
||||
partsProving = append(partsProving, p)
|
||||
|
||||
return nil
|
||||
})
|
||||
})
|
||||
})))
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("(get sectors) failed to load miner actor state: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: Optimization: we could avoid loaditg the whole proving set here if we had AMT.GetNth with bitfield filtering
|
||||
sectorSet, err := GetProvingSetRaw(ctx, sm, mas)
|
||||
provingSectors, err := bitfield.MultiMerge(partsProving...)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting proving set: %w", err)
|
||||
return nil, xerrors.Errorf("merge partition proving sets: %w", err)
|
||||
}
|
||||
|
||||
if len(sectorSet) == 0 {
|
||||
numProvSect, err := provingSectors.Count()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to count bits: %w", err)
|
||||
}
|
||||
|
||||
// TODO(review): is this right? feels fishy to me
|
||||
if numProvSect == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
spt, err := ffiwrapper.SealProofTypeFromSectorSize(mas.Info.SectorSize)
|
||||
spt, err := ffiwrapper.SealProofTypeFromSectorSize(info.SectorSize)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting seal proof type: %w", err)
|
||||
}
|
||||
@ -198,31 +248,48 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S
|
||||
return nil, xerrors.Errorf("getting miner ID: %w", err)
|
||||
}
|
||||
|
||||
ids, err := pv.GenerateWinningPoStSectorChallenge(ctx, wpt, abi.ActorID(mid), rand, uint64(len(sectorSet)))
|
||||
ids, err := pv.GenerateWinningPoStSectorChallenge(ctx, wpt, abi.ActorID(mid), rand, numProvSect)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("generating winning post challenges: %w", err)
|
||||
}
|
||||
|
||||
sectors, err := provingSectors.All(miner.SectorsMax)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to enumerate all sector IDs: %w", err)
|
||||
}
|
||||
|
||||
sectorAmt, err := amt.LoadAMT(ctx, sm.cs.Store(ctx), mas.Sectors)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load sectors amt: %w", err)
|
||||
}
|
||||
|
||||
out := make([]abi.SectorInfo, len(ids))
|
||||
for i, n := range ids {
|
||||
sid := sectors[n]
|
||||
|
||||
var sinfo miner.SectorOnChainInfo
|
||||
if err := sectorAmt.Get(ctx, sid, &sinfo); err != nil {
|
||||
return nil, xerrors.Errorf("failed to get sector %d: %w", sid, err)
|
||||
}
|
||||
|
||||
out[i] = abi.SectorInfo{
|
||||
RegisteredProof: wpt,
|
||||
SectorNumber: sectorSet[n].ID,
|
||||
SealedCID: sectorSet[n].Info.Info.SealedCID,
|
||||
SealProof: spt,
|
||||
SectorNumber: sinfo.SectorNumber,
|
||||
SealedCID: sinfo.SealedCID,
|
||||
}
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func StateMinerInfo(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (miner.MinerInfo, error) {
|
||||
func StateMinerInfo(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (*miner.MinerInfo, error) {
|
||||
var mas miner.State
|
||||
_, err := sm.LoadActorStateRaw(ctx, maddr, &mas, ts.ParentState())
|
||||
if err != nil {
|
||||
return miner.MinerInfo{}, xerrors.Errorf("(get ssize) failed to load miner actor state: %w", err)
|
||||
return nil, xerrors.Errorf("(get ssize) failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
return mas.Info, nil
|
||||
return mas.GetInfo(sm.cs.Store(ctx))
|
||||
}
|
||||
|
||||
func GetMinerSlashed(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (bool, error) {
|
||||
@ -256,36 +323,6 @@ func GetMinerSlashed(ctx context.Context, sm *StateManager, ts *types.TipSet, ma
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func GetMinerDeadlines(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (*miner.Deadlines, error) {
|
||||
var mas miner.State
|
||||
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("(get ssize) failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
return mas.LoadDeadlines(sm.cs.Store(ctx))
|
||||
}
|
||||
|
||||
func GetMinerFaults(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (*abi.BitField, error) {
|
||||
var mas miner.State
|
||||
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("(get faults) failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
return mas.Faults, nil
|
||||
}
|
||||
|
||||
func GetMinerRecoveries(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (*abi.BitField, error) {
|
||||
var mas miner.State
|
||||
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("(get recoveries) failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
return mas.Recoveries, nil
|
||||
}
|
||||
|
||||
func GetStorageDeal(ctx context.Context, sm *StateManager, dealID abi.DealID, ts *types.TipSet) (*api.MarketDeal, error) {
|
||||
var state market.State
|
||||
if _, err := sm.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil {
|
||||
@ -427,20 +464,6 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
||||
return root, trace, nil
|
||||
}
|
||||
|
||||
func GetProvingSetRaw(ctx context.Context, sm *StateManager, mas miner.State) ([]*api.ChainSectorInfo, error) {
|
||||
notProving, err := abi.BitFieldUnion(mas.Faults, mas.Recoveries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
provset, err := LoadSectorsFromSet(ctx, sm.cs.Blockstore(), mas.Sectors, notProving, true)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get proving set: %w", err)
|
||||
}
|
||||
|
||||
return provset, nil
|
||||
}
|
||||
|
||||
func GetLookbackTipSetForRound(ctx context.Context, sm *StateManager, ts *types.TipSet, round abi.ChainEpoch) (*types.TipSet, error) {
|
||||
var lbr abi.ChainEpoch
|
||||
if round > build.WinningPoStSectorSetLookback {
|
||||
@ -524,7 +547,12 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBe
|
||||
return nil, xerrors.Errorf("failed to get power: %w", err)
|
||||
}
|
||||
|
||||
worker, err := sm.ResolveToKeyAddress(ctx, mas.GetWorker(), ts)
|
||||
info, err := mas.GetInfo(sm.cs.Store(ctx))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
worker, err := sm.ResolveToKeyAddress(ctx, info.Worker, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("resolving worker address: %w", err)
|
||||
}
|
||||
@ -534,8 +562,90 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBe
|
||||
NetworkPower: tpow.QualityAdjPower,
|
||||
Sectors: sectors,
|
||||
WorkerKey: worker,
|
||||
SectorSize: mas.Info.SectorSize,
|
||||
SectorSize: info.SectorSize,
|
||||
PrevBeaconEntry: *prev,
|
||||
BeaconEntries: entries,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) CirculatingSupply(ctx context.Context, ts *types.TipSet) (abi.TokenAmount, error) {
|
||||
if ts == nil {
|
||||
ts = sm.cs.GetHeaviestTipSet()
|
||||
}
|
||||
|
||||
st, _, err := sm.TipSetState(ctx, ts)
|
||||
if err != nil {
|
||||
return big.Zero(), err
|
||||
}
|
||||
|
||||
r := store.NewChainRand(sm.cs, ts.Cids(), ts.Height())
|
||||
vmi, err := vm.NewVM(st, ts.Height(), r, sm.cs.Blockstore(), sm.cs.VMSys())
|
||||
if err != nil {
|
||||
return big.Zero(), err
|
||||
}
|
||||
|
||||
unsafeVM := &vm.UnsafeVM{VM: vmi}
|
||||
rt := unsafeVM.MakeRuntime(ctx, &types.Message{
|
||||
GasLimit: 100e6,
|
||||
From: builtin.SystemActorAddr,
|
||||
}, builtin.SystemActorAddr, 0, 0, 0)
|
||||
|
||||
return rt.TotalFilCircSupply(), nil
|
||||
}
|
||||
|
||||
type methodMeta struct {
|
||||
Name string
|
||||
|
||||
Params reflect.Type
|
||||
Ret reflect.Type
|
||||
}
|
||||
|
||||
var MethodsMap = map[cid.Cid][]methodMeta{}
|
||||
|
||||
func init() {
|
||||
cidToMethods := map[cid.Cid][2]interface{}{
|
||||
// builtin.SystemActorCodeID: {builtin.MethodsSystem, system.Actor{} }- apparently it doesn't have methods
|
||||
builtin.InitActorCodeID: {builtin.MethodsInit, init_.Actor{}},
|
||||
builtin.CronActorCodeID: {builtin.MethodsCron, cron.Actor{}},
|
||||
builtin.AccountActorCodeID: {builtin.MethodsAccount, account.Actor{}},
|
||||
builtin.StoragePowerActorCodeID: {builtin.MethodsPower, power.Actor{}},
|
||||
builtin.StorageMinerActorCodeID: {builtin.MethodsMiner, miner.Actor{}},
|
||||
builtin.StorageMarketActorCodeID: {builtin.MethodsMarket, market.Actor{}},
|
||||
builtin.PaymentChannelActorCodeID: {builtin.MethodsPaych, paych.Actor{}},
|
||||
builtin.MultisigActorCodeID: {builtin.MethodsMultisig, multisig.Actor{}},
|
||||
builtin.RewardActorCodeID: {builtin.MethodsReward, reward.Actor{}},
|
||||
builtin.VerifiedRegistryActorCodeID: {builtin.MethodsVerifiedRegistry, verifreg.Actor{}},
|
||||
}
|
||||
|
||||
for c, m := range cidToMethods {
|
||||
rt := reflect.TypeOf(m[0])
|
||||
nf := rt.NumField()
|
||||
|
||||
MethodsMap[c] = append(MethodsMap[c], methodMeta{
|
||||
Name: "Send",
|
||||
Params: reflect.TypeOf(new(adt.EmptyValue)),
|
||||
Ret: reflect.TypeOf(new(adt.EmptyValue)),
|
||||
})
|
||||
|
||||
exports := m[1].(abi.Invokee).Exports()
|
||||
for i := 0; i < nf; i++ {
|
||||
export := reflect.TypeOf(exports[i+1])
|
||||
|
||||
MethodsMap[c] = append(MethodsMap[c], methodMeta{
|
||||
Name: rt.Field(i).Name,
|
||||
Params: export.In(1),
|
||||
Ret: export.Out(0),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, method abi.MethodNum, ts *types.TipSet) (cbg.CBORUnmarshaler, error) {
|
||||
var act types.Actor
|
||||
if err := sm.WithParentState(ts, sm.WithActor(to, GetActor(&act))); err != nil {
|
||||
return nil, xerrors.Errorf("getting actor: %w", err)
|
||||
}
|
||||
|
||||
m := MethodsMap[act.Code][method]
|
||||
return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil
|
||||
}
|
||||
|
@ -32,8 +32,11 @@ func (fts *FullTipSet) Cids() []cid.Cid {
|
||||
return cids
|
||||
}
|
||||
|
||||
// TipSet returns a narrower view of this FullTipSet elliding the block
|
||||
// messages.
|
||||
func (fts *FullTipSet) TipSet() *types.TipSet {
|
||||
if fts.tipset != nil {
|
||||
// FIXME: fts.tipset is actually never set. Should it memoize?
|
||||
return fts.tipset
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ type lbEntry struct {
|
||||
target types.TipSetKey
|
||||
}
|
||||
|
||||
func (ci *ChainIndex) GetTipsetByHeight(ctx context.Context, from *types.TipSet, to abi.ChainEpoch) (*types.TipSet, error) {
|
||||
func (ci *ChainIndex) GetTipsetByHeight(_ context.Context, from *types.TipSet, to abi.ChainEpoch) (*types.TipSet, error) {
|
||||
if from.Height()-to <= ci.skipLength {
|
||||
return ci.walkBack(from, to)
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ import (
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/lotus/lib/adtutil"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/minio/blake2b-simd"
|
||||
|
||||
@ -20,6 +22,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/filecoin-project/lotus/metrics"
|
||||
"go.opencensus.io/stats"
|
||||
"go.opencensus.io/trace"
|
||||
@ -47,10 +50,20 @@ import (
|
||||
var log = logging.Logger("chainstore")
|
||||
|
||||
var chainHeadKey = dstore.NewKey("head")
|
||||
var blockValidationCacheKeyPrefix = dstore.NewKey("blockValidation")
|
||||
|
||||
// ReorgNotifee represents a callback that gets called upon reorgs.
|
||||
type ReorgNotifee func(rev, app []*types.TipSet) error
|
||||
|
||||
// ChainStore is the main point of access to chain data.
|
||||
//
|
||||
// Raw chain data is stored in the Blockstore, with relevant markers (genesis,
|
||||
// latest head tipset references) being tracked in the Datastore (key-value
|
||||
// store).
|
||||
//
|
||||
// To alleviate disk access, the ChainStore has two ARC caches:
|
||||
// 1. a tipset cache
|
||||
// 2. a block => messages references cache.
|
||||
type ChainStore struct {
|
||||
bs bstore.Blockstore
|
||||
ds dstore.Datastore
|
||||
@ -217,6 +230,22 @@ func (cs *ChainStore) SubscribeHeadChanges(f ReorgNotifee) {
|
||||
cs.reorgNotifeeCh <- f
|
||||
}
|
||||
|
||||
func (cs *ChainStore) IsBlockValidated(ctx context.Context, blkid cid.Cid) (bool, error) {
|
||||
key := blockValidationCacheKeyPrefix.Instance(blkid.String())
|
||||
|
||||
return cs.ds.Has(key)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) MarkBlockAsValidated(ctx context.Context, blkid cid.Cid) error {
|
||||
key := blockValidationCacheKeyPrefix.Instance(blkid.String())
|
||||
|
||||
if err := cs.ds.Put(key, []byte{0}); err != nil {
|
||||
return xerrors.Errorf("cache block validation: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) SetGenesis(b *types.BlockHeader) error {
|
||||
ts, err := types.NewTipSet([]*types.BlockHeader{b})
|
||||
if err != nil {
|
||||
@ -249,6 +278,9 @@ func (cs *ChainStore) PutTipSet(ctx context.Context, ts *types.TipSet) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MaybeTakeHeavierTipSet evaluates the incoming tipset and locks it in our
|
||||
// internal state as our new head, if and only if it is heavier than the current
|
||||
// head.
|
||||
func (cs *ChainStore) MaybeTakeHeavierTipSet(ctx context.Context, ts *types.TipSet) error {
|
||||
cs.heaviestLk.Lock()
|
||||
defer cs.heaviestLk.Unlock()
|
||||
@ -295,6 +327,14 @@ func (cs *ChainStore) reorgWorker(ctx context.Context, initialNotifees []ReorgNo
|
||||
continue
|
||||
}
|
||||
|
||||
journal.Add("sync", map[string]interface{}{
|
||||
"op": "headChange",
|
||||
"from": r.old.Key(),
|
||||
"to": r.new.Key(),
|
||||
"rev": len(revert),
|
||||
"apply": len(apply),
|
||||
})
|
||||
|
||||
// reverse the apply array
|
||||
for i := len(apply)/2 - 1; i >= 0; i-- {
|
||||
opp := len(apply) - 1 - i
|
||||
@ -314,6 +354,9 @@ func (cs *ChainStore) reorgWorker(ctx context.Context, initialNotifees []ReorgNo
|
||||
return out
|
||||
}
|
||||
|
||||
// takeHeaviestTipSet actually sets the incoming tipset as our head both in
|
||||
// memory and in the ChainStore. It also sends a notification to deliver to
|
||||
// ReorgNotifees.
|
||||
func (cs *ChainStore) takeHeaviestTipSet(ctx context.Context, ts *types.TipSet) error {
|
||||
_, span := trace.StartSpan(ctx, "takeHeaviestTipSet")
|
||||
defer span.End()
|
||||
@ -351,6 +394,7 @@ func (cs *ChainStore) SetHead(ts *types.TipSet) error {
|
||||
return cs.takeHeaviestTipSet(context.TODO(), ts)
|
||||
}
|
||||
|
||||
// Contains returns whether our BlockStore has all blocks in the supplied TipSet.
|
||||
func (cs *ChainStore) Contains(ts *types.TipSet) (bool, error) {
|
||||
for _, c := range ts.Cids() {
|
||||
has, err := cs.bs.Has(c)
|
||||
@ -365,6 +409,8 @@ func (cs *ChainStore) Contains(ts *types.TipSet) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// GetBlock fetches a BlockHeader with the supplied CID. It returns
|
||||
// blockstore.ErrNotFound if the block was not found in the BlockStore.
|
||||
func (cs *ChainStore) GetBlock(c cid.Cid) (*types.BlockHeader, error) {
|
||||
sb, err := cs.bs.Get(c)
|
||||
if err != nil {
|
||||
@ -457,6 +503,7 @@ func (cs *ChainStore) ReorgOps(a, b *types.TipSet) ([]*types.TipSet, []*types.Ti
|
||||
return leftChain, rightChain, nil
|
||||
}
|
||||
|
||||
// GetHeaviestTipSet returns the current heaviest tipset known (i.e. our head).
|
||||
func (cs *ChainStore) GetHeaviestTipSet() *types.TipSet {
|
||||
cs.heaviestLk.Lock()
|
||||
defer cs.heaviestLk.Unlock()
|
||||
@ -613,7 +660,7 @@ func (cs *ChainStore) GetCMessage(c cid.Cid) (types.ChainMsg, error) {
|
||||
return m, nil
|
||||
}
|
||||
if err != bstore.ErrNotFound {
|
||||
log.Warn("GetCMessage: unexpected error getting unsigned message: %s", err)
|
||||
log.Warnf("GetCMessage: unexpected error getting unsigned message: %s", err)
|
||||
}
|
||||
|
||||
return cs.GetSignedMessage(c)
|
||||
@ -849,27 +896,7 @@ func (cs *ChainStore) Blockstore() bstore.Blockstore {
|
||||
}
|
||||
|
||||
func ActorStore(ctx context.Context, bs blockstore.Blockstore) adt.Store {
|
||||
return &astore{
|
||||
cst: cbor.NewCborStore(bs),
|
||||
ctx: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
type astore struct {
|
||||
cst cbor.IpldStore
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func (a *astore) Context() context.Context {
|
||||
return a.ctx
|
||||
}
|
||||
|
||||
func (a *astore) Get(ctx context.Context, c cid.Cid, out interface{}) error {
|
||||
return a.cst.Get(ctx, c, out)
|
||||
}
|
||||
|
||||
func (a *astore) Put(ctx context.Context, v interface{}) (cid.Cid, error) {
|
||||
return a.cst.Put(ctx, v)
|
||||
return adtutil.NewStore(ctx, cbor.NewCborStore(bs))
|
||||
}
|
||||
|
||||
func (cs *ChainStore) Store(ctx context.Context) adt.Store {
|
||||
@ -1001,21 +1028,25 @@ func recurseLinks(bs blockstore.Blockstore, root cid.Cid, in []cid.Cid) ([]cid.C
|
||||
return nil, xerrors.Errorf("recurse links get (%s) failed: %w", root, err)
|
||||
}
|
||||
|
||||
top, err := cbg.ScanForLinks(bytes.NewReader(data.RawData()))
|
||||
var rerr error
|
||||
err = cbg.ScanForLinks(bytes.NewReader(data.RawData()), func(c cid.Cid) {
|
||||
if rerr != nil {
|
||||
// No error return on ScanForLinks :(
|
||||
return
|
||||
}
|
||||
|
||||
in = append(in, c)
|
||||
var err error
|
||||
in, err = recurseLinks(bs, c, in)
|
||||
if err != nil {
|
||||
rerr = err
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("scanning for links failed: %w", err)
|
||||
}
|
||||
|
||||
in = append(in, top...)
|
||||
for _, c := range top {
|
||||
var err error
|
||||
in, err = recurseLinks(bs, c, in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return in, nil
|
||||
return in, rerr
|
||||
}
|
||||
|
||||
func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, w io.Writer) error {
|
||||
|
@ -22,8 +22,8 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
|
||||
abi.RegisteredProof_StackedDRG2KiBSeal: {},
|
||||
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||
}
|
||||
power.ConsensusMinerMinPower = big.NewInt(2048)
|
||||
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
||||
|
@ -21,11 +21,11 @@ func (cs *ChainStore) Weight(ctx context.Context, ts *types.TipSet) (types.BigIn
|
||||
if ts == nil {
|
||||
return types.NewInt(0), nil
|
||||
}
|
||||
// >>> w[r] <<< + wFunction(totalPowerAtTipset(ts)) * 2^8 + (wFunction(totalPowerAtTipset(ts)) * len(ts.blocks) * wRatio_num * 2^8) / (e * wRatio_den)
|
||||
// >>> w[r] <<< + wFunction(totalPowerAtTipset(ts)) * 2^8 + (wFunction(totalPowerAtTipset(ts)) * sum(ts.blocks[].ElectionProof.WinCount) * wRatio_num * 2^8) / (e * wRatio_den)
|
||||
|
||||
var out = new(big.Int).Set(ts.Blocks()[0].ParentWeight.Int)
|
||||
|
||||
// >>> wFunction(totalPowerAtTipset(ts)) * 2^8 <<< + (wFunction(totalPowerAtTipset(ts)) * len(ts.blocks) * wRatio_num * 2^8) / (e * wRatio_den)
|
||||
// >>> wFunction(totalPowerAtTipset(ts)) * 2^8 <<< + (wFunction(totalPowerAtTipset(ts)) * sum(ts.blocks[].ElectionProof.WinCount) * wRatio_num * 2^8) / (e * wRatio_den)
|
||||
|
||||
tpow := big2.Zero()
|
||||
{
|
||||
@ -57,11 +57,19 @@ func (cs *ChainStore) Weight(ctx context.Context, ts *types.TipSet) (types.BigIn
|
||||
|
||||
out.Add(out, big.NewInt(log2P<<8))
|
||||
|
||||
// (wFunction(totalPowerAtTipset(ts)) * len(ts.blocks) * wRatio_num * 2^8) / (e * wRatio_den)
|
||||
// (wFunction(totalPowerAtTipset(ts)) * sum(ts.blocks[].ElectionProof.WinCount) * wRatio_num * 2^8) / (e * wRatio_den)
|
||||
|
||||
eWeight := big.NewInt((log2P * int64(len(ts.Blocks())) * build.WRatioNum) << 8)
|
||||
eWeight.Div(eWeight, big.NewInt(int64(build.BlocksPerEpoch*build.WRatioDen)))
|
||||
out.Add(out, eWeight)
|
||||
totalJ := int64(0)
|
||||
for _, b := range ts.Blocks() {
|
||||
totalJ += b.ElectionProof.WinCount
|
||||
}
|
||||
|
||||
eWeight := big.NewInt((log2P * build.WRatioNum))
|
||||
eWeight = eWeight.Lsh(eWeight, 8)
|
||||
eWeight = eWeight.Mul(eWeight, new(big.Int).SetInt64(totalJ))
|
||||
eWeight = eWeight.Div(eWeight, big.NewInt(int64(build.BlocksPerEpoch*build.WRatioDen)))
|
||||
|
||||
out = out.Add(out, eWeight)
|
||||
|
||||
return types.BigInt{Int: out}, nil
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/filecoin-project/lotus/lib/adtutil"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -60,7 +61,7 @@ func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *cha
|
||||
src := msg.GetFrom()
|
||||
|
||||
go func() {
|
||||
start := time.Now()
|
||||
start := build.Clock.Now()
|
||||
log.Debug("about to fetch messages for block from pubsub")
|
||||
bmsgs, err := s.Bsync.FetchMessagesByCids(context.TODO(), blk.BlsMessages)
|
||||
if err != nil {
|
||||
@ -74,9 +75,9 @@ func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *cha
|
||||
return
|
||||
}
|
||||
|
||||
took := time.Since(start)
|
||||
took := build.Clock.Since(start)
|
||||
log.Infow("new block over pubsub", "cid", blk.Header.Cid(), "source", msg.GetFrom(), "msgfetch", took)
|
||||
if delay := time.Now().Unix() - int64(blk.Header.Timestamp); delay > 5 {
|
||||
if delay := build.Clock.Now().Unix() - int64(blk.Header.Timestamp); delay > 5 {
|
||||
log.Warnf("Received block with large delay %d from miner %s", delay, blk.Header.Miner)
|
||||
}
|
||||
|
||||
@ -141,9 +142,9 @@ func (bv *BlockValidator) flagPeer(p peer.ID) {
|
||||
|
||||
func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub.Message) pubsub.ValidationResult {
|
||||
// track validation time
|
||||
begin := time.Now()
|
||||
begin := build.Clock.Now()
|
||||
defer func() {
|
||||
log.Debugf("block validation time: %s", time.Since(begin))
|
||||
log.Debugf("block validation time: %s", build.Clock.Since(begin))
|
||||
}()
|
||||
|
||||
stats.Record(ctx, metrics.BlockReceived.M(1))
|
||||
@ -210,6 +211,12 @@ func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub
|
||||
return pubsub.ValidationReject
|
||||
}
|
||||
|
||||
if blk.Header.ElectionProof.WinCount < 1 {
|
||||
log.Errorf("block is not claiming to be winning")
|
||||
recordFailure("not_winning")
|
||||
return pubsub.ValidationReject
|
||||
}
|
||||
|
||||
// it's a good block! make sure we've only seen it once
|
||||
if bv.recvBlocks.add(blk.Header.Cid()) > 0 {
|
||||
// TODO: once these changes propagate to the network, we can consider
|
||||
@ -226,7 +233,7 @@ func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub
|
||||
func (bv *BlockValidator) isChainNearSynced() bool {
|
||||
ts := bv.chain.GetHeaviestTipSet()
|
||||
timestamp := ts.MinTimestamp()
|
||||
now := time.Now().UnixNano()
|
||||
now := build.Clock.Now().UnixNano()
|
||||
cutoff := uint64(now) - uint64(6*time.Hour)
|
||||
return timestamp > cutoff
|
||||
}
|
||||
@ -311,7 +318,12 @@ func (bv *BlockValidator) getMinerWorkerKey(ctx context.Context, msg *types.Bloc
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
worker := mst.Info.Worker
|
||||
info, err := mst.GetInfo(adtutil.NewStore(ctx, cst))
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
worker := info.Worker
|
||||
key, err = bv.stmgr.ResolveToKeyAddress(ctx, worker, ts)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
|
343
chain/sync.go
343
chain/sync.go
@ -8,7 +8,6 @@ import (
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/Gurpartap/async"
|
||||
@ -50,10 +49,37 @@ import (
|
||||
"github.com/filecoin-project/lotus/metrics"
|
||||
)
|
||||
|
||||
// Blocks that are more than MaxHeightDrift epochs above
|
||||
//the theoretical max height based on systime are quickly rejected
|
||||
const MaxHeightDrift = 5
|
||||
|
||||
var log = logging.Logger("chain")
|
||||
|
||||
var LocalIncoming = "incoming"
|
||||
|
||||
// Syncer is in charge of running the chain synchronization logic. As such, it
|
||||
// is tasked with these functions, amongst others:
|
||||
//
|
||||
// * Fast-forwards the chain as it learns of new TipSets from the network via
|
||||
// the SyncManager.
|
||||
// * Applies the fork choice rule to select the correct side when confronted
|
||||
// with a fork in the network.
|
||||
// * Requests block headers and messages from other peers when not available
|
||||
// in our BlockStore.
|
||||
// * Tracks blocks marked as bad in a cache.
|
||||
// * Keeps the BlockStore and ChainStore consistent with our view of the world,
|
||||
// the latter of which in turn informs other components when a reorg has been
|
||||
// committed.
|
||||
//
|
||||
// The Syncer does not run workers itself. It's mainly concerned with
|
||||
// ensuring a consistent state of chain consensus. The reactive and network-
|
||||
// interfacing processes are part of other components, such as the SyncManager
|
||||
// (which owns the sync scheduler and sync workers), BlockSync, the HELLO
|
||||
// protocol, and the gossipsub block propagation layer.
|
||||
//
|
||||
// {hint/concept} The fork-choice rule as it currently stands is: "pick the
|
||||
// chain with the heaviest weight, so long as it hasn’t deviated one finality
|
||||
// threshold from our head (900 epochs, parameter determined by spec-actors)".
|
||||
type Syncer struct {
|
||||
// The interface for accessing and putting tipsets into local storage
|
||||
store *store.ChainStore
|
||||
@ -86,6 +112,7 @@ type Syncer struct {
|
||||
verifier ffiwrapper.Verifier
|
||||
}
|
||||
|
||||
// NewSyncer creates a new Syncer object.
|
||||
func NewSyncer(sm *stmgr.StateManager, bsync *blocksync.BlockSync, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*Syncer, error) {
|
||||
gen, err := sm.ChainStore().GetGenesis()
|
||||
if err != nil {
|
||||
@ -134,6 +161,11 @@ func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if syncer.IsEpochBeyondCurrMax(fts.TipSet().Height()) {
|
||||
log.Errorf("Received block with impossibly large height %d", fts.TipSet().Height())
|
||||
return false
|
||||
}
|
||||
|
||||
for _, b := range fts.Blocks {
|
||||
if reason, ok := syncer.bad.Has(b.Cid()); ok {
|
||||
log.Warnf("InformNewHead called on block marked as bad: %s (reason: %s)", b.Cid(), reason)
|
||||
@ -183,6 +215,11 @@ func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IncomingBlocks spawns a goroutine that subscribes to the local eventbus to
|
||||
// receive new block headers as they arrive from the network, and sends them to
|
||||
// the returned channel.
|
||||
//
|
||||
// These blocks have not necessarily been incorporated to our view of the chain.
|
||||
func (syncer *Syncer) IncomingBlocks(ctx context.Context) (<-chan *types.BlockHeader, error) {
|
||||
sub := syncer.incoming.Sub(LocalIncoming)
|
||||
out := make(chan *types.BlockHeader, 10)
|
||||
@ -210,11 +247,15 @@ func (syncer *Syncer) IncomingBlocks(ctx context.Context) (<-chan *types.BlockHe
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ValidateMsgMeta performs structural and content hash validation of the
|
||||
// messages within this block. If validation passes, it stores the messages in
|
||||
// the underlying IPLD block store.
|
||||
func (syncer *Syncer) ValidateMsgMeta(fblk *types.FullBlock) error {
|
||||
if msgc := len(fblk.BlsMessages) + len(fblk.SecpkMessages); msgc > build.BlockMessageLimit {
|
||||
return xerrors.Errorf("block %s has too many messages (%d)", fblk.Header.Cid(), msgc)
|
||||
}
|
||||
|
||||
// Collect the CIDs of both types of messages separately: BLS and Secpk.
|
||||
var bcids, scids []cbg.CBORMarshaler
|
||||
for _, m := range fblk.BlsMessages {
|
||||
c := cbg.CborCid(m.Cid())
|
||||
@ -232,11 +273,14 @@ func (syncer *Syncer) ValidateMsgMeta(fblk *types.FullBlock) error {
|
||||
blockstore := syncer.store.Blockstore()
|
||||
|
||||
bs := cbor.NewCborStore(blockstore)
|
||||
|
||||
// Compute the root CID of the combined message trie.
|
||||
smroot, err := computeMsgMeta(bs, bcids, scids)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("validating msgmeta, compute failed: %w", err)
|
||||
}
|
||||
|
||||
// Check that the message trie root matches with what's in the block.
|
||||
if fblk.Header.Messages != smroot {
|
||||
return xerrors.Errorf("messages in full block did not match msgmeta root in header (%s != %s)", fblk.Header.Messages, smroot)
|
||||
}
|
||||
@ -305,6 +349,10 @@ func zipTipSetAndMessages(bs cbor.IpldStore, ts *types.TipSet, allbmsgs []*types
|
||||
|
||||
fts := &store.FullTipSet{}
|
||||
for bi, b := range ts.Blocks() {
|
||||
if msgc := len(bmi[bi]) + len(smi[bi]); msgc > build.BlockMessageLimit {
|
||||
return nil, fmt.Errorf("block %q has too many messages (%d)", b.Cid(), msgc)
|
||||
}
|
||||
|
||||
var smsgs []*types.SignedMessage
|
||||
var smsgCids []cbg.CBORMarshaler
|
||||
for _, m := range smi[bi] {
|
||||
@ -321,10 +369,6 @@ func zipTipSetAndMessages(bs cbor.IpldStore, ts *types.TipSet, allbmsgs []*types
|
||||
bmsgCids = append(bmsgCids, &c)
|
||||
}
|
||||
|
||||
if msgc := len(bmsgCids) + len(smsgCids); msgc > build.BlockMessageLimit {
|
||||
return nil, fmt.Errorf("block %q has too many messages (%d)", b.Cid(), msgc)
|
||||
}
|
||||
|
||||
mrcid, err := computeMsgMeta(bs, bmsgCids, smsgCids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -346,6 +390,8 @@ func zipTipSetAndMessages(bs cbor.IpldStore, ts *types.TipSet, allbmsgs []*types
|
||||
return fts, nil
|
||||
}
|
||||
|
||||
// computeMsgMeta computes the root CID of the combined arrays of message CIDs
|
||||
// of both types (BLS and Secpk).
|
||||
func computeMsgMeta(bs cbor.IpldStore, bmsgCids, smsgCids []cbg.CBORMarshaler) (cid.Cid, error) {
|
||||
ctx := context.TODO()
|
||||
bmroot, err := amt.FromArray(ctx, bs, bmsgCids)
|
||||
@ -369,14 +415,24 @@ func computeMsgMeta(bs cbor.IpldStore, bmsgCids, smsgCids []cbg.CBORMarshaler) (
|
||||
return mrcid, nil
|
||||
}
|
||||
|
||||
// FetchTipSet tries to load the provided tipset from the store, and falls back
|
||||
// to the network (BlockSync) by querying the supplied peer if not found
|
||||
// locally.
|
||||
//
|
||||
// {hint/usage} This is used from the HELLO protocol, to fetch the greeting
|
||||
// peer's heaviest tipset if we don't have it.
|
||||
func (syncer *Syncer) FetchTipSet(ctx context.Context, p peer.ID, tsk types.TipSetKey) (*store.FullTipSet, error) {
|
||||
if fts, err := syncer.tryLoadFullTipSet(tsk); err == nil {
|
||||
return fts, nil
|
||||
}
|
||||
|
||||
// fall back to the network.
|
||||
return syncer.Bsync.GetFullTipSet(ctx, p, tsk)
|
||||
}
|
||||
|
||||
// tryLoadFullTipSet queries the tipset in the ChainStore, and returns a full
|
||||
// representation of it containing FullBlocks. If ALL blocks are not found
|
||||
// locally, it errors entirely with blockstore.ErrNotFound.
|
||||
func (syncer *Syncer) tryLoadFullTipSet(tsk types.TipSetKey) (*store.FullTipSet, error) {
|
||||
ts, err := syncer.store.LoadTipSet(tsk)
|
||||
if err != nil {
|
||||
@ -401,6 +457,12 @@ func (syncer *Syncer) tryLoadFullTipSet(tsk types.TipSetKey) (*store.FullTipSet,
|
||||
return fts, nil
|
||||
}
|
||||
|
||||
// Sync tries to advance our view of the chain to `maybeHead`. It does nothing
|
||||
// if our current head is heavier than the requested tipset, or if we're already
|
||||
// at the requested head, or if the head is the genesis.
|
||||
//
|
||||
// Most of the heavy-lifting logic happens in syncer#collectChain. Refer to the
|
||||
// godocs on that method for a more detailed view.
|
||||
func (syncer *Syncer) Sync(ctx context.Context, maybeHead *types.TipSet) error {
|
||||
ctx, span := trace.StartSpan(ctx, "chain.Sync")
|
||||
defer span.End()
|
||||
@ -467,16 +529,27 @@ func (syncer *Syncer) ValidateTipSet(ctx context.Context, fts *store.FullTipSet)
|
||||
return nil
|
||||
}
|
||||
|
||||
var futures []async.ErrorFuture
|
||||
for _, b := range fts.Blocks {
|
||||
if err := syncer.ValidateBlock(ctx, b); err != nil {
|
||||
if isPermanent(err) {
|
||||
syncer.bad.Add(b.Cid(), err.Error())
|
||||
}
|
||||
return xerrors.Errorf("validating block %s: %w", b.Cid(), err)
|
||||
}
|
||||
b := b // rebind to a scoped variable
|
||||
|
||||
if err := syncer.sm.ChainStore().AddToTipSetTracker(b.Header); err != nil {
|
||||
return xerrors.Errorf("failed to add validated header to tipset tracker: %w", err)
|
||||
futures = append(futures, async.Err(func() error {
|
||||
if err := syncer.ValidateBlock(ctx, b); err != nil {
|
||||
if isPermanent(err) {
|
||||
syncer.bad.Add(b.Cid(), NewBadBlockReason([]cid.Cid{b.Cid()}, err.Error()))
|
||||
}
|
||||
return xerrors.Errorf("validating block %s: %w", b.Cid(), err)
|
||||
}
|
||||
|
||||
if err := syncer.sm.ChainStore().AddToTipSetTracker(b.Header); err != nil {
|
||||
return xerrors.Errorf("failed to add validated header to tipset tracker: %w", err)
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
}
|
||||
for _, f := range futures {
|
||||
if err := f.AwaitContext(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -529,8 +602,25 @@ func blockSanityChecks(h *types.BlockHeader) error {
|
||||
}
|
||||
|
||||
// ValidateBlock should match up with 'Semantical Validation' in validation.md in the spec
|
||||
func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) error {
|
||||
validationStart := time.Now()
|
||||
func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (err error) {
|
||||
defer func() {
|
||||
// b.Cid() could panic for empty blocks that are used in tests.
|
||||
if rerr := recover(); rerr != nil {
|
||||
err = xerrors.Errorf("validate block panic: %w", rerr)
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
isValidated, err := syncer.store.IsBlockValidated(ctx, b.Cid())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("check block validation cache %s: %w", b.Cid(), err)
|
||||
}
|
||||
|
||||
if isValidated {
|
||||
return nil
|
||||
}
|
||||
|
||||
validationStart := build.Clock.Now()
|
||||
defer func() {
|
||||
dur := time.Since(validationStart)
|
||||
durMilli := dur.Seconds() * float64(1000)
|
||||
@ -542,7 +632,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
||||
defer span.End()
|
||||
|
||||
if build.InsecurePoStValidation {
|
||||
log.Warn("insecure test validation is enabled, if you see this outside of a test, it is a severe bug!")
|
||||
log.Warn("[INSECURE-POST-VALIDATION] if you see this outside of a test, it is a severe bug!")
|
||||
}
|
||||
|
||||
if err := blockSanityChecks(b.Header); err != nil {
|
||||
@ -575,19 +665,19 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
||||
|
||||
// fast checks first
|
||||
|
||||
now := uint64(time.Now().Unix())
|
||||
if h.Timestamp > now+build.AllowableClockDrift {
|
||||
now := uint64(build.Clock.Now().Unix())
|
||||
if h.Timestamp > now+build.AllowableClockDriftSecs {
|
||||
return xerrors.Errorf("block was from the future (now=%d, blk=%d): %w", now, h.Timestamp, ErrTemporal)
|
||||
}
|
||||
if h.Timestamp > now {
|
||||
log.Warn("Got block from the future, but within threshold", h.Timestamp, time.Now().Unix())
|
||||
log.Warn("Got block from the future, but within threshold", h.Timestamp, build.Clock.Now().Unix())
|
||||
}
|
||||
|
||||
if h.Timestamp < baseTs.MinTimestamp()+(build.BlockDelay*uint64(h.Height-baseTs.Height())) {
|
||||
if h.Timestamp < baseTs.MinTimestamp()+(build.BlockDelaySecs*uint64(h.Height-baseTs.Height())) {
|
||||
log.Warn("timestamp funtimes: ", h.Timestamp, baseTs.MinTimestamp(), h.Height, baseTs.Height())
|
||||
diff := (baseTs.MinTimestamp() + (build.BlockDelay * uint64(h.Height-baseTs.Height()))) - h.Timestamp
|
||||
diff := (baseTs.MinTimestamp() + (build.BlockDelaySecs * uint64(h.Height-baseTs.Height()))) - h.Timestamp
|
||||
|
||||
return xerrors.Errorf("block was generated too soon (h.ts:%d < base.mints:%d + BLOCK_DELAY:%d * deltaH:%d; diff %d)", h.Timestamp, baseTs.MinTimestamp(), build.BlockDelay, h.Height-baseTs.Height(), diff)
|
||||
return xerrors.Errorf("block was generated too soon (h.ts:%d < base.mints:%d + BLOCK_DELAY:%d * deltaH:%d; diff %d)", h.Timestamp, baseTs.MinTimestamp(), build.BlockDelaySecs, h.Height-baseTs.Height(), diff)
|
||||
}
|
||||
|
||||
msgsCheck := async.Err(func() error {
|
||||
@ -635,6 +725,10 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
||||
}
|
||||
|
||||
winnerCheck := async.Err(func() error {
|
||||
if h.ElectionProof.WinCount < 1 {
|
||||
return xerrors.Errorf("block is not claiming to be a winner")
|
||||
}
|
||||
|
||||
rBeacon := *prevBeacon
|
||||
if len(h.BeaconEntries) != 0 {
|
||||
rBeacon = h.BeaconEntries[len(h.BeaconEntries)-1]
|
||||
@ -644,13 +738,12 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
||||
return xerrors.Errorf("failed to marshal miner address to cbor: %w", err)
|
||||
}
|
||||
|
||||
//TODO: DST from spec actors when it is there
|
||||
vrfBase, err := store.DrawRandomness(rBeacon.Data, crypto.DomainSeparationTag_ElectionProofProduction, h.Height, buf.Bytes())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("could not draw randomness: %w", err)
|
||||
}
|
||||
|
||||
if err := gen.VerifyVRF(ctx, waddr, vrfBase, h.ElectionProof.VRFProof); err != nil {
|
||||
if err := VerifyElectionPoStVRF(ctx, waddr, vrfBase, h.ElectionProof.VRFProof); err != nil {
|
||||
return xerrors.Errorf("validating block election proof failed: %w", err)
|
||||
}
|
||||
|
||||
@ -668,8 +761,9 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
||||
return xerrors.Errorf("failed getting power: %w", err)
|
||||
}
|
||||
|
||||
if !types.IsTicketWinner(h.ElectionProof.VRFProof, mpow.QualityAdjPower, tpow.QualityAdjPower) {
|
||||
return xerrors.Errorf("miner created a block but was not a winner")
|
||||
j := h.ElectionProof.ComputeWinCount(mpow.QualityAdjPower, tpow.QualityAdjPower)
|
||||
if h.ElectionProof.WinCount != j {
|
||||
return xerrors.Errorf("miner claims wrong number of wins: miner: %d, computed: %d", h.ElectionProof.WinCount, j)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -711,7 +805,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
||||
return xerrors.Errorf("failed to compute vrf base for ticket: %w", err)
|
||||
}
|
||||
|
||||
err = gen.VerifyVRF(ctx, waddr, vrfBase, h.Ticket.VRFProof)
|
||||
err = VerifyElectionPoStVRF(ctx, waddr, vrfBase, h.Ticket.VRFProof)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("validating block tickets failed: %w", err)
|
||||
}
|
||||
@ -759,19 +853,23 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
||||
}
|
||||
}
|
||||
|
||||
return merr
|
||||
if err := syncer.store.MarkBlockAsValidated(ctx, b.Cid()); err != nil {
|
||||
return xerrors.Errorf("caching block validation %s: %w", b.Cid(), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (syncer *Syncer) VerifyWinningPoStProof(ctx context.Context, h *types.BlockHeader, prevBeacon types.BeaconEntry, lbst cid.Cid, waddr address.Address) error {
|
||||
if build.InsecurePoStValidation {
|
||||
if len(h.WinPoStProof) == 0 {
|
||||
return xerrors.Errorf("[TESTING] No winning post proof given")
|
||||
return xerrors.Errorf("[INSECURE-POST-VALIDATION] No winning post proof given")
|
||||
}
|
||||
|
||||
if string(h.WinPoStProof[0].ProofBytes) == "valid proof" {
|
||||
return nil
|
||||
}
|
||||
return xerrors.Errorf("[TESTING] winning post was invalid")
|
||||
return xerrors.Errorf("[INSECURE-POST-VALIDATION] winning post was invalid")
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
@ -852,15 +950,24 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
|
||||
return xerrors.Errorf("failed to load base state tree: %w", err)
|
||||
}
|
||||
|
||||
pl := vm.PricelistByEpoch(baseTs.Height())
|
||||
var sumGasLimit int64
|
||||
checkMsg := func(msg types.ChainMsg) error {
|
||||
m := msg.VMMessage()
|
||||
|
||||
// Phase 1: syntactic validation, as defined in the spec
|
||||
minGas := vm.PricelistByEpoch(baseTs.Height()).OnChainMessage(msg.ChainLength())
|
||||
minGas := pl.OnChainMessage(msg.ChainLength())
|
||||
if err := m.ValidForBlockInclusion(minGas.Total()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// ValidForBlockInclusion checks if any single message does not exceed BlockGasLimit
|
||||
// So below is overflow safe
|
||||
sumGasLimit += m.GasLimit
|
||||
if sumGasLimit > build.BlockGasLimit {
|
||||
return xerrors.Errorf("block gas limit exceeded")
|
||||
}
|
||||
|
||||
// Phase 2: (Partial) semantic validation:
|
||||
// the sender exists and is an account actor, and the nonces make sense
|
||||
if _, ok := nonces[m.From]; !ok {
|
||||
@ -949,23 +1056,14 @@ func (syncer *Syncer) verifyBlsAggregate(ctx context.Context, sig *crypto.Signat
|
||||
trace.Int64Attribute("msgCount", int64(len(msgs))),
|
||||
)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
digests := make([]bls.Digest, len(msgs))
|
||||
for i := 0; i < 10; i++ {
|
||||
wg.Add(1)
|
||||
go func(w int) {
|
||||
defer wg.Done()
|
||||
for j := 0; (j*10)+w < len(msgs); j++ {
|
||||
digests[j*10+w] = bls.Hash(bls.Message(msgs[j*10+w].Bytes()))
|
||||
}
|
||||
}(i)
|
||||
bmsgs := make([]bls.Message, len(msgs))
|
||||
for i, m := range msgs {
|
||||
bmsgs[i] = m.Bytes()
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
var bsig bls.Signature
|
||||
copy(bsig[:], sig.Data)
|
||||
if !bls.Verify(&bsig, digests, pubks) {
|
||||
if !bls.HashVerify(&bsig, bmsgs, pubks) {
|
||||
return xerrors.New("bls aggregate signature failed to verify")
|
||||
}
|
||||
|
||||
@ -982,41 +1080,70 @@ func extractSyncState(ctx context.Context) *SyncerState {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (syncer *Syncer) collectHeaders(ctx context.Context, from *types.TipSet, to *types.TipSet) ([]*types.TipSet, error) {
|
||||
// collectHeaders collects the headers from the blocks between any two tipsets.
|
||||
//
|
||||
// `incoming` is the heaviest/projected/target tipset we have learned about, and
|
||||
// `known` is usually an anchor tipset we already have in our view of the chain
|
||||
// (which could be the genesis).
|
||||
//
|
||||
// collectHeaders checks if portions of the chain are in our ChainStore; falling
|
||||
// down to the network to retrieve the missing parts. If during the process, any
|
||||
// portion we receive is in our denylist (bad list), we short-circuit.
|
||||
//
|
||||
// {hint/usage}: This is used by collectChain, which is in turn called from the
|
||||
// main Sync method (Syncer#Sync), so it's a pretty central method.
|
||||
//
|
||||
// {hint/logic}: The logic of this method is as follows:
|
||||
//
|
||||
// 1. Check that the from tipset is not linked to a parent block known to be
|
||||
// bad.
|
||||
// 2. Check the consistency of beacon entries in the from tipset. We check
|
||||
// total equality of the BeaconEntries in each block.
|
||||
// 3. Traverse the chain backwards, for each tipset:
|
||||
// 3a. Load it from the chainstore; if found, it move on to its parent.
|
||||
// 3b. Query our peers via BlockSync in batches, requesting up to a
|
||||
// maximum of 500 tipsets every time.
|
||||
//
|
||||
// Once we've concluded, if we find a mismatching tipset at the height where the
|
||||
// anchor tipset should be, we are facing a fork, and we invoke Syncer#syncFork
|
||||
// to resolve it. Refer to the godocs there.
|
||||
//
|
||||
// All throughout the process, we keep checking if the received blocks are in
|
||||
// the deny list, and short-circuit the process if so.
|
||||
func (syncer *Syncer) collectHeaders(ctx context.Context, incoming *types.TipSet, known *types.TipSet) ([]*types.TipSet, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "collectHeaders")
|
||||
defer span.End()
|
||||
ss := extractSyncState(ctx)
|
||||
|
||||
span.AddAttributes(
|
||||
trace.Int64Attribute("fromHeight", int64(from.Height())),
|
||||
trace.Int64Attribute("toHeight", int64(to.Height())),
|
||||
trace.Int64Attribute("incomingHeight", int64(incoming.Height())),
|
||||
trace.Int64Attribute("knownHeight", int64(known.Height())),
|
||||
)
|
||||
|
||||
markBad := func(fmts string, args ...interface{}) {
|
||||
for _, b := range from.Cids() {
|
||||
syncer.bad.Add(b, fmt.Sprintf(fmts, args...))
|
||||
}
|
||||
}
|
||||
|
||||
for _, pcid := range from.Parents().Cids() {
|
||||
// Check if the parents of the from block are in the denylist.
|
||||
// i.e. if a fork of the chain has been requested that we know to be bad.
|
||||
for _, pcid := range incoming.Parents().Cids() {
|
||||
if reason, ok := syncer.bad.Has(pcid); ok {
|
||||
markBad("linked to %s", pcid)
|
||||
return nil, xerrors.Errorf("chain linked to block marked previously as bad (%s, %s) (reason: %s)", from.Cids(), pcid, reason)
|
||||
newReason := reason.Linked("linked to %s", pcid)
|
||||
for _, b := range incoming.Cids() {
|
||||
syncer.bad.Add(b, newReason)
|
||||
}
|
||||
return nil, xerrors.Errorf("chain linked to block marked previously as bad (%s, %s) (reason: %s)", incoming.Cids(), pcid, reason)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// ensure consistency of beacon entires
|
||||
targetBE := from.Blocks()[0].BeaconEntries
|
||||
targetBE := incoming.Blocks()[0].BeaconEntries
|
||||
sorted := sort.SliceIsSorted(targetBE, func(i, j int) bool {
|
||||
return targetBE[i].Round < targetBE[j].Round
|
||||
})
|
||||
if !sorted {
|
||||
syncer.bad.Add(from.Cids()[0], "wrong order of beacon entires")
|
||||
syncer.bad.Add(incoming.Cids()[0], NewBadBlockReason(incoming.Cids(), "wrong order of beacon entires"))
|
||||
return nil, xerrors.Errorf("wrong order of beacon entires")
|
||||
}
|
||||
|
||||
for _, bh := range from.Blocks()[1:] {
|
||||
for _, bh := range incoming.Blocks()[1:] {
|
||||
if len(targetBE) != len(bh.BeaconEntries) {
|
||||
// cannot mark bad, I think @Kubuxu
|
||||
return nil, xerrors.Errorf("tipset contained different number for beacon entires")
|
||||
@ -1031,12 +1158,12 @@ func (syncer *Syncer) collectHeaders(ctx context.Context, from *types.TipSet, to
|
||||
}
|
||||
}
|
||||
|
||||
blockSet := []*types.TipSet{from}
|
||||
blockSet := []*types.TipSet{incoming}
|
||||
|
||||
at := from.Parents()
|
||||
at := incoming.Parents()
|
||||
|
||||
// we want to sync all the blocks until the height above the block we have
|
||||
untilHeight := to.Height() + 1
|
||||
untilHeight := known.Height() + 1
|
||||
|
||||
ss.SetHeight(blockSet[len(blockSet)-1].Height())
|
||||
|
||||
@ -1046,11 +1173,12 @@ loop:
|
||||
for blockSet[len(blockSet)-1].Height() > untilHeight {
|
||||
for _, bc := range at.Cids() {
|
||||
if reason, ok := syncer.bad.Has(bc); ok {
|
||||
newReason := reason.Linked("change contained %s", bc)
|
||||
for _, b := range acceptedBlocks {
|
||||
syncer.bad.Add(b, fmt.Sprintf("chain contained %s", bc))
|
||||
syncer.bad.Add(b, newReason)
|
||||
}
|
||||
|
||||
return nil, xerrors.Errorf("chain contained block marked previously as bad (%s, %s) (reason: %s)", from.Cids(), bc, reason)
|
||||
return nil, xerrors.Errorf("chain contained block marked previously as bad (%s, %s) (reason: %s)", incoming.Cids(), bc, reason)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1068,8 +1196,8 @@ loop:
|
||||
}
|
||||
|
||||
// NB: GetBlocks validates that the blocks are in-fact the ones we
|
||||
// requested, and that they are correctly linked to eachother. It does
|
||||
// not validate any state transitions
|
||||
// requested, and that they are correctly linked to one another. It does
|
||||
// not validate any state transitions.
|
||||
window := 500
|
||||
if gap := int(blockSet[len(blockSet)-1].Height() - untilHeight); gap < window {
|
||||
window = gap
|
||||
@ -1094,11 +1222,12 @@ loop:
|
||||
}
|
||||
for _, bc := range b.Cids() {
|
||||
if reason, ok := syncer.bad.Has(bc); ok {
|
||||
newReason := reason.Linked("change contained %s", bc)
|
||||
for _, b := range acceptedBlocks {
|
||||
syncer.bad.Add(b, fmt.Sprintf("chain contained %s", bc))
|
||||
syncer.bad.Add(b, newReason)
|
||||
}
|
||||
|
||||
return nil, xerrors.Errorf("chain contained block marked previously as bad (%s, %s) (reason: %s)", from.Cids(), bc, reason)
|
||||
return nil, xerrors.Errorf("chain contained block marked previously as bad (%s, %s) (reason: %s)", incoming.Cids(), bc, reason)
|
||||
}
|
||||
}
|
||||
blockSet = append(blockSet, b)
|
||||
@ -1110,22 +1239,23 @@ loop:
|
||||
at = blks[len(blks)-1].Parents()
|
||||
}
|
||||
|
||||
// We have now ascertained that this is *not* a 'fast forward'
|
||||
if !types.CidArrsEqual(blockSet[len(blockSet)-1].Parents().Cids(), to.Cids()) {
|
||||
last := blockSet[len(blockSet)-1]
|
||||
if last.Parents() == to.Parents() {
|
||||
// base is the tipset in the candidate chain at the height equal to our known tipset height.
|
||||
if base := blockSet[len(blockSet)-1]; !types.CidArrsEqual(base.Parents().Cids(), known.Cids()) {
|
||||
if base.Parents() == known.Parents() {
|
||||
// common case: receiving a block thats potentially part of the same tipset as our best block
|
||||
return blockSet, nil
|
||||
}
|
||||
|
||||
log.Warnf("(fork detected) synced header chain (%s - %d) does not link to our best block (%s - %d)", from.Cids(), from.Height(), to.Cids(), to.Height())
|
||||
fork, err := syncer.syncFork(ctx, last, to)
|
||||
// We have now ascertained that this is *not* a 'fast forward'
|
||||
|
||||
log.Warnf("(fork detected) synced header chain (%s - %d) does not link to our best block (%s - %d)", incoming.Cids(), incoming.Height(), known.Cids(), known.Height())
|
||||
fork, err := syncer.syncFork(ctx, base, known)
|
||||
if err != nil {
|
||||
if xerrors.Is(err, ErrForkTooLong) {
|
||||
// TODO: we're marking this block bad in the same way that we mark invalid blocks bad. Maybe distinguish?
|
||||
log.Warn("adding forked chain to our bad tipset cache")
|
||||
for _, b := range from.Blocks() {
|
||||
syncer.bad.Add(b.Cid(), "fork past finality")
|
||||
for _, b := range incoming.Blocks() {
|
||||
syncer.bad.Add(b.Cid(), NewBadBlockReason(incoming.Cids(), "fork past finality"))
|
||||
}
|
||||
}
|
||||
return nil, xerrors.Errorf("failed to sync fork: %w", err)
|
||||
@ -1139,13 +1269,19 @@ loop:
|
||||
|
||||
var ErrForkTooLong = fmt.Errorf("fork longer than threshold")
|
||||
|
||||
func (syncer *Syncer) syncFork(ctx context.Context, from *types.TipSet, to *types.TipSet) ([]*types.TipSet, error) {
|
||||
tips, err := syncer.Bsync.GetBlocks(ctx, from.Parents(), int(build.ForkLengthThreshold))
|
||||
// syncFork tries to obtain the chain fragment that links a fork into a common
|
||||
// ancestor in our view of the chain.
|
||||
//
|
||||
// If the fork is too long (build.ForkLengthThreshold), we add the entire subchain to the
|
||||
// denylist. Else, we find the common ancestor, and add the missing chain
|
||||
// fragment until the fork point to the returned []TipSet.
|
||||
func (syncer *Syncer) syncFork(ctx context.Context, incoming *types.TipSet, known *types.TipSet) ([]*types.TipSet, error) {
|
||||
tips, err := syncer.Bsync.GetBlocks(ctx, incoming.Parents(), int(build.ForkLengthThreshold))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nts, err := syncer.store.LoadTipSet(to.Parents())
|
||||
nts, err := syncer.store.LoadTipSet(known.Parents())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load next local tipset: %w", err)
|
||||
}
|
||||
@ -1155,7 +1291,7 @@ func (syncer *Syncer) syncFork(ctx context.Context, from *types.TipSet, to *type
|
||||
if !syncer.Genesis.Equals(nts) {
|
||||
return nil, xerrors.Errorf("somehow synced chain that linked back to a different genesis (bad genesis: %s)", nts.Key())
|
||||
}
|
||||
return nil, xerrors.Errorf("synced chain forked at genesis, refusing to sync")
|
||||
return nil, xerrors.Errorf("synced chain forked at genesis, refusing to sync; incoming: %s")
|
||||
}
|
||||
|
||||
if nts.Equals(tips[cur]) {
|
||||
@ -1290,6 +1426,25 @@ func persistMessages(bs bstore.Blockstore, bst *blocksync.BSTipSet) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// collectChain tries to advance our view of the chain to the purported head.
|
||||
//
|
||||
// It goes through various stages:
|
||||
//
|
||||
// 1. StageHeaders: we proceed in the sync process by requesting block headers
|
||||
// from our peers, moving back from their heads, until we reach a tipset
|
||||
// that we have in common (such a common tipset must exist, thought it may
|
||||
// simply be the genesis block).
|
||||
//
|
||||
// If the common tipset is our head, we treat the sync as a "fast-forward",
|
||||
// else we must drop part of our chain to connect to the peer's head
|
||||
// (referred to as "forking").
|
||||
//
|
||||
// 2. StagePersistHeaders: now that we've collected the missing headers,
|
||||
// augmented by those on the other side of a fork, we persist them to the
|
||||
// BlockStore.
|
||||
//
|
||||
// 3. StageMessages: having acquired the headers and found a common tipset,
|
||||
// we then move forward, requesting the full blocks, including the messages.
|
||||
func (syncer *Syncer) collectChain(ctx context.Context, ts *types.TipSet) error {
|
||||
ctx, span := trace.StartSpan(ctx, "collectChain")
|
||||
defer span.End()
|
||||
@ -1336,12 +1491,11 @@ func (syncer *Syncer) collectChain(ctx context.Context, ts *types.TipSet) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func VerifyElectionPoStVRF(ctx context.Context, evrf []byte, rand []byte, worker address.Address) error {
|
||||
if err := gen.VerifyVRF(ctx, worker, rand, evrf); err != nil {
|
||||
return xerrors.Errorf("failed to verify post_randomness vrf: %w", err)
|
||||
func VerifyElectionPoStVRF(ctx context.Context, worker address.Address, rand []byte, evrf []byte) error {
|
||||
if build.InsecurePoStValidation {
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
return gen.VerifyVRF(ctx, worker, rand, evrf)
|
||||
}
|
||||
|
||||
func (syncer *Syncer) State() []SyncerState {
|
||||
@ -1352,14 +1506,17 @@ func (syncer *Syncer) State() []SyncerState {
|
||||
return out
|
||||
}
|
||||
|
||||
// MarkBad manually adds a block to the "bad blocks" cache.
|
||||
func (syncer *Syncer) MarkBad(blk cid.Cid) {
|
||||
syncer.bad.Add(blk, "manually marked bad")
|
||||
syncer.bad.Add(blk, NewBadBlockReason([]cid.Cid{blk}, "manually marked bad"))
|
||||
}
|
||||
|
||||
func (syncer *Syncer) CheckBadBlockCache(blk cid.Cid) (string, bool) {
|
||||
return syncer.bad.Has(blk)
|
||||
bbr, ok := syncer.bad.Has(blk)
|
||||
return bbr.String(), ok
|
||||
}
|
||||
func (syncer *Syncer) getLatestBeaconEntry(ctx context.Context, ts *types.TipSet) (*types.BeaconEntry, error) {
|
||||
|
||||
func (syncer *Syncer) getLatestBeaconEntry(_ context.Context, ts *types.TipSet) (*types.BeaconEntry, error) {
|
||||
cur := ts
|
||||
for i := 0; i < 20; i++ {
|
||||
cbe := cur.Blocks()[0].BeaconEntries
|
||||
@ -1380,3 +1537,13 @@ func (syncer *Syncer) getLatestBeaconEntry(ctx context.Context, ts *types.TipSet
|
||||
|
||||
return nil, xerrors.Errorf("found NO beacon entries in the 20 blocks prior to given tipset")
|
||||
}
|
||||
|
||||
func (syncer *Syncer) IsEpochBeyondCurrMax(epoch abi.ChainEpoch) bool {
|
||||
g, err := syncer.store.GetGenesis()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
now := uint64(build.Clock.Now().Unix())
|
||||
return epoch > (abi.ChainEpoch((now-g.Timestamp)/build.BlockDelaySecs) + MaxHeightDrift)
|
||||
}
|
||||
|
@ -34,8 +34,8 @@ import (
|
||||
func init() {
|
||||
build.InsecurePoStValidation = true
|
||||
os.Setenv("TRUST_PARAMS", "1")
|
||||
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
|
||||
abi.RegisteredProof_StackedDRG2KiBSeal: {},
|
||||
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||
}
|
||||
power.ConsensusMinerMinPower = big.NewInt(2048)
|
||||
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
||||
@ -408,7 +408,7 @@ func TestSyncBadTimestamp(t *testing.T) {
|
||||
|
||||
base := tu.g.CurTipset
|
||||
tu.g.Timestamper = func(pts *types.TipSet, tl abi.ChainEpoch) uint64 {
|
||||
return pts.MinTimestamp() + (build.BlockDelay / 2)
|
||||
return pts.MinTimestamp() + (build.BlockDelaySecs / 2)
|
||||
}
|
||||
|
||||
fmt.Println("BASE: ", base.Cids())
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
@ -48,7 +49,7 @@ func (ss *SyncerState) SetStage(v api.SyncStateStage) {
|
||||
defer ss.lk.Unlock()
|
||||
ss.Stage = v
|
||||
if v == api.StageSyncComplete {
|
||||
ss.End = time.Now()
|
||||
ss.End = build.Clock.Now()
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,7 +65,7 @@ func (ss *SyncerState) Init(base, target *types.TipSet) {
|
||||
ss.Stage = api.StageHeaders
|
||||
ss.Height = 0
|
||||
ss.Message = ""
|
||||
ss.Start = time.Now()
|
||||
ss.Start = build.Clock.Now()
|
||||
ss.End = time.Time{}
|
||||
}
|
||||
|
||||
@ -87,7 +88,7 @@ func (ss *SyncerState) Error(err error) {
|
||||
defer ss.lk.Unlock()
|
||||
ss.Message = err.Error()
|
||||
ss.Stage = api.StageSyncErrored
|
||||
ss.End = time.Now()
|
||||
ss.End = build.Clock.Now()
|
||||
}
|
||||
|
||||
func (ss *SyncerState) Snapshot() SyncerState {
|
||||
|
@ -76,7 +76,7 @@ func SizeStr(bi BigInt) string {
|
||||
}
|
||||
|
||||
f, _ := r.Float64()
|
||||
return fmt.Sprintf("%.3g %s", f, byteSizeUnits[i])
|
||||
return fmt.Sprintf("%.4g %s", f, byteSizeUnits[i])
|
||||
}
|
||||
|
||||
var deciUnits = []string{"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"}
|
||||
|
@ -3,7 +3,12 @@ package types
|
||||
import (
|
||||
"bytes"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/go-units"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@ -38,7 +43,7 @@ func TestBigIntSerializationRoundTrip(t *testing.T) {
|
||||
|
||||
func TestFilRoundTrip(t *testing.T) {
|
||||
testValues := []string{
|
||||
"0", "1", "1.001", "100.10001", "101100", "5000.01", "5000",
|
||||
"0 FIL", "1 FIL", "1.001 FIL", "100.10001 FIL", "101100 FIL", "5000.01 FIL", "5000 FIL",
|
||||
}
|
||||
|
||||
for _, v := range testValues {
|
||||
@ -60,8 +65,10 @@ func TestSizeStr(t *testing.T) {
|
||||
}{
|
||||
{0, "0 B"},
|
||||
{1, "1 B"},
|
||||
{1016, "1016 B"},
|
||||
{1024, "1 KiB"},
|
||||
{2000, "1.95 KiB"},
|
||||
{1000 * 1024, "1000 KiB"},
|
||||
{2000, "1.953 KiB"},
|
||||
{5 << 20, "5 MiB"},
|
||||
{11 << 60, "11 EiB"},
|
||||
}
|
||||
@ -71,6 +78,22 @@ func TestSizeStr(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSizeStrUnitsSymmetry(t *testing.T) {
|
||||
s := rand.NewSource(time.Now().UnixNano())
|
||||
r := rand.New(s)
|
||||
|
||||
for i := 0; i < 10000; i++ {
|
||||
n := r.Uint64()
|
||||
l := strings.ReplaceAll(units.BytesSize(float64(n)), " ", "")
|
||||
r := strings.ReplaceAll(SizeStr(NewInt(n)), " ", "")
|
||||
|
||||
assert.NotContains(t, l, "e+")
|
||||
assert.NotContains(t, r, "e+")
|
||||
|
||||
assert.Equal(t, l, r, "wrong formatting for %d", n)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSizeStrBig(t *testing.T) {
|
||||
ZiB := big.NewInt(50000)
|
||||
ZiB = ZiB.Lsh(ZiB, 70)
|
||||
|
@ -23,10 +23,6 @@ type Ticket struct {
|
||||
VRFProof []byte
|
||||
}
|
||||
|
||||
type ElectionProof struct {
|
||||
VRFProof []byte
|
||||
}
|
||||
|
||||
type BeaconEntry struct {
|
||||
Round uint64
|
||||
Data []byte
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"testing"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
@ -79,13 +80,13 @@ func TestInteropBH(t *testing.T) {
|
||||
}
|
||||
|
||||
posts := []abi.PoStProof{
|
||||
{abi.RegisteredProof_StackedDRG2KiBWinningPoSt, []byte{0x07}},
|
||||
{abi.RegisteredPoStProof_StackedDrgWinning2KiBV1, []byte{0x07}},
|
||||
}
|
||||
|
||||
bh := &BlockHeader{
|
||||
Miner: newAddr,
|
||||
Ticket: &Ticket{[]byte{0x01, 0x02, 0x03}},
|
||||
ElectionProof: &ElectionProof{[]byte{0x0a, 0x0b}},
|
||||
ElectionProof: &ElectionProof{0, []byte{0x0a, 0x0b}},
|
||||
BeaconEntries: []BeaconEntry{
|
||||
{
|
||||
Round: 5,
|
||||
@ -115,11 +116,8 @@ func TestInteropBH(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// acquired from go-filecoin
|
||||
gfc := "8f5501d04cb15021bf6bd003073d79e2238d4e61f1ad22814301020381420a0b818205410c818209410781d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc430003e802d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc410001f603"
|
||||
if gfc != hex.EncodeToString(bhsb) {
|
||||
t.Fatal("not equal!")
|
||||
}
|
||||
gfc := "8f5501d04cb15021bf6bd003073d79e2238d4e61f1ad2281430102038200420a0b818205410c818200410781d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc430003e802d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc410001f603"
|
||||
require.Equal(t, gfc, hex.EncodeToString(bhsb))
|
||||
}
|
||||
|
||||
func BenchmarkBlockHeaderMarshal(b *testing.B) {
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
||||
"github.com/ipfs/go-cid"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
xerrors "golang.org/x/xerrors"
|
||||
)
|
||||
@ -146,6 +146,8 @@ func (t *BlockHeader) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *BlockHeader) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = BlockHeader{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@ -470,6 +472,8 @@ func (t *Ticket) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *Ticket) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = Ticket{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@ -505,7 +509,7 @@ func (t *Ticket) UnmarshalCBOR(r io.Reader) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var lengthBufElectionProof = []byte{129}
|
||||
var lengthBufElectionProof = []byte{130}
|
||||
|
||||
func (t *ElectionProof) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
@ -518,6 +522,17 @@ func (t *ElectionProof) MarshalCBOR(w io.Writer) error {
|
||||
|
||||
scratch := make([]byte, 9)
|
||||
|
||||
// t.WinCount (int64) (int64)
|
||||
if t.WinCount >= 0 {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.WinCount)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.WinCount-1)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// t.VRFProof ([]uint8) (slice)
|
||||
if len(t.VRFProof) > cbg.ByteArrayMaxLen {
|
||||
return xerrors.Errorf("Byte array in field t.VRFProof was too long")
|
||||
@ -534,6 +549,8 @@ func (t *ElectionProof) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *ElectionProof) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = ElectionProof{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@ -545,10 +562,35 @@ func (t *ElectionProof) UnmarshalCBOR(r io.Reader) error {
|
||||
return fmt.Errorf("cbor input should be of type array")
|
||||
}
|
||||
|
||||
if extra != 1 {
|
||||
if extra != 2 {
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
}
|
||||
|
||||
// t.WinCount (int64) (int64)
|
||||
{
|
||||
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
var extraI int64
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch maj {
|
||||
case cbg.MajUnsignedInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 positive overflow")
|
||||
}
|
||||
case cbg.MajNegativeInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 negative oveflow")
|
||||
}
|
||||
extraI = -1 - extraI
|
||||
default:
|
||||
return fmt.Errorf("wrong type for int64 field: %d", maj)
|
||||
}
|
||||
|
||||
t.WinCount = int64(extraI)
|
||||
}
|
||||
// t.VRFProof ([]uint8) (slice)
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
@ -652,6 +694,8 @@ func (t *Message) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *Message) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = Message{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@ -825,6 +869,8 @@ func (t *SignedMessage) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *SignedMessage) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = SignedMessage{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@ -890,6 +936,8 @@ func (t *MsgMeta) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *MsgMeta) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = MsgMeta{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@ -971,6 +1019,8 @@ func (t *Actor) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *Actor) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = Actor{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@ -1087,6 +1137,8 @@ func (t *MessageReceipt) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *MessageReceipt) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = MessageReceipt{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@ -1221,6 +1273,8 @@ func (t *BlockMsg) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *BlockMsg) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = BlockMsg{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@ -1371,6 +1425,8 @@ func (t *ExpTipSet) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *ExpTipSet) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = ExpTipSet{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
@ -1506,6 +1562,8 @@ func (t *BeaconEntry) MarshalCBOR(w io.Writer) error {
|
||||
}
|
||||
|
||||
func (t *BeaconEntry) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = BeaconEntry{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
|
205
chain/types/electionproof.go
Normal file
205
chain/types/electionproof.go
Normal file
@ -0,0 +1,205 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/minio/blake2b-simd"
|
||||
)
|
||||
|
||||
type ElectionProof struct {
|
||||
WinCount int64
|
||||
VRFProof []byte
|
||||
}
|
||||
|
||||
const precision = 256
|
||||
|
||||
var (
|
||||
expNumCoef []*big.Int
|
||||
expDenoCoef []*big.Int
|
||||
)
|
||||
|
||||
func init() {
|
||||
parse := func(coefs []string) []*big.Int {
|
||||
out := make([]*big.Int, len(coefs))
|
||||
for i, coef := range coefs {
|
||||
c, ok := new(big.Int).SetString(coef, 10)
|
||||
if !ok {
|
||||
panic("could not parse exp paramemter")
|
||||
}
|
||||
// << 256 (Q.0 to Q.256), >> 128 to transform integer params to coefficients
|
||||
c = c.Lsh(c, precision-128)
|
||||
out[i] = c
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// parameters are in integer format,
|
||||
// coefficients are *2^-128 of that
|
||||
num := []string{
|
||||
"-648770010757830093818553637600",
|
||||
"67469480939593786226847644286976",
|
||||
"-3197587544499098424029388939001856",
|
||||
"89244641121992890118377641805348864",
|
||||
"-1579656163641440567800982336819953664",
|
||||
"17685496037279256458459817590917169152",
|
||||
"-115682590513835356866803355398940131328",
|
||||
"340282366920938463463374607431768211456",
|
||||
}
|
||||
expNumCoef = parse(num)
|
||||
|
||||
deno := []string{
|
||||
"1225524182432722209606361",
|
||||
"114095592300906098243859450",
|
||||
"5665570424063336070530214243",
|
||||
"194450132448609991765137938448",
|
||||
"5068267641632683791026134915072",
|
||||
"104716890604972796896895427629056",
|
||||
"1748338658439454459487681798864896",
|
||||
"23704654329841312470660182937960448",
|
||||
"259380097567996910282699886670381056",
|
||||
"2250336698853390384720606936038375424",
|
||||
"14978272436876548034486263159246028800",
|
||||
"72144088983913131323343765784380833792",
|
||||
"224599776407103106596571252037123047424",
|
||||
"340282366920938463463374607431768211456",
|
||||
}
|
||||
expDenoCoef = parse(deno)
|
||||
}
|
||||
|
||||
// expneg accepts x in Q.256 format and computes e^-x.
|
||||
// It is most precise within [0, 1.725) range, where error is less than 3.4e-30.
|
||||
// Over the [0, 5) range its error is less than 4.6e-15.
|
||||
// Output is in Q.256 format.
|
||||
func expneg(x *big.Int) *big.Int {
|
||||
// exp is approximated by rational function
|
||||
// polynomials of the rational function are evaluated using Horner's method
|
||||
num := polyval(expNumCoef, x) // Q.256
|
||||
deno := polyval(expDenoCoef, x) // Q.256
|
||||
|
||||
num = num.Lsh(num, precision) // Q.512
|
||||
return num.Div(num, deno) // Q.512 / Q.256 => Q.256
|
||||
}
|
||||
|
||||
// polyval evaluates a polynomial given by coefficients `p` in Q.256 format
|
||||
// at point `x` in Q.256 format. Output is in Q.256.
|
||||
// Coefficients should be ordered from the highest order coefficient to the lowest.
|
||||
func polyval(p []*big.Int, x *big.Int) *big.Int {
|
||||
// evaluation using Horner's method
|
||||
res := new(big.Int).Set(p[0]) // Q.256
|
||||
tmp := new(big.Int) // big.Int.Mul doesn't like when input is reused as output
|
||||
for _, c := range p[1:] {
|
||||
tmp = tmp.Mul(res, x) // Q.256 * Q.256 => Q.512
|
||||
res = res.Rsh(tmp, precision) // Q.512 >> 256 => Q.256
|
||||
res = res.Add(res, c)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// computes lambda in Q.256
|
||||
func lambda(power, totalPower *big.Int) *big.Int {
|
||||
lam := new(big.Int).Mul(power, blocksPerEpoch.Int) // Q.0
|
||||
lam = lam.Lsh(lam, precision) // Q.256
|
||||
lam = lam.Div(lam /* Q.256 */, totalPower /* Q.0 */) // Q.256
|
||||
return lam
|
||||
}
|
||||
|
||||
var MaxWinCount = 3 * int64(build.BlocksPerEpoch)
|
||||
|
||||
type poiss struct {
|
||||
lam *big.Int
|
||||
pmf *big.Int
|
||||
icdf *big.Int
|
||||
|
||||
tmp *big.Int // temporary variable for optimization
|
||||
|
||||
k uint64
|
||||
}
|
||||
|
||||
// newPoiss starts poisson inverted CDF
|
||||
// lambda is in Q.256 format
|
||||
// returns (instance, `1-poisscdf(0, lambda)`)
|
||||
// CDF value returend is reused when calling `next`
|
||||
func newPoiss(lambda *big.Int) (*poiss, *big.Int) {
|
||||
|
||||
// pmf(k) = (lambda^k)*(e^lambda) / k!
|
||||
// k = 0 here, so it simplifies to just e^-lambda
|
||||
elam := expneg(lambda) // Q.256
|
||||
pmf := new(big.Int).Set(elam)
|
||||
|
||||
// icdf(k) = 1 - ∑ᵏᵢ₌₀ pmf(i)
|
||||
// icdf(0) = 1 - pmf(0)
|
||||
icdf := big.NewInt(1)
|
||||
icdf = icdf.Lsh(icdf, precision) // Q.256
|
||||
icdf = icdf.Sub(icdf, pmf) // Q.256
|
||||
|
||||
k := uint64(0)
|
||||
|
||||
p := &poiss{
|
||||
lam: lambda,
|
||||
pmf: pmf,
|
||||
|
||||
tmp: elam,
|
||||
icdf: icdf,
|
||||
|
||||
k: k,
|
||||
}
|
||||
|
||||
return p, icdf
|
||||
}
|
||||
|
||||
// next computes `k++, 1-poisscdf(k, lam)`
|
||||
// return is in Q.256 format
|
||||
func (p *poiss) next() *big.Int {
|
||||
// incrementally compute next pmf and icdf
|
||||
|
||||
// pmf(k) = (lambda^k)*(e^lambda) / k!
|
||||
// so pmf(k) = pmf(k-1) * lambda / k
|
||||
p.k++
|
||||
p.tmp.SetUint64(p.k) // Q.0
|
||||
|
||||
// calculate pmf for k
|
||||
p.pmf = p.pmf.Div(p.pmf, p.tmp) // Q.256 / Q.0 => Q.256
|
||||
// we are using `tmp` as target for multiplication as using an input as output
|
||||
// for Int.Mul causes allocations
|
||||
p.tmp = p.tmp.Mul(p.pmf, p.lam) // Q.256 * Q.256 => Q.512
|
||||
p.pmf = p.pmf.Rsh(p.tmp, precision) // Q.512 >> 256 => Q.256
|
||||
|
||||
// calculate output
|
||||
// icdf(k) = icdf(k-1) - pmf(k)
|
||||
p.icdf = p.icdf.Sub(p.icdf, p.pmf) // Q.256
|
||||
return p.icdf
|
||||
}
|
||||
|
||||
// ComputeWinCount uses VRFProof to compute number of wins
|
||||
// The algorithm is based on Algorand's Sortition with Binomial distribution
|
||||
// replaced by Poisson distribution.
|
||||
func (ep *ElectionProof) ComputeWinCount(power BigInt, totalPower BigInt) int64 {
|
||||
h := blake2b.Sum256(ep.VRFProof)
|
||||
|
||||
lhs := BigFromBytes(h[:]).Int // 256bits, assume Q.256 so [0, 1)
|
||||
|
||||
// We are calculating upside-down CDF of Poisson distribution with
|
||||
// rate λ=power*E/totalPower
|
||||
// Steps:
|
||||
// 1. calculate λ=power*E/totalPower
|
||||
// 2. calculate elam = exp(-λ)
|
||||
// 3. Check how many times we win:
|
||||
// j = 0
|
||||
// pmf = elam
|
||||
// rhs = 1 - pmf
|
||||
// for h(vrf) < rhs: j++; pmf = pmf * lam / j; rhs = rhs - pmf
|
||||
|
||||
lam := lambda(power.Int, totalPower.Int) // Q.256
|
||||
|
||||
p, rhs := newPoiss(lam)
|
||||
|
||||
var j int64
|
||||
for lhs.Cmp(rhs) < 0 && j < MaxWinCount {
|
||||
rhs = p.next()
|
||||
j++
|
||||
}
|
||||
|
||||
return j
|
||||
}
|
145
chain/types/electionproof_test.go
Normal file
145
chain/types/electionproof_test.go
Normal file
@ -0,0 +1,145 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/xorcare/golden"
|
||||
)
|
||||
|
||||
func TestPoissonFunction(t *testing.T) {
|
||||
tests := []struct {
|
||||
lambdaBase uint64
|
||||
lambdaShift uint
|
||||
}{
|
||||
{10, 10}, // 0.0097
|
||||
{209714, 20}, // 0.19999885
|
||||
{1036915, 20}, // 0.9888792038
|
||||
{1706, 10}, // 1.6660
|
||||
{2, 0}, // 2
|
||||
{5242879, 20}, //4.9999990
|
||||
{5, 0}, // 5
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(fmt.Sprintf("lam-%d-%d", test.lambdaBase, test.lambdaShift), func(t *testing.T) {
|
||||
b := &bytes.Buffer{}
|
||||
b.WriteString("icdf\n")
|
||||
|
||||
lam := new(big.Int).SetUint64(test.lambdaBase)
|
||||
lam = lam.Lsh(lam, precision-test.lambdaShift)
|
||||
p, icdf := newPoiss(lam)
|
||||
|
||||
b.WriteString(icdf.String())
|
||||
b.WriteRune('\n')
|
||||
|
||||
for i := 0; i < 15; i++ {
|
||||
b.WriteString(p.next().String())
|
||||
b.WriteRune('\n')
|
||||
}
|
||||
golden.Assert(t, []byte(b.String()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLambdaFunction(t *testing.T) {
|
||||
tests := []struct {
|
||||
power string
|
||||
totalPower string
|
||||
target float64
|
||||
}{
|
||||
{"10", "100", .1 * 5.},
|
||||
{"1024", "2048", 0.5 * 5.},
|
||||
{"2000000000000000", "100000000000000000", 0.02 * 5.},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(fmt.Sprintf("%s-%s", test.power, test.totalPower), func(t *testing.T) {
|
||||
pow, ok := new(big.Int).SetString(test.power, 10)
|
||||
assert.True(t, ok)
|
||||
total, ok := new(big.Int).SetString(test.totalPower, 10)
|
||||
assert.True(t, ok)
|
||||
lam := lambda(pow, total)
|
||||
assert.Equal(t, test.target, q256ToF(lam))
|
||||
golden.Assert(t, []byte(lam.String()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpFunction(t *testing.T) {
|
||||
const N = 256
|
||||
|
||||
step := big.NewInt(5)
|
||||
step = step.Lsh(step, 256) // Q.256
|
||||
step = step.Div(step, big.NewInt(N-1))
|
||||
|
||||
x := big.NewInt(0)
|
||||
b := &bytes.Buffer{}
|
||||
|
||||
b.WriteString("x, y\n")
|
||||
for i := 0; i < N; i++ {
|
||||
y := expneg(x)
|
||||
fmt.Fprintf(b, "%s,%s\n", x, y)
|
||||
x = x.Add(x, step)
|
||||
}
|
||||
|
||||
golden.Assert(t, b.Bytes())
|
||||
}
|
||||
|
||||
func q256ToF(x *big.Int) float64 {
|
||||
deno := big.NewInt(1)
|
||||
deno = deno.Lsh(deno, 256)
|
||||
rat := new(big.Rat).SetFrac(x, deno)
|
||||
f, _ := rat.Float64()
|
||||
return f
|
||||
}
|
||||
|
||||
func TestElectionLam(t *testing.T) {
|
||||
p := big.NewInt(64)
|
||||
tot := big.NewInt(128)
|
||||
lam := lambda(p, tot)
|
||||
target := 64. * 5. / 128.
|
||||
if q256ToF(lam) != target {
|
||||
t.Fatalf("wrong lambda: %f, should be: %f", q256ToF(lam), target)
|
||||
}
|
||||
}
|
||||
|
||||
var Res int64
|
||||
|
||||
func BenchmarkWinCounts(b *testing.B) {
|
||||
totalPower := NewInt(100)
|
||||
power := NewInt(100)
|
||||
ep := &ElectionProof{VRFProof: nil}
|
||||
var res int64
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ep.VRFProof = []byte{byte(i), byte(i >> 8), byte(i >> 16), byte(i >> 24), byte(i >> 32)}
|
||||
j := ep.ComputeWinCount(power, totalPower)
|
||||
res += j
|
||||
}
|
||||
Res += res
|
||||
}
|
||||
|
||||
func TestWinCounts(t *testing.T) {
|
||||
t.SkipNow()
|
||||
totalPower := NewInt(100)
|
||||
power := NewInt(30)
|
||||
|
||||
f, _ := os.Create("output.wins")
|
||||
fmt.Fprintf(f, "wins\n")
|
||||
ep := &ElectionProof{VRFProof: nil}
|
||||
for i := uint64(0); i < 1000000; i++ {
|
||||
i := i + 1000000
|
||||
ep.VRFProof = []byte{byte(i), byte(i >> 8), byte(i >> 16), byte(i >> 24), byte(i >> 32)}
|
||||
j := ep.ComputeWinCount(power, totalPower)
|
||||
fmt.Fprintf(f, "%d\n", j)
|
||||
}
|
||||
}
|
@ -21,13 +21,16 @@ type ExecutionTrace struct {
|
||||
type GasTrace struct {
|
||||
Name string
|
||||
|
||||
Location []Loc
|
||||
TotalGas int64
|
||||
ComputeGas int64
|
||||
StorageGas int64
|
||||
Location []Loc `json:"loc"`
|
||||
TotalGas int64 `json:"tg"`
|
||||
ComputeGas int64 `json:"cg"`
|
||||
StorageGas int64 `json:"sg"`
|
||||
TotalVirtualGas int64 `json:"vtg"`
|
||||
VirtualComputeGas int64 `json:"vcg"`
|
||||
VirtualStorageGas int64 `json:"vsg"`
|
||||
|
||||
TimeTaken time.Duration
|
||||
Extra interface{}
|
||||
TimeTaken time.Duration `json:"tt"`
|
||||
Extra interface{} `json:"ex,omitempty"`
|
||||
|
||||
Callers []uintptr `json:"-"`
|
||||
}
|
||||
|
@ -11,11 +11,11 @@ import (
|
||||
type FIL BigInt
|
||||
|
||||
func (f FIL) String() string {
|
||||
r := new(big.Rat).SetFrac(f.Int, big.NewInt(build.FilecoinPrecision))
|
||||
r := new(big.Rat).SetFrac(f.Int, big.NewInt(int64(build.FilecoinPrecision)))
|
||||
if r.Sign() == 0 {
|
||||
return "0"
|
||||
return "0 FIL"
|
||||
}
|
||||
return strings.TrimRight(strings.TrimRight(r.FloatString(18), "0"), ".")
|
||||
return strings.TrimRight(strings.TrimRight(r.FloatString(18), "0"), ".") + " FIL"
|
||||
}
|
||||
|
||||
func (f FIL) Format(s fmt.State, ch rune) {
|
||||
@ -28,14 +28,35 @@ func (f FIL) Format(s fmt.State, ch rune) {
|
||||
}
|
||||
|
||||
func ParseFIL(s string) (FIL, error) {
|
||||
suffix := strings.TrimLeft(s, ".1234567890")
|
||||
s = s[:len(s)-len(suffix)]
|
||||
var attofil bool
|
||||
if suffix != "" {
|
||||
norm := strings.ToLower(strings.TrimSpace(suffix))
|
||||
switch norm {
|
||||
case "", "fil":
|
||||
case "attofil", "afil":
|
||||
attofil = true
|
||||
default:
|
||||
return FIL{}, fmt.Errorf("unrecognized suffix: %q", suffix)
|
||||
}
|
||||
}
|
||||
|
||||
r, ok := new(big.Rat).SetString(s)
|
||||
if !ok {
|
||||
return FIL{}, fmt.Errorf("failed to parse %q as a decimal number", s)
|
||||
}
|
||||
|
||||
r = r.Mul(r, big.NewRat(build.FilecoinPrecision, 1))
|
||||
if !attofil {
|
||||
r = r.Mul(r, big.NewRat(int64(build.FilecoinPrecision), 1))
|
||||
}
|
||||
|
||||
if !r.IsInt() {
|
||||
return FIL{}, fmt.Errorf("invalid FIL value: %q", s)
|
||||
var pref string
|
||||
if attofil {
|
||||
pref = "atto"
|
||||
}
|
||||
return FIL{}, fmt.Errorf("invalid %sFIL value: %q", pref, s)
|
||||
}
|
||||
|
||||
return FIL{r.Num()}, nil
|
||||
|
@ -21,6 +21,7 @@ type ChainMsg interface {
|
||||
Cid() cid.Cid
|
||||
VMMessage() *Message
|
||||
ToStorageBlock() (block.Block, error)
|
||||
// FIXME: This is the *message* length, this name is misleading.
|
||||
ChainLength() int
|
||||
}
|
||||
|
||||
@ -157,3 +158,5 @@ func (m *Message) ValidForBlockInclusion(minGas int64) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const TestGasLimit = 100e6
|
||||
|
257
chain/types/testdata/TestExpFunction.golden
vendored
Normal file
257
chain/types/testdata/TestExpFunction.golden
vendored
Normal file
@ -0,0 +1,257 @@
|
||||
x, y
|
||||
0,115792089237316195423570985008687907853269984665640564039457584007913129639936
|
||||
2270433122300317557324921274680155055946470287561579687048187921723786855685,113543770489016942962237377411819033281128847358465443152965692667674515268459
|
||||
4540866244600635114649842549360310111892940575123159374096375843447573711370,111339107030360092669625707586928312989271150877369072427721155459215537208890
|
||||
6811299366900952671974763824040465167839410862684739061144563765171360567055,109177251212712547631698034978205369781807498766451007885527881500477232021682
|
||||
9081732489201270229299685098720620223785881150246318748192751686895147422740,107057371846115774238270822835274977319670170085938012474442950429894883628816
|
||||
11352165611501587786624606373400775279732351437807898435240939608618934278425,104978653879710027736182386389791146063108246474333192437116903221506365793784
|
||||
13622598733801905343949527648080930335678821725369478122289127530342721134110,102940298088363735750708779071187005425195044826988440514290336074628648838684
|
||||
15893031856102222901274448922761085391625292012931057809337315452066507989795,100941520765387555093691898043462296359944447036680097792913901290457279892923
|
||||
18163464978402540458599370197441240447571762300492637496385503373790294845480,98981553421214956610998073555828635758296463224923810238433739306701915887016
|
||||
20433898100702858015924291472121395503518232588054217183433691295514081701165,97059642487933486831615191223039105587754475193940197594806835165639555904556
|
||||
22704331223003175573249212746801550559464702875615796870481879217237868556850,95175049029553104647921939291264669504212075519331704270982994731418832879574
|
||||
24974764345303493130574134021481705615411173163177376557530067138961655412535,93327048457900197046298852001610623840008858609979636336358094295509875743050
|
||||
27245197467603810687899055296161860671357643450738956244578255060685442268220,91514930254028040867379060937212497464993417057199803702713818093495592131219
|
||||
29515630589904128245223976570842015727304113738300535931626442982409229123905,89737997695036598537471612414728492361735134837457880776578397164411259714034
|
||||
31786063712204445802548897845522170783250584025862115618674630904133015979590,87995567586196615492499061341239298336716207707733388009305962491415997438251
|
||||
34056496834504763359873819120202325839197054313423695305722818825856802835275,86286969998275026412807199079440137158468693464163642116594809068619896392941
|
||||
36326929956805080917198740394882480895143524600985274992771006747580589690960,84611548009960677185535234025783667242734659094160158991843756961639811974930
|
||||
38597363079105398474523661669562635951089994888546854679819194669304376546645,82968657455291330479761642121918798999912566007436555574905312488221049770642
|
||||
40867796201405716031848582944242791007036465176108434366867382591028163402330,81357666675984845712317087407692885985045766475399018683682465654293317561467
|
||||
43138229323706033589173504218922946062982935463670014053915570512751950258015,79777956278579309738294730369672998880873563557913118175337099978291132200541
|
||||
45408662446006351146498425493603101118929405751231593740963758434475737113700,78228918896288743544848199105491032646200262796326433813989850094529077282776
|
||||
47679095568306668703823346768283256174875876038793173428011946356199523969385,76709958955482823270730386397827358293917115388940737122493792142598409249118
|
||||
49949528690606986261148268042963411230822346326354753115060134277923310825070,75220492446700831714270851931718222334181221472926734650894450187207587804959
|
||||
52219961812907303818473189317643566286768816613916332802108322199647097680755,73759946700111799812659669164881767734266809389910877226542646506513000978489
|
||||
54490394935207621375798110592323721342715286901477912489156510121370884536440,72327760165334507045772504425420867449416167380982855532448913178137554210923
|
||||
56760828057507938933123031867003876398661757189039492176204698043094671392125,70923382195532685995592428750934431740132395987623204573329785474158712116147
|
||||
59031261179808256490447953141684031454608227476601071863252885964818458247810,69546272835702420022053453330708655397369524375477499739230911030535808540657
|
||||
61301694302108574047772874416364186510554697764162651550301073886542245103495,68195902615070334829829990481057773300819373544625447529491837404705895284329
|
||||
63572127424408891605097795691044341566501168051724231237349261808266031959180,66871752343522765217935231891690355471651496064655471661919663456330328641288
|
||||
65842560546709209162422716965724496622447638339285810924397449729989818814865,65573312911987628132646843093927406319425698793733957333572673848799954239855
|
||||
68112993669009526719747638240404651678394108626847390611445637651713605670550,64300085096692252880128256597394188085029084300287019159255155536716536636582
|
||||
70383426791309844277072559515084806734340578914408970298493825573437392526235,63051579367221909582465988028351521656270181701866074076641181901174457665557
|
||||
72653859913610161834397480789764961790287049201970549985542013495161179381920,61827315698305238252660159775306665170268657207834096298284442133031571582783
|
||||
74924293035910479391722402064445116846233519489532129672590201416884966237605,60626823385254213782224025259478780989246898268785251219150451819890211607196
|
||||
77194726158210796949047323339125271902179989777093709359638389338608753093290,59449640862987687230396859494036983576366375788559345059199710577555290424321
|
||||
79465159280511114506372244613805426958126460064655289046686577260332539948975,58295315528568921616783939661658889268848452171972763039788768615558483626267
|
||||
81735592402811432063697165888485582014072930352216868733734765182056326804660,57163403567188891479248718554448273836403260979137552976694337187145017476501
|
||||
84006025525111749621022087163165737070019400639778448420782953103780113660345,56053469781528440285551018178364674618486430618035927413379628478874266581878
|
||||
86276458647412067178347008437845892125965870927340028107831141025503900516030,54965087424433688889920273781092319643978134551542030239286748341146003208614
|
||||
88546891769712384735671929712526047181912341214901607794879328947227687371715,53897838034840362103953324191045652555242797708181047223345801682385818568835
|
||||
90817324892012702292996850987206202237858811502463187481927516868951474227400,52851311276883949594712447365930530107052884187291818795931120263968492084774
|
||||
93087758014313019850321772261886357293805281790024767168975704790675261083085,51825104782133842211941756402475821837684219892038783449941692633646927028868
|
||||
95358191136613337407646693536566512349751752077586346856023892712399047938770,50818823994890785951863832476942579771969130641977742986737254850253840075592
|
||||
97628624258913654964971614811246667405698222365147926543072080634122834794455,49832082020488173548864433257316990617151231489408392527154422207621203727615
|
||||
99899057381213972522296536085926822461644692652709506230120268555846621650140,48864499476538848601355411822273410550321020146722594189563317351144555102308
|
||||
102169490503514290079621457360606977517591162940271085917168456477570408505825,47915704347070229628266128780655102907390977725210624641985610920484495320871
|
||||
104439923625814607636946378635287132573537633227832665604216644399294195361510,46985331839491671953371264029121450743887309752499067780940162596021543960818
|
||||
106710356748114925194271299909967287629484103515394245291264832321017982217195,46073024244339074252983177578294403714924665379395655719184742489399140111119
|
||||
108980789870415242751596221184647442685430573802955824978313020242741769072880,45178430797742804397094652011443390009353450908460410593202993111115176300509
|
||||
111251222992715560308921142459327597741377044090517404665361208164465555928565,44301207546566066275398443059622984529245531090835413454138285364317904357889
|
||||
113521656115015877866246063734007752797323514378078984352409396086189342784250,43441017216161856030307536334277824451020867870703344545581645152489753618625
|
||||
115792089237316195423570985008687907853269984665640564039457584007913129639935,42597529080697662913911602080197270017224605406643086589378214572018159359656
|
||||
118062522359616512980895906283368062909216454953202143726505771929636916495620,41770418835998057231823154500906296232954940017107200954896529163626836852806
|
||||
120332955481916830538220827558048217965162925240763723413553959851360703351305,40959368474856275913667539524102962047053738936489506227266772182693729839202
|
||||
122603388604217148095545748832728373021109395528325303100602147773084490206990,40164066164766865529760099118055626254866338159841829407810028308443332329921
|
||||
124873821726517465652870670107408528077055865815886882787650335694808277062675,39384206128032373421270623986368325593061645265273820139765067969067422649415
|
||||
127144254848817783210195591382088683133002336103448462474698523616532063918360,38619488524197990384791697485732970600503064875453399931120765038045198401265
|
||||
129414687971118100767520512656768838188948806391010042161746711538255850774045,37869619334768943402646797366590078932213917335501796767692394741802326454228
|
||||
131685121093418418324845433931448993244895276678571621848794899459979637629730,37134310250166314581624891999905972285593140562157169782497980837053288139911
|
||||
133955554215718735882170355206129148300841746966133201535843087381703424485415,36413278558877823092557676422579316779501436559193491643756131394023796062011
|
||||
136225987338019053439495276480809303356788217253694781222891275303427211341100,35706247038760950822158313374858241516488865748339595127547394046982094249410
|
||||
138496420460319370996820197755489458412734687541256360909939463225150998196785,35012943850456619981286410714734531636271581473914516202135729910546566402779
|
||||
140766853582619688554145119030169613468681157828817940596987651146874785052470,34333102432872442378462629116615524982524168457316936505909372845805604900401
|
||||
143037286704920006111470040304849768524627628116379520284035839068598571908155,33666461400695355776019567288676251030810566791286359575983902200864972469996
|
||||
145307719827220323668794961579529923580574098403941099971084026990322358763840,33012764443894243004677309675463059806544657868579375264515822376830510918451
|
||||
147578152949520641226119882854210078636520568691502679658132214912046145619525,32371760229173894620565861867718452819385944209047587245952825283707541232161
|
||||
149848586071820958783444804128890233692467038979064259345180402833769932475210,31743202303342426140951325851524709564919796135818066107980273521807047228205
|
||||
152119019194121276340769725403570388748413509266625839032228590755493719330895,31126848998554996579614932864397941484844825641744252641191173459915093805187
|
||||
154389452316421593898094646678250543804359979554187418719276778677217506186580,30522463339397396402839881838375473280428264227964104623768547140174704396628
|
||||
156659885438721911455419567952930698860306449841748998406324966598941293042265,29929812951773780419644078230146692062203486832083285970050129935848796157421
|
||||
158930318561022229012744489227610853916252920129310578093373154520665079897950,29348669973563514777235550444240282773251884769510008252819331832439494645079
|
||||
161200751683322546570069410502291008972199390416872157780421342442388866753635,28778810967012787421358795112757003059950944596369120909715112149169964220370
|
||||
163471184805622864127394331776971164028145860704433737467469530364112653609320,28220016832827298362763401072714572174637391915333615996330037256359689152007
|
||||
165741617927923181684719253051651319084092330991995317154517718285836440465005,27672072725933000121901983367925347694111025283271589335038719296229849510185
|
||||
168012051050223499242044174326331474140038801279556896841565906207560227320690,27134767972872500055614403280459447260039099989714465645168626995212978266528
|
||||
170282484172523816799369095601011629195985271567118476528614094129284014176375,26607895990805365148558542391218752327077936735384764869356894955189244136002
|
||||
172552917294824134356694016875691784251931741854680056215662282051007801032060,26091254208081186520295830628576992670321075391182679321065607327265313932322
|
||||
174823350417124451914018938150371939307878212142241635902710469972731587887745,25584643986354865593328765236833491064966760582438881050282097633879965205565
|
||||
177093783539424769471343859425052094363824682429803215589758657894455374743430,25087870544214176820510595839294024971107825899184642127021233999936247081507
|
||||
179364216661725087028668780699732249419771152717364795276806845816179161599115,24600742882290243310082706540466488496131563143845631581983311961047083061256
|
||||
181634649784025404585993701974412404475717623004926374963855033737902948454800,24123073709822131836694888705209306323992339748006300420231840208502026712055
|
||||
183905082906325722143318623249092559531664093292487954650903221659626735310485,23654679372647332806338881400061315566868133427664662629105489367609937695646
|
||||
186175516028626039700643544523772714587610563580049534337951409581350522166170,23195379782590438967131080837393236404679360225477050241221440433306491390529
|
||||
188445949150926357257968465798452869643557033867611114024999597503074309021855,22744998348222874237097258296963376819397584603868543116623643157984253142510
|
||||
190716382273226674815293387073133024699503504155172693712047785424798095877540,22303361906967051161228844170125488556352938430940411562982254002868044311034
|
||||
192986815395526992372618308347813179755449974442734273399095973346521882733225,21870300658518852415771961233241780589753603014109439052609181643134330131200
|
||||
195257248517827309929943229622493334811396444730295853086144161268245669588910,21445648099562838646716735757033316057251336889853858375428467187815522927837
|
||||
197527681640127627487268150897173489867342915017857432773192349189969456444595,21029240959755081956656390289742251499446416407847034496990361844628688581109
|
||||
199798114762427945044593072171853644923289385305419012460240537111693243300280,20620919138949011730680161329173099008306763464882403634448661640684501661866
|
||||
202068547884728262601917993446533799979235855592980592147288725033417030155965,20220525645640137405137620676980023532901299004381393279093890751532452054423
|
||||
204338981007028580159242914721213955035182325880542171834336912955140817011650,19827906536605981416712487046651644994469849037549721389552871270682788176368
|
||||
206609414129328897716567835995894110091128796168103751521385100876864603867335,19442910857718015103451661807495877546362994006807802531582187045985408388323
|
||||
208879847251629215273892757270574265147075266455665331208433288798588390723020,19065390585902840940891643898043637774181614198870274451246241331546097600612
|
||||
211150280373929532831217678545254420203021736743226910895481476720312177578705,18695200572230306358460705740514292808692490977651168538902708783481421680348
|
||||
213420713496229850388542599819934575258968207030788490582529664642035964434390,18332198486106667663798285266862799262530724876828607112610697476363307765699
|
||||
215691146618530167945867521094614730314914677318350070269577852563759751290075,17976244760551347472111336927386090359808454572176186089250363261529225698797
|
||||
217961579740830485503192442369294885370861147605911649956626040485483538145760,17627202538536245657534631830721579840416279034844169182844082749512022955880
|
||||
220232012863130803060517363643975040426807617893473229643674228407207325001445,17284937620366972373860132250248373607831381821348510576523341628979456457899
|
||||
222502445985431120617842284918655195482754088181034809330722416328931111857130,16949318412085772290021286893087219332537721900597190962614965688689436470898
|
||||
224772879107731438175167206193335350538700558468596389017770604250654898712815,16620215874876302005383259706474512944760516297587146250989332554945114509504
|
||||
227043312230031755732492127468015505594647028756157968704818792172378685568500,16297503475450807802230954908656139014943597886328184429574709348911081384486
|
||||
229313745352332073289817048742695660650593499043719548391866980094102472424185,15981057137400628605961920332938849374838761847812884031059653371884698227732
|
||||
231584178474632390847141970017375815706539969331281128078915168015826259279870,15670755193491319402603874616100339746216923922257041729716527735529769853650
|
||||
233854611596932708404466891292055970762486439618842707765963355937550046135555,15366478338884053550790009737665512422829259009202431332168817628656130747976
|
||||
236125044719233025961791812566736125818432909906404287453011543859273832991240,15068109585265318560877642552077774766432262308314225827173090425609387180236
|
||||
238395477841533343519116733841416280874379380193965867140059731780997619846925,14775534215867269134414164114591717654313758765518045957328319974951247947864
|
||||
240665910963833661076441655116096435930325850481527446827107919702721406702610,14488639741361443696906809527925407527798326175077538816130520515576676432536
|
||||
242936344086133978633766576390776590986272320769089026514156107624445193558295,14207315856608886447500721787929418266891341269962575206208292606790558927738
|
||||
245206777208434296191091497665456746042218791056650606201204295546168980413980,13931454398250046219817842121237250069017319717552215812396900410729316780042
|
||||
247477210330734613748416418940136901098165261344212185888252483467892767269665,13660949303118146325455249570700165024364040604752663984462703166489664742339
|
||||
249747643453034931305741340214817056154111731631773765575300671389616554125350,13395696567460036159625482974163434950873419335747629798807509358843043114747
|
||||
252018076575335248863066261489497211210058201919335345262348859311340340981035,13135594206948845808872493016734991140070074672980170698797842470835657746355
|
||||
254288509697635566420391182764177366266004672206896924949397047233064127836720,12880542217473069333080972366140272174677497922483630681691757178031836728636
|
||||
256558942819935883977716104038857521321951142494458504636445235154787914692405,12630442536687000915161971042648362535726831652623366360951945091372138829073
|
||||
258829375942236201535041025313537676377897612782020084323493423076511701548090,12385199006307740796619289137869014505391917569864233277491827537392271272526
|
||||
261099809064536519092365946588217831433844083069581664010541610998235488403775,12144717335144274958225939593470301902208893969091913127900701796820969916276
|
||||
263370242186836836649690867862897986489790553357143243697589798919959275259460,11908905062844413972629474569782724684547574705479145661987238841262047512889
|
||||
265640675309137154207015789137578141545737023644704823384637986841683062115145,11677671524345652458077781103683012746985203951843087585351200546458450234583
|
||||
267911108431437471764340710412258296601683493932266403071686174763406848970830,11450927815016281205730420816822769656276856651451425159655410140798486590368
|
||||
270181541553737789321665631686938451657629964219827982758734362685130635826515,11228586756473349441251594323339849390046255944661352162796836657552528120100
|
||||
272451974676038106878990552961618606713576434507389562445782550606854422682200,11010562863064334916605775798811477728189133603960442457397758272811779333449
|
||||
274722407798338424436315474236298761769522904794951142132830738528578209537885,10796772308999634710251182117797466377054234368136632046647040836884880709149
|
||||
276992840920638741993640395510978916825469375082512721819878926450301996393570,10587132896123239841361951569073852197393979276538146129343090522801499481360
|
||||
279263274042939059550965316785659071881415845370074301506927114372025783249255,10381564022309202172514611506897394878877748812065679452742065418299049556809
|
||||
281533707165239377108290238060339226937362315657635881193975302293749570104940,10179986650471742679787468858482358928499942961441493648347660820939932354037
|
||||
283804140287539694665615159335019381993308785945197460881023490215473356960625,9982323278177086101950544601003257424140532557067992549916807460469069141662
|
||||
286074573409840012222940080609699537049255256232759040568071678137197143816310,9788497907845338332079968817743865213174453409259845129758908478094549262272
|
||||
288345006532140329780265001884379692105201726520320620255119866058920930671995,9598436017530949774464402361919053565881937627109257874972510208401009770963
|
||||
290615439654440647337589923159059847161148196807882199942168053980644717527680,9412064532270530344304969563638312480198627803597895883581869229790285361030
|
||||
292885872776740964894914844433740002217094667095443779629216241902368504383365,9229311795986999922973693773512111376663242782368889508055395732551288322377
|
||||
295156305899041282452239765708420157273041137383005359316264429824092291239050,9050107543939271981357133004643947981886610395815063538792001543567721697353
|
||||
297426739021341600009564686983100312328987607670566939003312617745816078094735,8874382875706877830311960657026508969290082662731915199950324279800475201683
|
||||
299697172143641917566889608257780467384934077958128518690360805667539864950420,8702070228699144631140925089885492819072907992531772224458410703022324971560
|
||||
301967605265942235124214529532460622440880548245690098377408993589263651806105,8533103352178741979338410836757093105256375792397040329065630149508413086135
|
||||
304238038388242552681539450807140777496827018533251678064457181510987438661790,8367417281789609639196736794874998402544481231388500060346139012236641543825
|
||||
306508471510542870238864372081820932552773488820813257751505369432711225517475,8204948314579472931243763439936896182045474760835882712220942160049717189792
|
||||
308778904632843187796189293356501087608719959108374837438553557354435012373160,8045633984507342433459354572450622071501444572221358150888492135726910593613
|
||||
311049337755143505353514214631181242664666429395936417125601745276158799228845,7889413038426581123905040544325858121069927256074308557819634343914244175953
|
||||
313319770877443822910839135905861397720612899683497996812649933197882586084530,7736225412534304938490539495998345262722685569683811485718517851478118074806
|
||||
315590203999744140468164057180541552776559369971059576499698121119606372940215,7586012209278062013393244296606783131019725342345569324815264018948034488407
|
||||
317860637122044458025488978455221707832505840258621156186746309041330159795900,7438715674710911696077991529315597910182131547815478256768516102178053147428
|
||||
320131070244344775582813899729901862888452310546182735873794496963053946651585,7294279176286196809531497726711149751773109079006438039328871808860505208647
|
||||
322401503366645093140138821004582017944398780833744315560842684884777733507270,7152647181083471707513356405012353952405611456310792512957976292047901188617
|
||||
324671936488945410697463742279262173000345251121305895247890872806501520362955,7013765234457214429330978163948031181884804665874684563234080173204818792192
|
||||
326942369611245728254788663553942328056291721408867474934939060728225307218640,6877579939100113814604817973991912882261222190269087624747098477473070920910
|
||||
329212802733546045812113584828622483112238191696429054621987248649949094074325,6744038934512881834200618407209402738374726406854013386327229734819886355209
|
||||
331483235855846363369438506103302638168184661983990634309035436571672880930010,6613090876872697694251640706911864470257281520044099539344107417605448847522
|
||||
333753668978146680926763427377982793224131132271552213996083624493396667785695,6484685419292543536070441670407899002441885350144223913319492393155843996609
|
||||
336024102100446998484088348652662948280077602559113793683131812415120454641380,6358773192463841844684321602472961808036370534710746466420213566001948927453
|
||||
338294535222747316041413269927343103336024072846675373370180000336844241497065,6235305785674952050504565665502249112334426989789636398933745643420892537805
|
||||
340564968345047633598738191202023258391970543134236953057228188258568028352750,6114235728198228318918503273647009044057809740115762935228605445446011541536
|
||||
342835401467347951156063112476703413447917013421798532744276376180291815208435,5995516471038482226936505302234614253048545365172641788639745380038847011850
|
||||
345105834589648268713388033751383568503863483709360112431324564102015602064120,5879102369035832978915788636227029754149990028304128445154065521569679896299
|
||||
347376267711948586270712955026063723559809953996921692118372752023739388919805,5764948663316064068243885471976803898564123312018636117461200936317441104963
|
||||
349646700834248903828037876300743878615756424284483271805420939945463175775490,5653011464081738901084106683312765416762298565331902697873676865978153014007
|
||||
351917133956549221385362797575424033671702894572044851492469127867186962631175,5543247733737458913233334532284737157076797625887278020789776292123991283042
|
||||
354187567078849538942687718850104188727649364859606431179517315788910749486860,5435615270342776182191625059155814516167449877265043810529451526313401440000
|
||||
356458000201149856500012640124784343783595835147168010866565503710634536342545,5330072691386398513087911834712869898427723411257226595273064182550426763859
|
||||
358728433323450174057337561399464498839542305434729590553613691632358323198230,5226579417875448507582021006206716342354483979921442218144570774799799153756
|
||||
360998866445750491614662482674144653895488775722291170240661879554082110053915,5125095658733659256765209168041122238133229257032719961413509211200048248333
|
||||
363269299568050809171987403948824808951435246009852749927710067475805896909600,5025582395502508078982293698284693835284469532255851267477746214208169030829
|
||||
365539732690351126729312325223504964007381716297414329614758255397529683765285,4928001367339406197066635979466804208185522234029567523625554767402211661565
|
||||
367810165812651444286637246498185119063328186584975909301806443319253470620970,4832315056307176461496499130904489365080602372384889128573871476885084197963
|
||||
370080598934951761843962167772865274119274656872537488988854631240977257476655,4738486672949163220359850565587517062963871431792713253071282139856533845449
|
||||
372351032057252079401287089047545429175221127160099068675902819162701044332340,4646480142144428256814095536419820031461458638508982355406532908762559366752
|
||||
374621465179552396958612010322225584231167597447660648362951007084424831188025,4556260089237594402171008726677813775125098076724227743627974892272588327070
|
||||
376891898301852714515936931596905739287114067735222228049999195006148618043710,4467791826438004029228927006814200361630588836617618519025510750743109199997
|
||||
379162331424153032073261852871585894343060538022783807737047382927872404899395,4381041339482963176613798998129770586400722046177381492207741626501677387270
|
||||
381432764546453349630586774146266049399007008310345387424095570849596191755080,4295975274559943590489358236239541053798654812625189402565013609912762502063
|
||||
383703197668753667187911695420946204454953478597906967111143758771319978610765,4212560925482714534092886286689429135772883215331118745250144375204860994258
|
||||
385973630791053984745236616695626359510899948885468546798191946693043765466450,4130766221116473846427146968171682243610648632762217464220432443306744076356
|
||||
388244063913354302302561537970306514566846419173030126485240134614767552322135,4050559713047143466628204822445172093558799258185730849489440714923595198306
|
||||
390514497035654619859886459244986669622792889460591706172288322536491339177820,3971910563490088516841239430057423861561699540314803552309386818215754652836
|
||||
392784930157954937417211380519666824678739359748153285859336510458215126033505,3894788533433611089965680791375046317061917745510095607652825551910399528715
|
||||
395055363280255254974536301794346979734685830035714865546384698379938912889190,3819163971012660154769745087149569914465567827492977553371176365210754983049
|
||||
397325796402555572531861223069027134790632300323276445233432886301662699744875,3745007800108287504328254434609249402710340257581916107575424870725436120735
|
||||
399596229524855890089186144343707289846578770610838024920481074223386486600560,3672291509168466468538116483953888412415082359790291319830667248103068617726
|
||||
401866662647156207646511065618387444902525240898399604607529262145110273456245,3600987140245975220983870041875004895679551495743211205866825798183240723922
|
||||
404137095769456525203835986893067599958471711185961184294577450066834060311930,3531067278249129967384164433549615728055232151532910541204821495878913836970
|
||||
406407528891756842761160908167747755014418181473522763981625637988557847167615,3462505040401235139336450269559039606157745830970264242579700439549733102016
|
||||
408677962014057160318485829442427910070364651761084343668673825910281634023300,3395274065904697964555996096535291493010779102468849709076001181212499029926
|
||||
410948395136357477875810750717108065126311122048645923355722013832005420878985,3329348505805833474130146144622500207015802447060544079287034222519730000801
|
||||
413218828258657795433135671991788220182257592336207503042770201753729207734670,3264703013056463168733957305768762048671220120100675556528510459350361442934
|
||||
415489261380958112990460593266468375238204062623769082729818389675452994590355,3201312732768486228946010278262122858837369338972372870253840600423809756146
|
||||
417759694503258430547785514541148530294150532911330662416866577597176781446040,3139153292657676348854251985374092135837494969951169782173776159644176534423
|
||||
420030127625558748105110435815828685350097003198892242103914765518900568301725,3078200793673030025577310098607138197203259951148621910059374341071023253667
|
||||
422300560747859065662435357090508840406043473486453821790962953440624355157410,3018431800808063478119054352864365216599069977484266467250325895140520117178
|
||||
424570993870159383219760278365188995461989943774015401478011141362348142013095,2959823334090525324552359078463176696893036195521598690559604864862321028159
|
||||
426841426992459700777085199639869150517936414061576981165059329284071928868780,2902352859747060743788555836574429934024784962979281619588506007014730754443
|
||||
429111860114760018334410120914549305573882884349138560852107517205795715724465,2845998281539430113506217335511024116647561786738955796723957128032460028562
|
||||
431382293237060335891735042189229460629829354636700140539155705127519502580150,2790737932268951075048841664512779579965827455433050874470612581492493796612
|
||||
433652726359360653449059963463909615685775824924261720226203893049243289435835,2736550565445897654615705160581380392035754504074875922703396122219838983601
|
||||
435923159481660971006384884738589770741722295211823299913252080970967076291520,2683415347120653492731207292836793547250299699949146040965909097366506826314
|
||||
438193592603961288563709806013269925797668765499384879600300268892690863147205,2631311847873478425170175781779819578108906286445566029098739049466961949804
|
||||
440464025726261606121034727287950080853615235786946459287348456814414650002890,2580220034959808642151093783793953402129918191024990104539947286476194870361
|
||||
442734458848561923678359648562630235909561706074508038974396644736138436858575,2530120264608070452133030819123365918858694576649021314235932359705643943273
|
||||
445004891970862241235684569837310390965508176362069618661444832657862223714260,2480993274467046314956915988152178555256121842686531405628524104350927660746
|
||||
447275325093162558793009491111990546021454646649631198348493020579586010569945,2432820176199889308902969867700028980919093407680036321083074765251991144298
|
||||
449545758215462876350334412386670701077401116937192778035541208501309797425630,2385582448221938579601135652712703469128873722647430092259396421200608174744
|
||||
451816191337763193907659333661350856133347587224754357722589396423033584281315,2339261928579543607308487238103279986560541266662742536344201858542715699027
|
||||
454086624460063511464984254936031011189294057512315937409637584344757371137000,2293840807967159344114184788286120867801944082584440628149280631165005320951
|
||||
456357057582363829022309176210711166245240527799877517096685772266481157992685,2249301622880027434993188844156208157845130306302793141117411709623435670173
|
||||
458627490704664146579634097485391321301186998087439096783733960188204944848370,2205627248899810866744487578412286757829514684708503434368069205255340039839
|
||||
460897923826964464136959018760071476357133468375000676470782148109928731704055,2162800894110600506761016035372877280458113909309651595222790899580498073682
|
||||
463168356949264781694283940034751631413079938662562256157830336031652518559740,2120806092642762118940557002260420725877403403643132375546681834433562628493
|
||||
465438790071565099251608861309431786469026408950123835844878523953376305415425,2079626698342141596131901285086838588831365589656553686857278748333033108659
|
||||
467709223193865416808933782584111941524972879237685415531926711875100092271110,2039246878562194346216395910444043784690021169116503952080024996424232086889
|
||||
469979656316165734366258703858792096580919349525246995218974899796823879126795,1999651108076652030782767922491430088269301331012688651267426380085596201366
|
||||
472250089438466051923583625133472251636865819812808574906023087718547665982480,1960824163110386199534010054524334089541753293394021687030939529972846447262
|
||||
474520522560766369480908546408152406692812290100370154593071275640271452838165,1922751115486173807887555445320207063113604718628558999245364537712059659787
|
||||
476790955683066687038233467682832561748758760387931734280119463561995239693850,1885417326885114167166377133451693487795698974827428621915772121522296322640
|
||||
479061388805367004595558388957512716804705230675493313967167651483719026549535,1848808443218490573462190057395600374688639714455162176619470154537224426642
|
||||
481331821927667322152883310232192871860651700963054893654215839405442813405220,1812910389108912709483102199711379114048329569523931425832014763952606023142
|
||||
483602255049967639710208231506873026916598171250616473341264027327166600260905,1777709362478617929951137999560857523114698493464640463314567998578763375930
|
||||
485872688172267957267533152781553181972544641538178053028312215248890387116590,1743191829242850741544443083382012278950030439838258806090307410195511152367
|
||||
488143121294568274824858074056233337028491111825739632715360403170614173972275,1709344518106280188825408838548340945706907890570414138312511052040629403114
|
||||
490413554416868592382182995330913492084437582113301212402408591092337960827960,1676154415460454473592585178001481888630499860343530369736761941087841137938
|
||||
492683987539168909939507916605593647140384052400862792089456779014061747683645,1643608760380330981872631688029464454202113613160652114812004614315882448607
|
||||
494954420661469227496832837880273802196330522688424371776504966935785534539330,1611695039717957985264493988118541627646396847164138227584506579980006189593
|
||||
497224853783769545054157759154953957252276992975985951463553154857509321395015,1580400983291421636207279946257561145576531467125488184028701658324803392105
|
||||
499495286906069862611482680429634112308223463263547531150601342779233108250700,1549714559167208504327370397252359435900676480118217197526808984667322295656
|
||||
501765720028370180168807601704314267364169933551109110837649530700956895106385,1519623969034169817411698521182954716530148741935550434876916238707975489825
|
||||
504036153150670497726132522978994422420116403838670690524697718622680681962070,1490117643667308789561999136522296289524839311469606144758176235295035574077
|
||||
506306586272970815283457444253674577476062874126232270211745906544404468817755,1461184238479646954250162028027864509672389242493414237027164373310873876617
|
||||
508577019395271132840782365528354732532009344413793849898794094466128255673440,1432812629160459284595696582392048709701342884089101780789506016757983545698
|
||||
510847452517571450398107286803034887587955814701355429585842282387852042529125,1404991907398201090242984454401886460001256486743771644647644675643019397120
|
||||
513117885639871767955432208077715042643902284988917009272890470309575829384810,1377711376686482242495906258989351428318340736703325118283502743772525420186
|
||||
515388318762172085512757129352395197699848755276478588959938658231299616240495,1350960548211476209390117246928289328516166528957389393408566548846213309144
|
||||
517658751884472403070082050627075352755795225564040168646986846153023403096180,1324729136819182692425165292411394327407511934209655077877674460464300121300
|
||||
519929185006772720627406971901755507811741695851601748334035034074747189951865,1299007057060993358777871916475898081725576133192311731321945268374304875079
|
||||
522199618129073038184731893176435662867688166139163328021083221996470976807550,1273784419316040268779271406014391437821438711132700913654395176336120357812
|
||||
524470051251373355742056814451115817923634636426724907708131409918194763663235,1249051525988836119835059106151604655038913776255529646900786453845629450261
|
||||
526740484373673673299381735725795972979581106714286487395179597839918550518920,1224798867780744376154319639656429438292590596449478554800662259883398133550
|
||||
529010917495973990856706657000476128035527577001848067082227785761642337374605,1201017120033845739753282342628997286268151802300216872136210819143441303664
|
||||
531281350618274308414031578275156283091474047289409646769275973683366124230290,1177697139145795253133868286972489045105718361046528878527448066379668652133
|
||||
533551783740574625971356499549836438147420517576971226456324161605089911085975,1154829959054291618502821225483149900650534431243083949245642604820923646588
|
||||
535822216862874943528681420824516593203366987864532806143372349526813697941660,1132406787789807082890425327211328755183700827007270235992079331829362643852
|
||||
538092649985175261086006342099196748259313458152094385830420537448537484797345,1110419004095252483338613492946986193747814242216914544087253927761374702549
|
||||
540363083107475578643331263373876903315259928439655965517468725370261271653030,1088858154111277781547261772857694251337802353360681665028106984738120501199
|
||||
542633516229775896200656184648557058371206398727217545204516913291985058508715,1067715948125933652889320598100629627595490376276215626206049496855639908739
|
||||
544903949352076213757981105923237213427152869014779124891565101213708845364400,1046984257387444440232701363407888596891997329416358164537461237895052190493
|
||||
547174382474376531315306027197917368483099339302340704578613289135432632220085,1026655110978867048053673500561104502292891906760695382551282292885769647385
|
||||
549444815596676848872630948472597523539045809589902284265661477057156419075770,1006720692753434146222353671415953866113533147281398201361542821926894368710
|
||||
551715248718977166429955869747277678594992279877463863952709664978880205931455,987173338329403384733958131783829533009147622988398599380784122106977308530
|
||||
553985681841277483987280791021957833650938750165025443639757852900603992787140,968005532143257199520483988560220733582298517120243540446994347402239110174
|
||||
556256114963577801544605712296637988706885220452587023326806040822327779642825,949209904560120224102845604039392059367322323910424009332173176480678795959
|
||||
558526548085878119101930633571318143762831690740148603013854228744051566498510,930779229040283320858879764591061717606873826779909083197312274038703255036
|
||||
560796981208178436659255554845998298818778161027710182700902416665775353354195,912706419360744817546225148870963828076628869100719699856881194145713586169
|
||||
563067414330478754216580476120678453874724631315271762387950604587499140209880,894984526890700687724824577161411173596658532863246109848772040565011872478
|
||||
565337847452779071773905397395358608930671101602833342074998792509222927065565,877606737919936156004596577686776039865420267809390448859339117903023609116
|
||||
567608280575079389331230318670038763986617571890394921762046980430946713921250,860566371039091548574664590528726362251021703804112434559419129682978794632
|
||||
569878713697379706888555239944718919042564042177956501449095168352670500776935,843856874570795154071557033366442926236979708804975971538286570121216914411
|
||||
572149146819680024445880161219399074098510512465518081136143356274394287632620,827471824050675417183296315424741971779066957250062452852260880325027656529
|
||||
574419579941980342003205082494079229154456982753079660823191544196118074488305,811404919757283964983682303379036253598800697102332643556476037720459831748
|
||||
576690013064280659560530003768759384210403453040641240510239732117841861343990,795649984289979771219745127738174910086802387263030261900019674061458963150
|
||||
578960446186580977117854925043439539266349923328202820197287920039565648199675,780200960193843203865524721501305631184795994974723658032277935470179306730
|
1
chain/types/testdata/TestLambdaFunction/10-100.golden
vendored
Normal file
1
chain/types/testdata/TestLambdaFunction/10-100.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
57896044618658097711785492504343953926634992332820282019728792003956564819968
|
1
chain/types/testdata/TestLambdaFunction/1024-2048.golden
vendored
Normal file
1
chain/types/testdata/TestLambdaFunction/1024-2048.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
289480223093290488558927462521719769633174961664101410098643960019782824099840
|
1
chain/types/testdata/TestLambdaFunction/2000000000000000-100000000000000000.golden
vendored
Normal file
1
chain/types/testdata/TestLambdaFunction/2000000000000000-100000000000000000.golden
vendored
Normal file
@ -0,0 +1 @@
|
||||
11579208923731619542357098500868790785326998466564056403945758400791312963993
|
17
chain/types/testdata/TestPoissonFunction/lam-10-10.golden
vendored
Normal file
17
chain/types/testdata/TestPoissonFunction/lam-10-10.golden
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
icdf
|
||||
1125278653883954157340515998824199281259686237023612910954531537010133365568
|
||||
5485581780123676224984074899749002236148166431650497590243915223971292577
|
||||
17842170241691453912141677461647358103546946338181118738604570718548080
|
||||
43538699106868068808561503680708109912117284430088557923220935824303
|
||||
85008817354919776986513548953593326094752560579206896166859206326
|
||||
138328508214407784218646352510285887677303021571444942144212932
|
||||
192946940473264032619492808002293590266469557064324916486706
|
||||
235498963868775663540157747991701194152938740691242898919
|
||||
255504995002156513848360474242833468958493714151012216
|
||||
249505772801580009049072856702435230216536441494110
|
||||
232834101038081471620316286291642591265760137159
|
||||
11533551765583311484083562200606025547302501012
|
||||
11353456917542541496993529059255898133794641608
|
||||
11353321629946357024346977051186975261639061786
|
||||
11353321535577219060847642123725989684858819334
|
||||
11353321535515780819985988910882590605707269697
|
17
chain/types/testdata/TestPoissonFunction/lam-1036915-20.golden
vendored
Normal file
17
chain/types/testdata/TestPoissonFunction/lam-1036915-20.golden
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
icdf
|
||||
72718197862321603787957847055188249408647877796280116987586082825356498974798
|
||||
30123322455004902866096392147720313525979066051167804713805891738863284666878
|
||||
9062729215708086547397523150443475826195010851218953471088727298493148732956
|
||||
2120601657722952965249404258310617497861606438105371150448777320082300909521
|
||||
404370264674629622846679825118378024155401061236248117877372450081489268106
|
||||
64941157977031699837280219244596630364570458903895153606060064374226923144
|
||||
8998760514291795062091202215054973561658841304177095664084807386711484044
|
||||
1095864305518189121413406860322570887693509822868614985675874891701983877
|
||||
118988091690998292615838041961723734187855286032350465668217096980526413
|
||||
11653361409102593830837021393444274321721937984503223867724441309766994
|
||||
1039253147016500070761515827557061937775360855994320103804816785188376
|
||||
85064880905559492020902336338153555957806293407638915883403930221828
|
||||
6433469833589351070633969345898155559842007456615136652210720692299
|
||||
452164666340411064711833496915674079929092772106312520794348036629
|
||||
29679788379529243880483477334855509673275091060271619731000625321
|
||||
1827354397264548824373139406487609602015834650190678153972930556
|
17
chain/types/testdata/TestPoissonFunction/lam-1706-10.golden
vendored
Normal file
17
chain/types/testdata/TestPoissonFunction/lam-1706-10.golden
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
icdf
|
||||
93907545465879218275260347624273708225148723352890415890955745471328115138024
|
||||
57447553596668785643406883388130520172829512611140657354486862128150346836988
|
||||
27076095525930017054568011324233899656590951319429188573619716140132147265911
|
||||
10209654292635635800479757502291310268341281539592025246744927385067352842651
|
||||
3184715634432458451975226003210729824895496226017269232182332263939291493510
|
||||
843984120585852874524302031056145794325474791455055607017530061469667926785
|
||||
194034907919461416983404196340045475941285897027461784665454449911533518447
|
||||
39345544525367691179167072173518251727638261160626536209449847049064587000
|
||||
7131182470884793691126479665205819536661348710819293305892247868965466268
|
||||
1167890189531948301087715470416213490892402026859749426392544722128541359
|
||||
174396377814374645286335419995210764907848995332895729280582459579342738
|
||||
23925812935985027317838050852967276757134553590636105055350959232313899
|
||||
3035286920153916620063269622769735189335169019323041991528942663951986
|
||||
358060554242868329017312833503133182524340437692927389149107908421231
|
||||
39467628723598770945019147503633808666969235107758896427288845018926
|
||||
4082242594961149456000070139366495398696105445630156285138889148853
|
17
chain/types/testdata/TestPoissonFunction/lam-2-0.golden
vendored
Normal file
17
chain/types/testdata/TestPoissonFunction/lam-2-0.golden
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
icdf
|
||||
100121334043824876020967110392587568107053060743383522309741056272383359786578
|
||||
68779823656842237215759361160386888614619212898869438850308000801323820079862
|
||||
37438313269859598410551611928186209122185365054355355390874945330264280373146
|
||||
16543973011871172540413112440052422793896133158012633084586241682891253902002
|
||||
6096802882876959605343862695985529629751517209841271931441889859204740666430
|
||||
1917934831279274431316162798358772364093670830572727470184149129730135372202
|
||||
524978814080046039973596165816519942207722037483212649764902219905266940794
|
||||
126991380594552213875719985090162107383165239457636986787974531383875960392
|
||||
27494522223178757351250939908572648677026039951243071043742609253528215292
|
||||
5384109251762433679146707645997213408995106727599978656135515446784271938
|
||||
962026657479168944725861193482126355388920082871360178614096685435483268
|
||||
158011640336757174831161838479383254733249783829793182701111456099339874
|
||||
24009137479688546515378612645592737957304733989532016715613917876649310
|
||||
3393367809370296005258116363471119991774726321799529640921988919312302
|
||||
448257856467688789526616894596603139556153797837745773108856211121302
|
||||
55576529414007827429083632080000892593677461309507924067105183362502
|
17
chain/types/testdata/TestPoissonFunction/lam-209714-20.golden
vendored
Normal file
17
chain/types/testdata/TestPoissonFunction/lam-209714-20.golden
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
icdf
|
||||
20989436322611254574979389012727393136091537312055593688180077279147576363096
|
||||
2029014232696520721523332453453803636238058967796600089005757967894658844577
|
||||
132982872945592560215194824292206599698851338836977427578620974467337246296
|
||||
6581505574095040906286115477587166321018484661524779791358182693980706360
|
||||
261473369241451189291715224208035992983406808190620756138506410631265448
|
||||
8673527587881831627652027122245179992541421812500366598395022980519170
|
||||
246914417172755020716947338861248744263385116558896234139925344965714
|
||||
6155418508705151241339695503211918565434455355693098789916851059631
|
||||
136477982954924943101944815709613669983383501630000081908122878386
|
||||
2724514397229876659600187515561464490237868059330199615762951760
|
||||
49460332945698577716770256622916953121860884014393828193908634
|
||||
823264627479642334265449493920662550930201158945634649498769
|
||||
12651460568281449375957051928671501418597070452648092732548
|
||||
180560129118157986659345179422379755776654969450793746138
|
||||
2405427973892505908363489341734991530618943133521671600
|
||||
30045550760659097055494870911555042207154242485930695
|
17
chain/types/testdata/TestPoissonFunction/lam-5-0.golden
vendored
Normal file
17
chain/types/testdata/TestPoissonFunction/lam-5-0.golden
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
icdf
|
||||
115011888277122352219705460287186602222085188670665840381425306072442950421456
|
||||
111110883476153136200377836679680074066161208695792222091263916395092054329056
|
||||
101358371473730096152058777660913753676351258758608176365860442201714814098056
|
||||
85104184803025029404860345962969886360001342196634766823521318546086080379726
|
||||
64786451464643695970862306340540052214563946494168004895597413976550163231816
|
||||
44468718126262362536864266718110218069126550791701242967673509407014246083906
|
||||
27537273677611251341865900366085356281262054372978941361070255599067648460651
|
||||
15443384785717600488295638686067597861358842645320154499210788593391507301186
|
||||
7884704228284068704814225136056498848919335315533412710548621714843919076521
|
||||
3685437251932106602880106497161443842008497910096333939069640115650814507266
|
||||
1585803763756125551913047177713916338553079207377794553330149316054262222641
|
||||
631424905494315983291656577965040200618797978869367559812198952601283911451
|
||||
233767047885228663032743828069675143146180800324189645846386301162542948456
|
||||
80821718035579693702392770417611659502866500883736602013381435224565655001
|
||||
26198385946419347512981678399017558201682822512146229215879697389573764486
|
||||
7990608583365898783177981059486191101288263054949438283379118111243134316
|
17
chain/types/testdata/TestPoissonFunction/lam-5242879-20.golden
vendored
Normal file
17
chain/types/testdata/TestPoissonFunction/lam-5242879-20.golden
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
icdf
|
||||
115011887533064380050215202002871794783671664388541274939039184893270600703151
|
||||
111110879755863630144777547269452207577572562543679248972859798819416242535921
|
||||
101358362173007217989878395557465593373392010546833825352856759707561945139525
|
||||
85104169301821710755220628061805234978705652326202881500299286939503312327242
|
||||
64786432088141395502693562453332343133008530920262028792733819517798429528997
|
||||
44468698749761909885846743680008378684637277300179598543979674797636862943384
|
||||
27537257530529080605729671834720742022613060678716434560927439906969908575619
|
||||
15443373252088578337713549627194971124753642243467082552611819728291522561946
|
||||
7884697019766617162458477655388623015603913245952633503615157778326861227793
|
||||
3685433247200570820185174890022164698361097802621279879954268046011715772231
|
||||
1585801761390548420193995297013958176769177427873274589439743405082427147382
|
||||
631423995328231141553650878972791975288890578033071631113620389859816342901
|
||||
233766668649395912353875000216328335294367462954196928187468994385755448892
|
||||
80821572175657684536655650469711580587115741420816601432036447172153463116
|
||||
26198333853594769407667441209847842642730676168975225661522405972966431948
|
||||
7990591219092428810606628986022697269060757693982546042792694706871429282
|
@ -112,6 +112,10 @@ func NewTipSet(blks []*BlockHeader) (*TipSet, error) {
|
||||
return nil, fmt.Errorf("cannot create tipset with mismatching heights")
|
||||
}
|
||||
|
||||
if len(blks[0].Parents) != len(b.Parents) {
|
||||
return nil, fmt.Errorf("cannot create tipset with mismatching number of parents")
|
||||
}
|
||||
|
||||
for i, cid := range b.Parents {
|
||||
if cid != blks[0].Parents[i] {
|
||||
return nil, fmt.Errorf("cannot create tipset with mismatching parents")
|
||||
|
@ -19,7 +19,7 @@ func TestSignedMessageJsonRoundtrip(t *testing.T) {
|
||||
Method: 1235126,
|
||||
Value: types.NewInt(123123),
|
||||
GasPrice: types.NewInt(1234),
|
||||
GasLimit: 9992969384,
|
||||
GasLimit: 100_000_000,
|
||||
Nonce: 123123,
|
||||
},
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package validation
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
@ -72,8 +73,8 @@ func (a *Applier) ApplyTipSetMessages(epoch abi.ChainEpoch, blocks []vtypes.Bloc
|
||||
var bms []stmgr.BlockMessages
|
||||
for _, b := range blocks {
|
||||
bm := stmgr.BlockMessages{
|
||||
Miner: b.Miner,
|
||||
TicketCount: 1,
|
||||
Miner: b.Miner,
|
||||
WinCount: 1,
|
||||
}
|
||||
|
||||
for _, m := range b.BLSMessages {
|
||||
|
@ -18,14 +18,31 @@ const (
|
||||
)
|
||||
|
||||
type GasCharge struct {
|
||||
Name string
|
||||
Name string
|
||||
Extra interface{}
|
||||
|
||||
ComputeGas int64
|
||||
StorageGas int64
|
||||
|
||||
VirtualCompute int64
|
||||
VirtualStorage int64
|
||||
}
|
||||
|
||||
func (g GasCharge) Total() int64 {
|
||||
return g.ComputeGas*GasComputeMulti + g.StorageGas*GasStorageMulti
|
||||
}
|
||||
func (g GasCharge) WithVirtual(compute, storage int64) GasCharge {
|
||||
out := g
|
||||
out.VirtualCompute = compute
|
||||
out.VirtualStorage = storage
|
||||
return out
|
||||
}
|
||||
|
||||
func (g GasCharge) WithExtra(extra interface{}) GasCharge {
|
||||
out := g
|
||||
out.Extra = extra
|
||||
return out
|
||||
}
|
||||
|
||||
func newGasCharge(name string, computeGas int64, storageGas int64) GasCharge {
|
||||
return GasCharge{
|
||||
@ -48,7 +65,7 @@ type Pricelist interface {
|
||||
OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) GasCharge
|
||||
|
||||
// OnIpldGet returns the gas used for storing an object
|
||||
OnIpldGet(dataSize int) GasCharge
|
||||
OnIpldGet() GasCharge
|
||||
// OnIpldPut returns the gas used for storing an object
|
||||
OnIpldPut(dataSize int) GasCharge
|
||||
|
||||
@ -59,7 +76,7 @@ type Pricelist interface {
|
||||
|
||||
OnVerifySignature(sigType crypto.SigType, planTextSize int) (GasCharge, error)
|
||||
OnHashing(dataSize int) GasCharge
|
||||
OnComputeUnsealedSectorCid(proofType abi.RegisteredProof, pieces []abi.PieceInfo) GasCharge
|
||||
OnComputeUnsealedSectorCid(proofType abi.RegisteredSealProof, pieces []abi.PieceInfo) GasCharge
|
||||
OnVerifySeal(info abi.SealVerifyInfo) GasCharge
|
||||
OnVerifyPost(info abi.WindowPoStVerifyInfo) GasCharge
|
||||
OnVerifyConsensusFault() GasCharge
|
||||
@ -67,30 +84,35 @@ type Pricelist interface {
|
||||
|
||||
var prices = map[abi.ChainEpoch]Pricelist{
|
||||
abi.ChainEpoch(0): &pricelistV0{
|
||||
onChainMessageBase: 0,
|
||||
onChainMessagePerByte: 2,
|
||||
onChainReturnValuePerByte: 8,
|
||||
sendBase: 5,
|
||||
sendTransferFunds: 5,
|
||||
sendInvokeMethod: 10,
|
||||
ipldGetBase: 10,
|
||||
ipldGetPerByte: 1,
|
||||
ipldPutBase: 20,
|
||||
ipldPutPerByte: 2,
|
||||
createActorBase: 40, // IPLD put + 20
|
||||
createActorExtra: 500,
|
||||
deleteActor: -500, // -createActorExtra
|
||||
// Dragons: this cost is not persistable, create a LinearCost{a,b} struct that has a `.Cost(x) -> ax + b`
|
||||
verifySignature: map[crypto.SigType]func(int64) int64{
|
||||
crypto.SigTypeBLS: func(x int64) int64 { return 3*x + 2 },
|
||||
crypto.SigTypeSecp256k1: func(x int64) int64 { return 3*x + 2 },
|
||||
onChainMessageComputeBase: 137137,
|
||||
onChainMessageStorageBase: 0, // TODO gas
|
||||
onChainMessageStoragePerByte: 2, // TODO gas
|
||||
|
||||
onChainReturnValuePerByte: 8, // TODO gas
|
||||
|
||||
sendBase: 97236,
|
||||
sendTransferFunds: 96812,
|
||||
sendTransferOnlyPremium: 347806,
|
||||
sendInvokeMethod: -3110,
|
||||
|
||||
ipldGetBase: 417230,
|
||||
ipldPutBase: 396100,
|
||||
ipldPutPerByte: 2, // TODO gas
|
||||
|
||||
createActorCompute: 750011,
|
||||
createActorStorage: 500, // TODO gas
|
||||
deleteActor: -500, // -createActorStorage
|
||||
|
||||
verifySignature: map[crypto.SigType]int64{
|
||||
crypto.SigTypeBLS: 219946580,
|
||||
crypto.SigTypeSecp256k1: 6726720,
|
||||
},
|
||||
hashingBase: 5,
|
||||
hashingPerByte: 2,
|
||||
computeUnsealedSectorCidBase: 100,
|
||||
verifySealBase: 2000,
|
||||
verifyPostBase: 700,
|
||||
verifyConsensusFault: 10,
|
||||
|
||||
hashingBase: 110685,
|
||||
computeUnsealedSectorCidBase: 431890,
|
||||
verifySealBase: 2000, // TODO gas , it VerifySeal syscall is not used
|
||||
verifyPostBase: 2621447835,
|
||||
verifyConsensusFault: 495422,
|
||||
},
|
||||
}
|
||||
|
||||
@ -126,30 +148,40 @@ func (ps pricedSyscalls) VerifySignature(signature crypto.Signature, signer addr
|
||||
return err
|
||||
}
|
||||
ps.chargeGas(c)
|
||||
defer ps.chargeGas(gasOnActorExec)
|
||||
|
||||
return ps.under.VerifySignature(signature, signer, plaintext)
|
||||
}
|
||||
|
||||
// Hashes input data using blake2b with 256 bit output.
|
||||
func (ps pricedSyscalls) HashBlake2b(data []byte) [32]byte {
|
||||
ps.chargeGas(ps.pl.OnHashing(len(data)))
|
||||
defer ps.chargeGas(gasOnActorExec)
|
||||
|
||||
return ps.under.HashBlake2b(data)
|
||||
}
|
||||
|
||||
// Computes an unsealed sector CID (CommD) from its constituent piece CIDs (CommPs) and sizes.
|
||||
func (ps pricedSyscalls) ComputeUnsealedSectorCID(reg abi.RegisteredProof, pieces []abi.PieceInfo) (cid.Cid, error) {
|
||||
func (ps pricedSyscalls) ComputeUnsealedSectorCID(reg abi.RegisteredSealProof, pieces []abi.PieceInfo) (cid.Cid, error) {
|
||||
ps.chargeGas(ps.pl.OnComputeUnsealedSectorCid(reg, pieces))
|
||||
defer ps.chargeGas(gasOnActorExec)
|
||||
|
||||
return ps.under.ComputeUnsealedSectorCID(reg, pieces)
|
||||
}
|
||||
|
||||
// Verifies a sector seal proof.
|
||||
func (ps pricedSyscalls) VerifySeal(vi abi.SealVerifyInfo) error {
|
||||
ps.chargeGas(ps.pl.OnVerifySeal(vi))
|
||||
defer ps.chargeGas(gasOnActorExec)
|
||||
|
||||
return ps.under.VerifySeal(vi)
|
||||
}
|
||||
|
||||
// Verifies a proof of spacetime.
|
||||
func (ps pricedSyscalls) VerifyPoSt(vi abi.WindowPoStVerifyInfo) error {
|
||||
ps.chargeGas(ps.pl.OnVerifyPost(vi))
|
||||
defer ps.chargeGas(gasOnActorExec)
|
||||
|
||||
return ps.under.VerifyPoSt(vi)
|
||||
}
|
||||
|
||||
@ -165,10 +197,21 @@ func (ps pricedSyscalls) VerifyPoSt(vi abi.WindowPoStVerifyInfo) error {
|
||||
// Returns nil and an error if the headers don't prove a fault.
|
||||
func (ps pricedSyscalls) VerifyConsensusFault(h1 []byte, h2 []byte, extra []byte) (*runtime.ConsensusFault, error) {
|
||||
ps.chargeGas(ps.pl.OnVerifyConsensusFault())
|
||||
defer ps.chargeGas(gasOnActorExec)
|
||||
|
||||
return ps.under.VerifyConsensusFault(h1, h2, extra)
|
||||
}
|
||||
|
||||
func (ps pricedSyscalls) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) {
|
||||
ps.chargeGas(newGasCharge("BatchVerifySeals", 0, 0)) // TODO: this is only called by the cron actor. Should we even charge gas?
|
||||
count := int64(0)
|
||||
for _, svis := range inp {
|
||||
count += int64(len(svis))
|
||||
}
|
||||
|
||||
gasChargeSum := newGasCharge("BatchVerifySeals", 0, 0)
|
||||
gasChargeSum = gasChargeSum.WithExtra(count).WithVirtual(15075005*count+899741502, 0)
|
||||
ps.chargeGas(gasChargeSum) // real gas charged by actors
|
||||
defer ps.chargeGas(gasOnActorExec)
|
||||
|
||||
return ps.under.BatchVerifySeals(inp)
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
)
|
||||
@ -19,8 +20,9 @@ type pricelistV0 struct {
|
||||
// Together, these account for the cost of message propagation and validation,
|
||||
// up to but excluding any actual processing by the VM.
|
||||
// This is the cost a block producer burns when including an invalid message.
|
||||
onChainMessageBase int64
|
||||
onChainMessagePerByte int64
|
||||
onChainMessageComputeBase int64
|
||||
onChainMessageStorageBase int64
|
||||
onChainMessageStoragePerByte int64
|
||||
|
||||
// Gas cost charged to the originator of a non-nil return value produced
|
||||
// by an on-chain message is given by:
|
||||
@ -40,15 +42,17 @@ type pricelistV0 struct {
|
||||
// already accounted for).
|
||||
sendTransferFunds int64
|
||||
|
||||
// Gsa cost charged, in addition to SendBase, if message only transfers funds.
|
||||
sendTransferOnlyPremium int64
|
||||
|
||||
// Gas cost charged, in addition to SendBase, if a message invokes
|
||||
// a method on the receiver.
|
||||
// Accounts for the cost of loading receiver code and method dispatch.
|
||||
sendInvokeMethod int64
|
||||
|
||||
// Gas cost (Base + len*PerByte) for any Get operation to the IPLD store
|
||||
// Gas cost for any Get operation to the IPLD store
|
||||
// in the runtime VM context.
|
||||
ipldGetBase int64
|
||||
ipldGetPerByte int64
|
||||
ipldGetBase int64
|
||||
|
||||
// Gas cost (Base + len*PerByte) for any Put operation to the IPLD store
|
||||
// in the runtime VM context.
|
||||
@ -63,18 +67,17 @@ type pricelistV0 struct {
|
||||
//
|
||||
// Note: this costs assume that the extra will be partially or totally refunded while
|
||||
// the base is covering for the put.
|
||||
createActorBase int64
|
||||
createActorExtra int64
|
||||
createActorCompute int64
|
||||
createActorStorage int64
|
||||
|
||||
// Gas cost for deleting an actor.
|
||||
//
|
||||
// Note: this partially refunds the create cost to incentivise the deletion of the actors.
|
||||
deleteActor int64
|
||||
|
||||
verifySignature map[crypto.SigType]func(len int64) int64
|
||||
verifySignature map[crypto.SigType]int64
|
||||
|
||||
hashingBase int64
|
||||
hashingPerByte int64
|
||||
hashingBase int64
|
||||
|
||||
computeUnsealedSectorCidBase int64
|
||||
verifySealBase int64
|
||||
@ -86,7 +89,8 @@ var _ Pricelist = (*pricelistV0)(nil)
|
||||
|
||||
// OnChainMessage returns the gas used for storing a message of a given size in the chain.
|
||||
func (pl *pricelistV0) OnChainMessage(msgSize int) GasCharge {
|
||||
return newGasCharge("OnChainMessage", 0, pl.onChainMessageBase+pl.onChainMessagePerByte*int64(msgSize))
|
||||
return newGasCharge("OnChainMessage", pl.onChainMessageComputeBase,
|
||||
pl.onChainMessageStorageBase+pl.onChainMessageStoragePerByte*int64(msgSize))
|
||||
}
|
||||
|
||||
// OnChainReturnValue returns the gas used for storing the response of a message in the chain.
|
||||
@ -97,28 +101,39 @@ func (pl *pricelistV0) OnChainReturnValue(dataSize int) GasCharge {
|
||||
// OnMethodInvocation returns the gas used when invoking a method.
|
||||
func (pl *pricelistV0) OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) GasCharge {
|
||||
ret := pl.sendBase
|
||||
if value != abi.NewTokenAmount(0) {
|
||||
extra := ""
|
||||
|
||||
if big.Cmp(value, abi.NewTokenAmount(0)) != 0 {
|
||||
ret += pl.sendTransferFunds
|
||||
if methodNum == builtin.MethodSend {
|
||||
// transfer only
|
||||
ret += pl.sendTransferOnlyPremium
|
||||
}
|
||||
extra += "t"
|
||||
}
|
||||
|
||||
if methodNum != builtin.MethodSend {
|
||||
extra += "i"
|
||||
// running actors is cheaper becase we hand over to actors
|
||||
ret += pl.sendInvokeMethod
|
||||
}
|
||||
return newGasCharge("OnMethodInvocation", ret, 0)
|
||||
return newGasCharge("OnMethodInvocation", ret, 0).WithExtra(extra)
|
||||
}
|
||||
|
||||
// OnIpldGet returns the gas used for storing an object
|
||||
func (pl *pricelistV0) OnIpldGet(dataSize int) GasCharge {
|
||||
return newGasCharge(fmt.Sprintf("OnIpldGet:%db", dataSize), pl.ipldGetBase+int64(dataSize)*pl.ipldGetPerByte, 0)
|
||||
func (pl *pricelistV0) OnIpldGet() GasCharge {
|
||||
return newGasCharge("OnIpldGet", pl.ipldGetBase, 0)
|
||||
}
|
||||
|
||||
// OnIpldPut returns the gas used for storing an object
|
||||
func (pl *pricelistV0) OnIpldPut(dataSize int) GasCharge {
|
||||
return newGasCharge(fmt.Sprintf("OnIpldPut:%db", dataSize), pl.ipldPutBase, int64(dataSize)*pl.ipldPutPerByte)
|
||||
return newGasCharge("OnIpldPut", pl.ipldPutBase, int64(dataSize)*pl.ipldPutPerByte).
|
||||
WithExtra(dataSize)
|
||||
}
|
||||
|
||||
// OnCreateActor returns the gas used for creating an actor
|
||||
func (pl *pricelistV0) OnCreateActor() GasCharge {
|
||||
return newGasCharge("OnCreateActor", pl.createActorBase, pl.createActorExtra)
|
||||
return newGasCharge("OnCreateActor", pl.createActorCompute, pl.createActorStorage)
|
||||
}
|
||||
|
||||
// OnDeleteActor returns the gas used for deleting an actor
|
||||
@ -127,36 +142,41 @@ func (pl *pricelistV0) OnDeleteActor() GasCharge {
|
||||
}
|
||||
|
||||
// OnVerifySignature
|
||||
|
||||
func (pl *pricelistV0) OnVerifySignature(sigType crypto.SigType, planTextSize int) (GasCharge, error) {
|
||||
costFn, ok := pl.verifySignature[sigType]
|
||||
cost, ok := pl.verifySignature[sigType]
|
||||
if !ok {
|
||||
return GasCharge{}, fmt.Errorf("cost function for signature type %d not supported", sigType)
|
||||
}
|
||||
|
||||
sigName, _ := sigType.Name()
|
||||
return newGasCharge("OnVerifySignature/"+sigName, costFn(int64(planTextSize)), 0), nil
|
||||
return newGasCharge("OnVerifySignature", cost, 0).
|
||||
WithExtra(map[string]interface{}{
|
||||
"type": sigName,
|
||||
"size": planTextSize,
|
||||
}), nil
|
||||
}
|
||||
|
||||
// OnHashing
|
||||
func (pl *pricelistV0) OnHashing(dataSize int) GasCharge {
|
||||
return newGasCharge("OnHashing", pl.hashingBase+int64(dataSize)*pl.hashingPerByte, 0)
|
||||
return newGasCharge("OnHashing", pl.hashingBase, 0).WithExtra(dataSize)
|
||||
}
|
||||
|
||||
// OnComputeUnsealedSectorCid
|
||||
func (pl *pricelistV0) OnComputeUnsealedSectorCid(proofType abi.RegisteredProof, pieces []abi.PieceInfo) GasCharge {
|
||||
// TODO: this needs more cost tunning, check with @lotus
|
||||
func (pl *pricelistV0) OnComputeUnsealedSectorCid(proofType abi.RegisteredSealProof, pieces []abi.PieceInfo) GasCharge {
|
||||
return newGasCharge("OnComputeUnsealedSectorCid", pl.computeUnsealedSectorCidBase, 0)
|
||||
}
|
||||
|
||||
// OnVerifySeal
|
||||
func (pl *pricelistV0) OnVerifySeal(info abi.SealVerifyInfo) GasCharge {
|
||||
// TODO: this needs more cost tunning, check with @lotus
|
||||
// this is not used
|
||||
return newGasCharge("OnVerifySeal", pl.verifySealBase, 0)
|
||||
}
|
||||
|
||||
// OnVerifyPost
|
||||
func (pl *pricelistV0) OnVerifyPost(info abi.WindowPoStVerifyInfo) GasCharge {
|
||||
// TODO: this needs more cost tunning, check with @lotus
|
||||
return newGasCharge("OnVerifyPost", pl.verifyPostBase, 0)
|
||||
return newGasCharge("OnVerifyPost", pl.verifyPostBase, 0).WithExtra(len(info.ChallengedSectors))
|
||||
}
|
||||
|
||||
// OnVerifyConsensusFault
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user