Compare commits

..
1 Commits
Author SHA1 Message Date
Travis Person 06670f4cae New interop network info 2020-06-02 00:29:49 +00:00
259 changed files with 4592 additions and 13330 deletions
+29 -6
View File
@@ -1,6 +1,6 @@
version: 2.1 version: 2.1
orbs: orbs:
go: gotest/tools@0.0.13 go: gotest/tools@0.0.9
executors: executors:
golang: golang:
@@ -45,7 +45,7 @@ commands:
- 'v25-2k-lotus-params' - 'v25-2k-lotus-params'
paths: paths:
- /var/tmp/filecoin-proof-parameters/ - /var/tmp/filecoin-proof-parameters/
- run: ./lotus fetch-params 2048 - run: ./lotus fetch-params --proving-params 2048
- save_cache: - save_cache:
name: Save parameters cache name: Save parameters cache
key: 'v25-2k-lotus-params' key: 'v25-2k-lotus-params'
@@ -79,6 +79,7 @@ jobs:
steps: steps:
- install-deps - install-deps
- prepare - prepare
- go/mod-download
- go/mod-tidy-check - go/mod-tidy-check
build-all: build-all:
@@ -86,8 +87,12 @@ jobs:
steps: steps:
- install-deps - install-deps
- prepare - prepare
- go/mod-download
- run: sudo apt-get update - run: sudo apt-get update
- run: sudo apt-get install npm - run: sudo apt-get install npm
- restore_cache:
name: restore go mod cache
key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }}
- run: - run:
command: make buildall command: make buildall
- store_artifacts: - store_artifacts:
@@ -107,6 +112,10 @@ jobs:
steps: steps:
- install-deps - install-deps
- prepare - prepare
- go/mod-download
- restore_cache:
name: restore go mod cache
key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }}
- run: - run:
command: make debug command: make debug
@@ -150,6 +159,10 @@ jobs:
steps: steps:
- install-deps - install-deps
- prepare - prepare
- go/mod-download
- restore_cache:
name: restore go mod cache
key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }}
- run: - run:
command: make deps lotus command: make deps lotus
no_output_timeout: 30m no_output_timeout: 30m
@@ -180,6 +193,13 @@ jobs:
shell: /bin/bash -eo pipefail shell: /bin/bash -eo pipefail
command: | command: |
bash <(curl -s https://codecov.io/bash) bash <(curl -s https://codecov.io/bash)
- save_cache:
name: save go mod cache
key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }}
paths:
- "~/go/pkg"
- "~/go/src/github.com"
- "~/go/src/golang.org"
test-short: test-short:
<<: *test <<: *test
@@ -214,9 +234,10 @@ jobs:
curl --location https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64 --output /usr/local/bin/jq curl --location https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64 --output /usr/local/bin/jq
chmod +x /usr/local/bin/jq chmod +x /usr/local/bin/jq
- restore_cache: - restore_cache:
name: restore cargo cache name: restore go mod and cargo cache
key: v3-go-deps-{{ arch }}-{{ checksum "~/go/src/github.com/filecoin-project/lotus/go.sum" }} key: v3-go-deps-{{ arch }}-{{ checksum "~/go/src/github.com/filecoin-project/lotus/go.sum" }}
- install-deps - install-deps
- go/mod-download
- run: - run:
command: make build command: make build
no_output_timeout: 30m no_output_timeout: 30m
@@ -243,6 +264,7 @@ jobs:
steps: steps:
- install-deps - install-deps
- prepare - prepare
- go/mod-download
- run: - run:
command: "! go fmt ./... 2>&1 | read" command: "! go fmt ./... 2>&1 | read"
@@ -255,7 +277,7 @@ jobs:
default: golang default: golang
golangci-lint-version: golangci-lint-version:
type: string type: string
default: 1.27.0 default: 1.23.8
concurrency: concurrency:
type: string type: string
default: '2' default: '2'
@@ -271,6 +293,7 @@ jobs:
steps: steps:
- install-deps - install-deps
- prepare - prepare
- go/mod-download
- run: - run:
command: make deps command: make deps
no_output_timeout: 30m no_output_timeout: 30m
@@ -280,7 +303,7 @@ jobs:
- run: - run:
name: Lint name: Lint
command: | command: |
$HOME/.local/bin/golangci-lint run -v --timeout 2m \ $HOME/.local/bin/golangci-lint run -v \
--concurrency << parameters.concurrency >> << parameters.args >> --concurrency << parameters.concurrency >> << parameters.args >>
lint-changes: lint-changes:
<<: *lint <<: *lint
@@ -314,7 +337,7 @@ workflows:
ci: ci:
jobs: jobs:
- lint-changes: - lint-changes:
args: "--new-from-rev origin/master" args: "--new-from-rev origin/next"
- mod-tidy-check - mod-tidy-check
- gofmt - gofmt
- test: - test:
+1 -1
View File
@@ -21,7 +21,7 @@ A clear and concise description of what you expected to happen.
**Screenshots** **Screenshots**
If applicable, add screenshots to help explain your problem. If applicable, add screenshots to help explain your problem.
**Version (run `lotus version`):** **Version (run `lotus --version`):**
**Additional context** **Additional context**
Add any other context about the problem here. Add any other context about the problem here.
-1
View File
@@ -35,4 +35,3 @@ build/paramfetch.sh
bin/ipget bin/ipget
bin/tmp/* bin/tmp/*
.idea .idea
scratchpad
-4
View File
@@ -37,10 +37,6 @@ issues:
- path: build/params_.*\.go - path: build/params_.*\.go
linters: linters:
- golint - golint
- path: api/apistruct/struct.go
linters:
- golint
- path: .*_test.go - path: .*_test.go
linters: linters:
+3 -17
View File
@@ -6,7 +6,7 @@ all: build
unexport GOFLAGS unexport GOFLAGS
GOVERSION:=$(shell go version | cut -d' ' -f 3 | cut -d. -f 2) GOVERSION:=$(shell go version | cut -d' ' -f 3 | cut -d. -f 2)
ifeq ($(shell expr $(GOVERSION) \< 14), 1) ifeq ($(shell expr $(GOVERSION) \< 13), 1)
$(warning Your Golang version is go 1.$(GOVERSION)) $(warning Your Golang version is go 1.$(GOVERSION))
$(error Update Golang to version $(shell grep '^go' go.mod)) $(error Update Golang to version $(shell grep '^go' go.mod))
endif endif
@@ -105,17 +105,15 @@ install:
install-services: install install-services: install
mkdir -p /usr/local/lib/systemd/system 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-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 install -C -m 0644 ./scripts/lotus-miner.service /usr/local/lib/systemd/system/lotus-miner.service
systemctl daemon-reload systemctl daemon-reload
@echo @echo
@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." @echo "lotus and lotus-miner services installed. Don't forget to 'systemctl enable lotus|lotus-miner' for it to be enabled on startup."
clean-services: clean-services:
rm -f /usr/local/lib/systemd/system/lotus-daemon.service 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-miner.service
rm -f /usr/local/lib/systemd/system/chainwatch.service
systemctl daemon-reload systemctl daemon-reload
# TOOLS # TOOLS
@@ -158,16 +156,10 @@ BINS+=fountain
chainwatch: chainwatch:
rm -f chainwatch rm -f chainwatch
go build -o chainwatch ./cmd/lotus-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 .PHONY: chainwatch
BINS+=chainwatch BINS+=chainwatch
install-chainwatch-service: chainwatch
install -C ./chainwatch /usr/local/bin/chainwatch
install -C -m 0644 ./scripts/chainwatch.service /usr/local/lib/systemd/system/chainwatch.service
systemctl daemon-reload
@echo
@echo "chainwatch installed. Don't forget to 'systemctl enable chainwatch' for it to be enabled on startup."
bench: bench:
rm -f bench rm -f bench
go build -o bench ./cmd/lotus-bench go build -o bench ./cmd/lotus-bench
@@ -190,12 +182,6 @@ health:
.PHONY: health .PHONY: health
BINS+=health BINS+=health
testground:
go build -tags testground -o /dev/null ./cmd/lotus
.PHONY: testground
BINS+=testground
# MISC # MISC
buildall: $(BINS) buildall: $(BINS)
+3 -12
View File
@@ -4,22 +4,13 @@
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). 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).
## 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 ## 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). 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: ## Building & Documentation
* [`master`](https://github.com/filecoin-project/lotus): current testnet.
* [`next`](https://github.com/filecoin-project/lotus/tree/next): working branch with chain-breaking changes. 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).
* [`ntwk-calibration`](https://github.com/filecoin-project/lotus/tree/ntwk-calibration): devnet running one of `next` commits.
## License ## License
-29
View File
@@ -1,29 +0,0 @@
# 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: |
+2 -12
View File
@@ -13,13 +13,11 @@ import (
) )
type Common interface { type Common interface {
// Auth
// MethodGroup: Auth
AuthVerify(ctx context.Context, token string) ([]auth.Permission, error) AuthVerify(ctx context.Context, token string) ([]auth.Permission, error)
AuthNew(ctx context.Context, perms []auth.Permission) ([]byte, error) AuthNew(ctx context.Context, perms []auth.Permission) ([]byte, error)
// MethodGroup: Net // network
NetConnectedness(context.Context, peer.ID) (network.Connectedness, error) NetConnectedness(context.Context, peer.ID) (network.Connectedness, error)
NetPeers(context.Context) ([]peer.AddrInfo, error) NetPeers(context.Context) ([]peer.AddrInfo, error)
@@ -27,9 +25,6 @@ type Common interface {
NetAddrsListen(context.Context) (peer.AddrInfo, error) NetAddrsListen(context.Context) (peer.AddrInfo, error)
NetDisconnect(context.Context, peer.ID) error NetDisconnect(context.Context, peer.ID) error
NetFindPeer(context.Context, peer.ID) (peer.AddrInfo, error) 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 returns peerID of libp2p node backing this API
ID(context.Context) (peer.ID, error) ID(context.Context) (peer.ID, error)
@@ -39,11 +34,6 @@ type Common interface {
LogList(context.Context) ([]string, error) LogList(context.Context) ([]string, error)
LogSetLevel(context.Context, string, string) error LogSetLevel(context.Context, string, string) error
// trigger graceful shutdown
Shutdown(context.Context) error
Closing(context.Context) (<-chan struct{}, error)
} }
// Version provides various build-time information // Version provides various build-time information
+34 -189
View File
@@ -26,126 +26,60 @@ import (
type FullNode interface { type FullNode interface {
Common Common
// TODO: TipSetKeys
// MethodGroup: Chain // MethodGroup: Chain
// The Chain method group contains methods for interacting with the // 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. // ChainNotify returns channel with chain head updates
// First message is guaranteed to be of len == 1, and type == 'current'. // First message is guaranteed to be of len == 1, and type == 'current'
ChainNotify(context.Context) (<-chan []*HeadChange, error) 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) 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) 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) 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) ChainGetTipSet(context.Context, types.TipSetKey) (*types.TipSet, error)
ChainGetBlockMessages(context.Context, cid.Cid) (*BlockMessages, error)
// ChainGetBlockMessages returns messages stored in the specified block. ChainGetParentReceipts(context.Context, cid.Cid) ([]*types.MessageReceipt, error)
ChainGetBlockMessages(ctx context.Context, blockCid cid.Cid) (*BlockMessages, error) ChainGetParentMessages(context.Context, cid.Cid) ([]Message, 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 an earlier epoch
// will be returned.
ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) 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) 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) ChainHasObj(context.Context, cid.Cid) (bool, error)
ChainStatObj(context.Context, cid.Cid, cid.Cid) (ObjStat, 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 ChainSetHead(context.Context, types.TipSetKey) error
// ChainGetGenesis returns the genesis tipset.
ChainGetGenesis(context.Context) (*types.TipSet, error) ChainGetGenesis(context.Context) (*types.TipSet, error)
// ChainTipSetWeight computes weight for the specified tipset.
ChainTipSetWeight(context.Context, types.TipSetKey) (types.BigInt, error) ChainTipSetWeight(context.Context, types.TipSetKey) (types.BigInt, error)
ChainGetNode(ctx context.Context, p string) (*IpldObject, 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) 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) 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) ChainExport(context.Context, types.TipSetKey) (<-chan []byte, error)
// MethodGroup: Sync // MethodGroup: Sync
// The Sync method group contains methods for interacting with and // 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) 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 // network through this node
SyncSubmitBlock(ctx context.Context, blk *types.BlockMsg) error 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) 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 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) SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error)
// MethodGroup: Mpool // MethodGroup: Mpool
// The Mpool methods are for interacting with the message pool. The message pool // The Mpool methods are for interacting with the message pool. The message pool
// manages all incoming and outgoing 'messages' going over the network. // manages all incoming and outgoing 'messages' going over the network.
// MpoolPending returns pending mempool messages.
MpoolPending(context.Context, types.TipSetKey) ([]*types.SignedMessage, error) MpoolPending(context.Context, types.TipSetKey) ([]*types.SignedMessage, error)
// MpoolPush pushes a signed message to mempool.
MpoolPush(context.Context, *types.SignedMessage) (cid.Cid, error) 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) MpoolGetNonce(context.Context, address.Address) (uint64, error)
MpoolSub(context.Context) (<-chan MpoolUpdate, error) MpoolSub(context.Context) (<-chan MpoolUpdate, error)
MpoolEstimateGasPrice(context.Context, uint64, address.Address, int64, types.TipSetKey) (types.BigInt, error)
// MpoolEstimateGasPrice estimates what gas price should be used for a
// message to have high likelihood of inclusion in `nblocksincl` epochs.
MpoolEstimateGasPrice(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error)
// MethodGroup: Miner // MethodGroup: Miner
@@ -156,31 +90,17 @@ type FullNode interface {
// MethodGroup: Wallet // MethodGroup: Wallet
// WalletNew creates a new address in the wallet with the given sigType.
WalletNew(context.Context, crypto.SigType) (address.Address, error) 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) WalletHas(context.Context, address.Address) (bool, error)
// WalletList lists all the addresses in the wallet.
WalletList(context.Context) ([]address.Address, error) 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) 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) 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) 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 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) WalletDefaultAddress(context.Context) (address.Address, error)
// WalletSetDefault marks the given address as as the default one.
WalletSetDefault(context.Context, address.Address) error 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) 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) WalletImport(context.Context, *types.KeyInfo) (address.Address, error)
// WalletDelete deletes an address from the wallet.
WalletDelete(context.Context, address.Address) error
// Other // Other
@@ -188,27 +108,18 @@ type FullNode interface {
// The Client methods all have to do with interacting with the storage and // The Client methods all have to do with interacting with the storage and
// retrieval markets as a client // retrieval markets as a client
// ClientImport imports file under the specified path into filestore. // ClientImport imports file under the specified path into filestore
ClientImport(ctx context.Context, ref FileRef) (cid.Cid, error) ClientImport(ctx context.Context, ref FileRef) (cid.Cid, error)
// ClientStartDeal proposes a deal with a miner. // ClientStartDeal proposes a deal with a miner
ClientStartDeal(ctx context.Context, params *StartDealParams) (*cid.Cid, error) ClientStartDeal(ctx context.Context, params *StartDealParams) (*cid.Cid, error)
// ClientGetDealInfo returns the latest information about a given deal. // ClientGetDeal info returns the latest information about a given deal
ClientGetDealInfo(context.Context, cid.Cid) (*DealInfo, error) ClientGetDealInfo(context.Context, cid.Cid) (*DealInfo, error)
// ClientListDeals returns information about the deals made by the local client.
ClientListDeals(ctx context.Context) ([]DealInfo, error) ClientListDeals(ctx context.Context) ([]DealInfo, error)
// ClientHasLocal indicates whether a certain CID is locally stored.
ClientHasLocal(ctx context.Context, root cid.Cid) (bool, error) ClientHasLocal(ctx context.Context, root cid.Cid) (bool, error)
// ClientFindData identifies peers that have a certain file, and returns QueryOffers (one per peer).
ClientFindData(ctx context.Context, root cid.Cid) ([]QueryOffer, error) ClientFindData(ctx context.Context, root cid.Cid) ([]QueryOffer, error)
// ClientMinerQueryOffer returns a QueryOffer for the specific miner and file.
ClientMinerQueryOffer(ctx context.Context, root cid.Cid, miner address.Address) (QueryOffer, error)
// ClientRetrieve initiates the retrieval of a file, as specified in the order.
ClientRetrieve(ctx context.Context, order RetrievalOrder, ref *FileRef) error 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) 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) 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 ClientGenCar(ctx context.Context, ref FileRef, outpath string) error
// ClientUnimport removes references to the specified file from filestore // ClientUnimport removes references to the specified file from filestore
@@ -220,119 +131,55 @@ type FullNode interface {
//ClientListAsks() []Ask //ClientListAsks() []Ask
// MethodGroup: State // 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.
// StateCall runs the given message and returns its result without any persisted changes. // if tipset is nil, we'll use heaviest
StateCall(context.Context, *types.Message, types.TipSetKey) (*InvocResult, error) 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) 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) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error)
// StateReadState returns the indicated actor's state. StateReadState(ctx context.Context, act *types.Actor, tsk types.TipSetKey) (*ActorState, error)
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) 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) 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) StateMinerSectors(context.Context, address.Address, *abi.BitField, bool, types.TipSetKey) ([]*ChainSectorInfo, error)
// StateMinerProvingSet returns info about those sectors that a given miner is actively proving.
StateMinerProvingSet(context.Context, address.Address, types.TipSetKey) ([]*ChainSectorInfo, error) StateMinerProvingSet(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) 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) StateMinerPower(context.Context, address.Address, types.TipSetKey) (*MinerPower, error)
// StateMinerInfo returns info about the indicated miner StateMinerInfo(context.Context, address.Address, types.TipSetKey) (miner.MinerInfo, error)
StateMinerInfo(context.Context, address.Address, types.TipSetKey) (MinerInfo, error)
// StateMinerDeadlines returns all the proving deadlines for the given miner
StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) (*miner.Deadlines, error) StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) (*miner.Deadlines, error)
// StateMinerFaults returns a bitfield indicating the faulty sectors of the given miner
StateMinerFaults(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error) StateMinerFaults(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error)
// StateAllMinerFaults returns all non-expired Faults that occur within lookback epochs of the given tipset // 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) 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) StateMinerRecoveries(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error)
// StateMinerInitialPledgeCollateral returns the initial pledge collateral for the specified miner's sector
StateMinerInitialPledgeCollateral(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (types.BigInt, error) StateMinerInitialPledgeCollateral(context.Context, address.Address, abi.SectorNumber, 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) 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) StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error)
// StateSectorGetInfo returns the on-chain info for the specified miner's sector
StateSectorGetInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error) StateSectorGetInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error)
StatePledgeCollateral(context.Context, types.TipSetKey) (types.BigInt, error) StatePledgeCollateral(context.Context, types.TipSetKey) (types.BigInt, error)
// StateSearchMsg searches for a message in the chain, and returns its receipt and the tipset where it was executed StateWaitMsg(context.Context, cid.Cid) (*MsgLookup, error)
StateSearchMsg(context.Context, cid.Cid) (*MsgLookup, error) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) StateCompute(context.Context, abi.ChainEpoch, []*types.Message, types.TipSetKey) (*ComputeStateOutput, error)
// MethodGroup: Msig // MethodGroup: Msig
// The Msig methods are used to interact with multisig wallets on the // The Msig methods are used to interact with multisig wallets on the
// filecoin network // 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) MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
// MsigCreate creates a multisig wallet MsigCreate(context.Context, int64, []address.Address, types.BigInt, address.Address, types.BigInt) (cid.Cid, error)
// 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, int64, []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) 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) MsigApprove(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 MsigCancel(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
// 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) MarketEnsureAvailable(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error)
// MarketFreeBalance // MarketFreeBalance
@@ -387,10 +234,8 @@ type DealInfo struct {
} }
type MsgLookup struct { type MsgLookup struct {
Receipt types.MessageReceipt Receipt types.MessageReceipt
ReturnDec interface{} TipSet *types.TipSet
TipSet types.TipSetKey
Height abi.ChainEpoch
} }
type BlockMessages struct { type BlockMessages struct {
@@ -504,11 +349,11 @@ type RetrievalOrder struct {
} }
type InvocResult struct { type InvocResult struct {
Msg *types.Message Msg *types.Message
MsgRct *types.MessageReceipt MsgRct *types.MessageReceipt
ExecutionTrace types.ExecutionTrace InternalExecutions []*types.ExecutionResult
Error string Error string
Duration time.Duration Duration time.Duration
} }
type MethodCall struct { type MethodCall struct {
+1 -13
View File
@@ -36,7 +36,6 @@ type StorageMiner interface {
SectorsRefs(context.Context) (map[string][]SealedRef, error) SectorsRefs(context.Context) (map[string][]SealedRef, error)
SectorsUpdate(context.Context, abi.SectorNumber, SectorState) error SectorsUpdate(context.Context, abi.SectorNumber, SectorState) error
SectorRemove(context.Context, abi.SectorNumber) error
StorageList(ctx context.Context) (map[stores.ID][]stores.Decl, error) StorageList(ctx context.Context) (map[stores.ID][]stores.Decl, error)
StorageLocal(ctx context.Context) (map[stores.ID]string, error) StorageLocal(ctx context.Context) (map[stores.ID]string, error)
@@ -51,21 +50,10 @@ type StorageMiner interface {
MarketImportDealData(ctx context.Context, propcid cid.Cid, path string) error MarketImportDealData(ctx context.Context, propcid cid.Cid, path string) error
MarketListDeals(ctx context.Context) ([]storagemarket.StorageDeal, error) MarketListDeals(ctx context.Context) ([]storagemarket.StorageDeal, error)
MarketListIncompleteDeals(ctx context.Context) ([]storagemarket.MinerDeal, error) MarketListIncompleteDeals(ctx context.Context) ([]storagemarket.MinerDeal, error)
MarketSetAsk(ctx context.Context, price types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error MarketSetPrice(context.Context, types.BigInt) error
MarketGetAsk(ctx context.Context) (*storagemarket.SignedStorageAsk, error)
DealsImportData(ctx context.Context, dealPropCid cid.Cid, file string) error DealsImportData(ctx context.Context, dealPropCid cid.Cid, file string) error
DealsList(ctx context.Context) ([]storagemarket.StorageDeal, 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 StorageAddLocal(ctx context.Context, path string) error
} }
+1 -3
View File
@@ -25,12 +25,10 @@ type WorkerAPI interface {
storage.Sealer storage.Sealer
MoveStorage(ctx context.Context, sector abi.SectorID) error
UnsealPiece(context.Context, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize, abi.SealRandomness, cid.Cid) error UnsealPiece(context.Context, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize, abi.SealRandomness, cid.Cid) error
ReadPiece(context.Context, io.Writer, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize) error ReadPiece(context.Context, io.Writer, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize) error
Fetch(context.Context, abi.SectorID, stores.SectorFileType, stores.PathType, stores.AcquireMode) error Fetch(context.Context, abi.SectorID, stores.SectorFileType, bool, stores.AcquireMode) error
Closing(context.Context) (<-chan struct{}, error) Closing(context.Context) (<-chan struct{}, error)
} }
+54 -179
View File
@@ -42,16 +42,12 @@ type CommonStruct struct {
NetAddrsListen func(context.Context) (peer.AddrInfo, error) `perm:"read"` NetAddrsListen func(context.Context) (peer.AddrInfo, error) `perm:"read"`
NetDisconnect func(context.Context, peer.ID) error `perm:"write"` NetDisconnect func(context.Context, peer.ID) error `perm:"write"`
NetFindPeer func(context.Context, peer.ID) (peer.AddrInfo, error) `perm:"read"` NetFindPeer func(context.Context, peer.ID) (peer.AddrInfo, error) `perm:"read"`
NetPubsubScores func(context.Context) ([]api.PubsubScore, error) `perm:"read"`
ID func(context.Context) (peer.ID, error) `perm:"read"` ID func(context.Context) (peer.ID, error) `perm:"read"`
Version func(context.Context) (api.Version, error) `perm:"read"` Version func(context.Context) (api.Version, error) `perm:"read"`
LogList func(context.Context) ([]string, error) `perm:"write"` LogList func(context.Context) ([]string, error) `perm:"write"`
LogSetLevel func(context.Context, string, string) error `perm:"write"` LogSetLevel func(context.Context, string, string) error `perm:"write"`
Shutdown func(context.Context) error `perm:"admin"`
Closing func(context.Context) (<-chan struct{}, error) `perm:"read"`
} }
} }
@@ -107,27 +103,25 @@ type FullNodeStruct struct {
WalletSetDefault func(context.Context, address.Address) error `perm:"admin"` WalletSetDefault func(context.Context, address.Address) error `perm:"admin"`
WalletExport func(context.Context, address.Address) (*types.KeyInfo, error) `perm:"admin"` WalletExport func(context.Context, address.Address) (*types.KeyInfo, error) `perm:"admin"`
WalletImport func(context.Context, *types.KeyInfo) (address.Address, error) `perm:"admin"` 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"` ClientImport func(ctx context.Context, ref api.FileRef) (cid.Cid, error) `perm:"admin"`
ClientListImports func(ctx context.Context) ([]api.Import, error) `perm:"write"` ClientListImports func(ctx context.Context) ([]api.Import, error) `perm:"write"`
ClientHasLocal func(ctx context.Context, root cid.Cid) (bool, 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"` ClientFindData func(ctx context.Context, root cid.Cid) ([]api.QueryOffer, error) `perm:"read"`
ClientMinerQueryOffer func(ctx context.Context, root cid.Cid, miner address.Address) (api.QueryOffer, error) `perm:"read"` ClientStartDeal func(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) `perm:"admin"`
ClientStartDeal func(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) `perm:"admin"` ClientGetDealInfo func(context.Context, cid.Cid) (*api.DealInfo, error) `perm:"read"`
ClientGetDealInfo func(context.Context, cid.Cid) (*api.DealInfo, error) `perm:"read"` ClientListDeals func(ctx context.Context) ([]api.DealInfo, error) `perm:"write"`
ClientListDeals func(ctx context.Context) ([]api.DealInfo, error) `perm:"write"` ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error `perm:"admin"`
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"`
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"`
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"`
ClientGenCar func(ctx context.Context, ref api.FileRef, outpath string) error `perm:"write"`
StateNetworkName func(context.Context) (dtypes.NetworkName, error) `perm:"read"` 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"` 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"` StateMinerProvingSet 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"` 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"` 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"` StateMinerInfo func(context.Context, address.Address, types.TipSetKey) (miner.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.Deadlines, error) `perm:"read"`
StateMinerFaults func(context.Context, address.Address, types.TipSetKey) (*abi.BitField, 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"` StateAllMinerFaults func(context.Context, abi.ChainEpoch, types.TipSetKey) ([]*api.Fault, error) `perm:"read"`
@@ -139,9 +133,9 @@ type FullNodeStruct struct {
StateCall func(context.Context, *types.Message, types.TipSetKey) (*api.InvocResult, 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"` 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"` StateGetActor func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) `perm:"read"`
StateReadState func(context.Context, address.Address, types.TipSetKey) (*api.ActorState, error) `perm:"read"` StateReadState func(context.Context, *types.Actor, types.TipSetKey) (*api.ActorState, error) `perm:"read"`
StatePledgeCollateral func(context.Context, types.TipSetKey) (types.BigInt, 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"` StateWaitMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"`
StateSearchMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"` StateSearchMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"`
StateListMiners func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"` StateListMiners func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
StateListActors func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"` StateListActors func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
@@ -158,13 +152,10 @@ type FullNodeStruct struct {
StateCompute func(context.Context, abi.ChainEpoch, []*types.Message, types.TipSetKey) (*api.ComputeStateOutput, error) `perm:"read"` StateCompute func(context.Context, abi.ChainEpoch, []*types.Message, types.TipSetKey) (*api.ComputeStateOutput, error) `perm:"read"`
MsigGetAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"` MsigGetAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
MsigCreate func(context.Context, int64, []address.Address, abi.ChainEpoch, types.BigInt, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"` MsigCreate func(context.Context, int64, []address.Address, 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"` 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"` 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, 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"`
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"` MarketEnsureAvailable func(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"`
@@ -197,11 +188,10 @@ type StorageMinerStruct struct {
MiningBase func(context.Context) (*types.TipSet, error) `perm:"read"` MiningBase func(context.Context) (*types.TipSet, error) `perm:"read"`
MarketImportDealData func(context.Context, cid.Cid, string) error `perm:"write"` MarketImportDealData func(context.Context, cid.Cid, string) error `perm:"write"`
MarketListDeals func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"` MarketListDeals func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"`
MarketListIncompleteDeals func(ctx context.Context) ([]storagemarket.MinerDeal, 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"` MarketSetPrice func(context.Context, types.BigInt) error `perm:"admin"`
MarketGetAsk func(ctx context.Context) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
PledgeSector func(context.Context) error `perm:"write"` PledgeSector func(context.Context) error `perm:"write"`
@@ -209,36 +199,23 @@ type StorageMinerStruct struct {
SectorsList func(context.Context) ([]abi.SectorNumber, error) `perm:"read"` SectorsList func(context.Context) ([]abi.SectorNumber, error) `perm:"read"`
SectorsRefs func(context.Context) (map[string][]api.SealedRef, 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"` SectorsUpdate func(context.Context, abi.SectorNumber, api.SectorState) error `perm:"write"`
SectorRemove func(context.Context, abi.SectorNumber) error `perm:"admin"`
WorkerConnect func(context.Context, string) error `perm:"admin"` // TODO: worker perm WorkerConnect func(context.Context, string) error `perm:"admin"` // TODO: worker perm
WorkerStats func(context.Context) (map[uint64]storiface.WorkerStats, error) `perm:"admin"` WorkerStats func(context.Context) (map[uint64]storiface.WorkerStats, error) `perm:"admin"`
StorageList func(context.Context) (map[stores.ID][]stores.Decl, 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"` StorageLocal func(context.Context) (map[stores.ID]string, error) `perm:"admin"`
StorageStat func(context.Context, stores.ID) (stores.FsStat, 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"` 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"` 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"` 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"` 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"` 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"` 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"` 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"` DealsImportData func(ctx context.Context, dealPropCid cid.Cid, file string) error `perm:"write"`
DealsList func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"` 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"` StorageAddLocal func(ctx context.Context, path string) error `perm:"admin"`
} }
@@ -254,19 +231,16 @@ type WorkerStruct struct {
Paths func(context.Context) ([]stores.StoragePath, error) `perm:"admin"` Paths func(context.Context) ([]stores.StoragePath, error) `perm:"admin"`
Info func(context.Context) (storiface.WorkerInfo, 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"` 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"` 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"` 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"` SealCommit2 func(context.Context, abi.SectorID, storage.Commit1Out) (storage.Proof, error) `perm:"admin"`
FinalizeSector func(context.Context, abi.SectorID, []storage.Range) error `perm:"admin"` FinalizeSector func(context.Context, abi.SectorID) 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"` 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"` ReadPiece func(context.Context, io.Writer, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize) error `perm:"admin"`
Fetch func(context.Context, abi.SectorID, stores.SectorFileType, stores.PathType, stores.AcquireMode) error `perm:"admin"` Fetch func(context.Context, abi.SectorID, stores.SectorFileType, bool, stores.AcquireMode) error `perm:"admin"`
Closing func(context.Context) (<-chan struct{}, error) `perm:"admin"` Closing func(context.Context) (<-chan struct{}, error) `perm:"admin"`
} }
@@ -282,9 +256,6 @@ func (c *CommonStruct) AuthNew(ctx context.Context, perms []auth.Permission) ([]
return c.Internal.AuthNew(ctx, perms) return c.Internal.AuthNew(ctx, perms)
} }
func (c *CommonStruct) NetPubsubScores(ctx context.Context) ([]api.PubsubScore, error) {
return c.Internal.NetPubsubScores(ctx)
}
func (c *CommonStruct) NetConnectedness(ctx context.Context, pid peer.ID) (network.Connectedness, error) { func (c *CommonStruct) NetConnectedness(ctx context.Context, pid peer.ID) (network.Connectedness, error) {
return c.Internal.NetConnectedness(ctx, pid) return c.Internal.NetConnectedness(ctx, pid)
} }
@@ -327,14 +298,6 @@ func (c *CommonStruct) LogSetLevel(ctx context.Context, group, level string) err
return c.Internal.LogSetLevel(ctx, group, level) return c.Internal.LogSetLevel(ctx, group, level)
} }
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 // FullNodeStruct
func (c *FullNodeStruct) ClientListImports(ctx context.Context) ([]api.Import, error) { func (c *FullNodeStruct) ClientListImports(ctx context.Context) ([]api.Import, error) {
@@ -353,10 +316,6 @@ func (c *FullNodeStruct) ClientFindData(ctx context.Context, root cid.Cid) ([]ap
return c.Internal.ClientFindData(ctx, root) return c.Internal.ClientFindData(ctx, root)
} }
func (c *FullNodeStruct) ClientMinerQueryOffer(ctx context.Context, root cid.Cid, miner address.Address) (api.QueryOffer, error) {
return c.Internal.ClientMinerQueryOffer(ctx, root, miner)
}
func (c *FullNodeStruct) ClientStartDeal(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) { func (c *FullNodeStruct) ClientStartDeal(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) {
return c.Internal.ClientStartDeal(ctx, params) return c.Internal.ClientStartDeal(ctx, params)
} }
@@ -467,10 +426,6 @@ func (c *FullNodeStruct) WalletImport(ctx context.Context, ki *types.KeyInfo) (a
return c.Internal.WalletImport(ctx, ki) return c.Internal.WalletImport(ctx, ki)
} }
func (c *FullNodeStruct) WalletDelete(ctx context.Context, addr address.Address) error {
return c.Internal.WalletDelete(ctx, addr)
}
func (c *FullNodeStruct) MpoolGetNonce(ctx context.Context, addr address.Address) (uint64, error) { func (c *FullNodeStruct) MpoolGetNonce(ctx context.Context, addr address.Address) (uint64, error) {
return c.Internal.MpoolGetNonce(ctx, addr) return c.Internal.MpoolGetNonce(ctx, addr)
} }
@@ -579,7 +534,7 @@ func (c *FullNodeStruct) StateMinerPower(ctx context.Context, a address.Address,
return c.Internal.StateMinerPower(ctx, a, tsk) return c.Internal.StateMinerPower(ctx, a, tsk)
} }
func (c *FullNodeStruct) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (api.MinerInfo, error) { func (c *FullNodeStruct) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) {
return c.Internal.StateMinerInfo(ctx, actor, tsk) return c.Internal.StateMinerInfo(ctx, actor, tsk)
} }
@@ -627,16 +582,16 @@ func (c *FullNodeStruct) StateGetActor(ctx context.Context, actor address.Addres
return c.Internal.StateGetActor(ctx, actor, tsk) return c.Internal.StateGetActor(ctx, actor, tsk)
} }
func (c *FullNodeStruct) StateReadState(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*api.ActorState, error) { func (c *FullNodeStruct) StateReadState(ctx context.Context, act *types.Actor, tsk types.TipSetKey) (*api.ActorState, error) {
return c.Internal.StateReadState(ctx, addr, tsk) return c.Internal.StateReadState(ctx, act, tsk)
} }
func (c *FullNodeStruct) StatePledgeCollateral(ctx context.Context, tsk types.TipSetKey) (types.BigInt, error) { func (c *FullNodeStruct) StatePledgeCollateral(ctx context.Context, tsk types.TipSetKey) (types.BigInt, error) {
return c.Internal.StatePledgeCollateral(ctx, tsk) return c.Internal.StatePledgeCollateral(ctx, tsk)
} }
func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid, confidence uint64) (*api.MsgLookup, error) { func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid) (*api.MsgLookup, error) {
return c.Internal.StateWaitMsg(ctx, msgc, confidence) return c.Internal.StateWaitMsg(ctx, msgc)
} }
func (c *FullNodeStruct) StateSearchMsg(ctx context.Context, msgc cid.Cid) (*api.MsgLookup, error) { func (c *FullNodeStruct) StateSearchMsg(ctx context.Context, msgc cid.Cid) (*api.MsgLookup, error) {
@@ -695,8 +650,8 @@ func (c *FullNodeStruct) MsigGetAvailableBalance(ctx context.Context, a address.
return c.Internal.MsigGetAvailableBalance(ctx, a, tsk) return c.Internal.MsigGetAvailableBalance(ctx, a, tsk)
} }
func (c *FullNodeStruct) MsigCreate(ctx context.Context, req int64, addrs []address.Address, duration abi.ChainEpoch, val types.BigInt, src address.Address, gp types.BigInt) (cid.Cid, error) { 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, duration, val, src, gp) return c.Internal.MsigCreate(ctx, req, addrs, 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) { 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) {
@@ -707,20 +662,8 @@ func (c *FullNodeStruct) MsigApprove(ctx context.Context, msig address.Address,
return c.Internal.MsigApprove(ctx, msig, txID, proposer, to, amt, src, method, params) 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, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) { 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, to, amt, src, method, params) return c.Internal.MsigCancel(ctx, msig, txID, proposer, 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) { func (c *FullNodeStruct) MarketEnsureAvailable(ctx context.Context, addr, wallet address.Address, amt types.BigInt) (cid.Cid, error) {
@@ -811,10 +754,6 @@ func (c *StorageMinerStruct) SectorsUpdate(ctx context.Context, id abi.SectorNum
return c.Internal.SectorsUpdate(ctx, id, state) 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) WorkerConnect(ctx context.Context, url string) error { func (c *StorageMinerStruct) WorkerConnect(ctx context.Context, url string) error {
return c.Internal.WorkerConnect(ctx, url) return c.Internal.WorkerConnect(ctx, url)
} }
@@ -855,7 +794,7 @@ func (c *StorageMinerStruct) StorageInfo(ctx context.Context, id stores.ID) (sto
return c.Internal.StorageInfo(ctx, id) return c.Internal.StorageInfo(ctx, id)
} }
func (c *StorageMinerStruct) StorageBestAlloc(ctx context.Context, allocate stores.SectorFileType, spt abi.RegisteredSealProof, pt stores.PathType) ([]stores.StorageInfo, error) { func (c *StorageMinerStruct) StorageBestAlloc(ctx context.Context, allocate stores.SectorFileType, spt abi.RegisteredProof, pt stores.PathType) ([]stores.StorageInfo, error) {
return c.Internal.StorageBestAlloc(ctx, allocate, spt, pt) return c.Internal.StorageBestAlloc(ctx, allocate, spt, pt)
} }
@@ -863,14 +802,6 @@ func (c *StorageMinerStruct) StorageReportHealth(ctx context.Context, id stores.
return c.Internal.StorageReportHealth(ctx, id, report) return c.Internal.StorageReportHealth(ctx, id, report)
} }
func (c *StorageMinerStruct) StorageLock(ctx context.Context, sector abi.SectorID, read stores.SectorFileType, write stores.SectorFileType) error {
return c.Internal.StorageLock(ctx, sector, read, write)
}
func (c *StorageMinerStruct) StorageTryLock(ctx context.Context, sector abi.SectorID, read stores.SectorFileType, write stores.SectorFileType) (bool, error) {
return c.Internal.StorageTryLock(ctx, sector, read, write)
}
func (c *StorageMinerStruct) MarketImportDealData(ctx context.Context, propcid cid.Cid, path string) error { func (c *StorageMinerStruct) MarketImportDealData(ctx context.Context, propcid cid.Cid, path string) error {
return c.Internal.MarketImportDealData(ctx, propcid, path) return c.Internal.MarketImportDealData(ctx, propcid, path)
} }
@@ -883,12 +814,8 @@ func (c *StorageMinerStruct) MarketListIncompleteDeals(ctx context.Context) ([]s
return c.Internal.MarketListIncompleteDeals(ctx) return c.Internal.MarketListIncompleteDeals(ctx)
} }
func (c *StorageMinerStruct) MarketSetAsk(ctx context.Context, price types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error { func (c *StorageMinerStruct) MarketSetPrice(ctx context.Context, p types.BigInt) error {
return c.Internal.MarketSetAsk(ctx, price, duration, minPieceSize, maxPieceSize) return c.Internal.MarketSetPrice(ctx, p)
}
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 { func (c *StorageMinerStruct) DealsImportData(ctx context.Context, dealPropCid cid.Cid, file string) error {
@@ -899,46 +826,6 @@ func (c *StorageMinerStruct) DealsList(ctx context.Context) ([]storagemarket.Sto
return c.Internal.DealsList(ctx) 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 { func (c *StorageMinerStruct) StorageAddLocal(ctx context.Context, path string) error {
return c.Internal.StorageAddLocal(ctx, path) return c.Internal.StorageAddLocal(ctx, path)
} }
@@ -977,20 +864,8 @@ func (w *WorkerStruct) SealCommit2(ctx context.Context, sector abi.SectorID, c1o
return w.Internal.SealCommit2(ctx, sector, c1o) return w.Internal.SealCommit2(ctx, sector, c1o)
} }
func (w *WorkerStruct) FinalizeSector(ctx context.Context, sector abi.SectorID, keepUnsealed []storage.Range) error { func (w *WorkerStruct) FinalizeSector(ctx context.Context, sector abi.SectorID) error {
return w.Internal.FinalizeSector(ctx, sector, keepUnsealed) return w.Internal.FinalizeSector(ctx, sector)
}
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 {
return w.Internal.MoveStorage(ctx, sector)
} }
func (w *WorkerStruct) UnsealPiece(ctx context.Context, id abi.SectorID, index storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize, randomness abi.SealRandomness, c cid.Cid) error { func (w *WorkerStruct) UnsealPiece(ctx context.Context, id abi.SectorID, index storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize, randomness abi.SealRandomness, c cid.Cid) error {
@@ -1001,8 +876,8 @@ func (w *WorkerStruct) ReadPiece(ctx context.Context, writer io.Writer, id abi.S
return w.Internal.ReadPiece(ctx, writer, id, index, size) return w.Internal.ReadPiece(ctx, writer, id, index, size)
} }
func (w *WorkerStruct) Fetch(ctx context.Context, id abi.SectorID, fileType stores.SectorFileType, ptype stores.PathType, am stores.AcquireMode) error { func (w *WorkerStruct) Fetch(ctx context.Context, id abi.SectorID, fileType stores.SectorFileType, b bool, am stores.AcquireMode) error {
return w.Internal.Fetch(ctx, id, fileType, ptype, am) return w.Internal.Fetch(ctx, id, fileType, b, am)
} }
func (w *WorkerStruct) Closing(ctx context.Context) (<-chan struct{}, error) { func (w *WorkerStruct) Closing(ctx context.Context) (<-chan struct{}, error) {
+23 -63
View File
@@ -16,7 +16,6 @@ import (
"github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-bitfield"
"github.com/filecoin-project/go-jsonrpc/auth" "github.com/filecoin-project/go-jsonrpc/auth"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/apistruct"
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/filecoin-project/lotus/node/modules/dtypes"
@@ -73,14 +72,10 @@ func init() {
addExample(pid) addExample(pid)
addExample(bitfield.NewFromSet([]uint64{5})) addExample(bitfield.NewFromSet([]uint64{5}))
addExample(abi.RegisteredSealProof_StackedDrg32GiBV1) addExample(abi.RegisteredProof_StackedDRG32GiBPoSt)
addExample(abi.RegisteredPoStProof_StackedDrgWindow32GiBV1)
addExample(abi.ChainEpoch(10101)) addExample(abi.ChainEpoch(10101))
addExample(crypto.SigTypeBLS) addExample(crypto.SigTypeBLS)
addExample(int64(9)) addExample(int64(9))
addExample(12.3)
addExample(123)
addExample(uintptr(0))
addExample(abi.MethodNum(1)) addExample(abi.MethodNum(1))
addExample(exitcode.ExitCode(0)) addExample(exitcode.ExitCode(0))
addExample(crypto.DomainSeparationTag_ElectionProofProduction) addExample(crypto.DomainSeparationTag_ElectionProofProduction)
@@ -98,18 +93,18 @@ func init() {
addExample(build.APIVersion) addExample(build.APIVersion)
addExample(api.PCHInbound) addExample(api.PCHInbound)
addExample(time.Minute) addExample(time.Minute)
addExample(&types.ExecutionTrace{ addExample(&types.ExecutionResult{
Msg: exampleValue(reflect.TypeOf(&types.Message{}), nil).(*types.Message), Msg: exampleValue(reflect.TypeOf(&types.Message{})).(*types.Message),
MsgRct: exampleValue(reflect.TypeOf(&types.MessageReceipt{}), nil).(*types.MessageReceipt), MsgRct: exampleValue(reflect.TypeOf(&types.MessageReceipt{})).(*types.MessageReceipt),
}) })
addExample(map[string]types.Actor{ addExample(map[string]types.Actor{
"t01236": exampleValue(reflect.TypeOf(types.Actor{}), nil).(types.Actor), "t01236": exampleValue(reflect.TypeOf(types.Actor{})).(types.Actor),
}) })
addExample(map[string]api.MarketDeal{ addExample(map[string]api.MarketDeal{
"t026363": exampleValue(reflect.TypeOf(api.MarketDeal{}), nil).(api.MarketDeal), "t026363": exampleValue(reflect.TypeOf(api.MarketDeal{})).(api.MarketDeal),
}) })
addExample(map[string]api.MarketBalance{ addExample(map[string]api.MarketBalance{
"t026363": exampleValue(reflect.TypeOf(api.MarketBalance{}), nil).(api.MarketBalance), "t026363": exampleValue(reflect.TypeOf(api.MarketBalance{})).(api.MarketBalance),
}) })
maddr, err := multiaddr.NewMultiaddr("/ip4/52.36.61.156/tcp/1347/p2p/12D3KooWFETiESTf1v4PGUvtnxMAcEFMzLZbJGg4tjWfGEimYior") maddr, err := multiaddr.NewMultiaddr("/ip4/52.36.61.156/tcp/1347/p2p/12D3KooWFETiESTf1v4PGUvtnxMAcEFMzLZbJGg4tjWfGEimYior")
@@ -122,7 +117,7 @@ func init() {
} }
func exampleValue(t, parent reflect.Type) interface{} { func exampleValue(t reflect.Type) interface{} {
v, ok := ExampleValues[t] v, ok := ExampleValues[t]
if ok { if ok {
return v return v
@@ -131,25 +126,25 @@ func exampleValue(t, parent reflect.Type) interface{} {
switch t.Kind() { switch t.Kind() {
case reflect.Slice: case reflect.Slice:
out := reflect.New(t).Elem() out := reflect.New(t).Elem()
reflect.Append(out, reflect.ValueOf(exampleValue(t.Elem(), t))) reflect.Append(out, reflect.ValueOf(exampleValue(t.Elem())))
return out.Interface() return out.Interface()
case reflect.Chan: case reflect.Chan:
return exampleValue(t.Elem(), nil) return exampleValue(t.Elem())
case reflect.Struct: case reflect.Struct:
es := exampleStruct(t, parent) es := exampleStruct(t)
v := reflect.ValueOf(es).Elem().Interface() v := reflect.ValueOf(es).Elem().Interface()
ExampleValues[t] = v ExampleValues[t] = v
return v return v
case reflect.Array: case reflect.Array:
out := reflect.New(t).Elem() out := reflect.New(t).Elem()
for i := 0; i < t.Len(); i++ { for i := 0; i < t.Len(); i++ {
out.Index(i).Set(reflect.ValueOf(exampleValue(t.Elem(), t))) out.Index(i).Set(reflect.ValueOf(exampleValue(t.Elem())))
} }
return out.Interface() return out.Interface()
case reflect.Ptr: case reflect.Ptr:
if t.Elem().Kind() == reflect.Struct { if t.Elem().Kind() == reflect.Struct {
es := exampleStruct(t.Elem(), t) es := exampleStruct(t.Elem())
//ExampleValues[t] = es //ExampleValues[t] = es
return es return es
} }
@@ -160,15 +155,12 @@ func exampleValue(t, parent reflect.Type) interface{} {
panic(fmt.Sprintf("No example value for type: %s", t)) panic(fmt.Sprintf("No example value for type: %s", t))
} }
func exampleStruct(t, parent reflect.Type) interface{} { func exampleStruct(t reflect.Type) interface{} {
ns := reflect.New(t) ns := reflect.New(t)
for i := 0; i < t.NumField(); i++ { for i := 0; i < t.NumField(); i++ {
f := t.Field(i) f := t.Field(i)
if f.Type == parent {
continue
}
if strings.Title(f.Name) == f.Name { if strings.Title(f.Name) == f.Name {
ns.Elem().Field(i).Set(reflect.ValueOf(exampleValue(f.Type, t))) ns.Elem().Field(i).Set(reflect.ValueOf(exampleValue(f.Type)))
} }
} }
@@ -201,7 +193,8 @@ func (v *Visitor) Visit(node ast.Node) ast.Visitor {
const noComment = "There are not yet any comments for this method." const noComment = "There are not yet any comments for this method."
func parseApiASTInfo() (map[string]string, map[string]string) { //nolint:golint func parseApiASTInfo() (map[string]string, map[string]string) {
fset := token.NewFileSet() fset := token.NewFileSet()
pkgs, err := parser.ParseDir(fset, "./api", nil, parser.AllErrors|parser.ParseComments) pkgs, err := parser.ParseDir(fset, "./api", nil, parser.AllErrors|parser.ParseComments)
if err != nil { if err != nil {
@@ -294,17 +287,17 @@ func main() {
ft := m.Func.Type() ft := m.Func.Type()
for j := 2; j < ft.NumIn(); j++ { for j := 2; j < ft.NumIn(); j++ {
inp := ft.In(j) inp := ft.In(j)
args = append(args, exampleValue(inp, nil)) args = append(args, exampleValue(inp))
} }
v, err := json.MarshalIndent(args, "", " ") v, err := json.Marshal(args)
if err != nil { if err != nil {
panic(err) panic(err)
} }
outv := exampleValue(ft.Out(0), nil) outv := exampleValue(ft.Out(0))
ov, err := json.MarshalIndent(outv, "", " ") ov, err := json.Marshal(outv)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -326,18 +319,6 @@ func main() {
return groupslice[i].GroupName < groupslice[j].GroupName 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 { for _, g := range groupslice {
g := g g := g
fmt.Printf("## %s\n", g.GroupName) fmt.Printf("## %s\n", g.GroupName)
@@ -351,29 +332,8 @@ func main() {
fmt.Printf("### %s\n", m.Name) fmt.Printf("### %s\n", m.Name)
fmt.Printf("%s\n\n", m.Comment) fmt.Printf("%s\n\n", m.Comment)
meth, ok := permStruct.FieldByName(m.Name) fmt.Printf("Inputs: `%s`\n\n", m.InputExample)
if !ok { fmt.Printf("Response: `%s`\n\n", m.ResponseExample)
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)
}
} }
} }
} }
+10 -11
View File
@@ -8,7 +8,6 @@ import (
"math/rand" "math/rand"
"os" "os"
"path/filepath" "path/filepath"
"sync/atomic"
"testing" "testing"
"time" "time"
@@ -36,7 +35,7 @@ func init() {
} }
func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport bool) { func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport bool) {
_ = os.Setenv("BELLMAN_NO_GPU", "1") os.Setenv("BELLMAN_NO_GPU", "1")
ctx := context.Background() ctx := context.Background()
n, sn := b(t, 1, oneMiner) n, sn := b(t, 1, oneMiner)
@@ -53,13 +52,13 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport
} }
time.Sleep(time.Second) time.Sleep(time.Second)
mine := int64(1) mine := true
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
defer close(done) defer close(done)
for atomic.LoadInt64(&mine) == 1 { for mine {
time.Sleep(blocktime) time.Sleep(blocktime)
if err := sn[0].MineOne(ctx, func(bool, error) {}); err != nil { if err := sn[0].MineOne(ctx, func(bool) {}); err != nil {
t.Error(err) t.Error(err)
} }
} }
@@ -67,13 +66,13 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport
makeDeal(t, ctx, 6, client, miner, carExport) makeDeal(t, ctx, 6, client, miner, carExport)
atomic.AddInt64(&mine, -1) mine = false
fmt.Println("shutting down mining") fmt.Println("shutting down mining")
<-done <-done
} }
func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) { func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
_ = os.Setenv("BELLMAN_NO_GPU", "1") os.Setenv("BELLMAN_NO_GPU", "1")
ctx := context.Background() ctx := context.Background()
n, sn := b(t, 1, oneMiner) n, sn := b(t, 1, oneMiner)
@@ -90,14 +89,14 @@ func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
} }
time.Sleep(time.Second) time.Sleep(time.Second)
mine := int64(1) mine := true
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
defer close(done) defer close(done)
for atomic.LoadInt64(&mine) == 1 { for mine {
time.Sleep(blocktime) time.Sleep(blocktime)
if err := sn[0].MineOne(ctx, func(bool, error) {}); err != nil { if err := sn[0].MineOne(ctx, func(bool) {}); err != nil {
t.Error(err) t.Error(err)
} }
} }
@@ -106,7 +105,7 @@ func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
makeDeal(t, ctx, 6, client, miner, false) makeDeal(t, ctx, 6, client, miner, false)
makeDeal(t, ctx, 7, client, miner, false) makeDeal(t, ctx, 7, client, miner, false)
atomic.AddInt64(&mine, -1) mine = false
fmt.Println("shutting down mining") fmt.Println("shutting down mining")
<-done <-done
} }
+7 -8
View File
@@ -34,7 +34,7 @@ func (ts *testSuite) testMining(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
<-newHeads <-newHeads
err = sn[0].MineOne(ctx, func(bool, error) {}) err = sn[0].MineOne(ctx, func(bool) {})
require.NoError(t, err) require.NoError(t, err)
<-newHeads <-newHeads
@@ -62,7 +62,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
<-newHeads <-newHeads
err = sn[0].MineOne(ctx, func(bool, error) {}) err = sn[0].MineOne(ctx, func(bool) {})
require.NoError(t, err) require.NoError(t, err)
<-newHeads <-newHeads
@@ -71,7 +71,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, abi.ChainEpoch(1), h2.Height()) require.Equal(t, abi.ChainEpoch(1), h2.Height())
err = sn[0].MineOne(ctx, func(bool, error) {}) err = sn[0].MineOne(ctx, func(bool) {})
require.NoError(t, err) require.NoError(t, err)
<-newHeads <-newHeads
@@ -82,7 +82,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
} }
func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExport bool) { func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExport bool) {
_ = os.Setenv("BELLMAN_NO_GPU", "1") os.Setenv("BELLMAN_NO_GPU", "1")
// test making a deal with a fresh miner, and see if it starts to mine // test making a deal with a fresh miner, and see if it starts to mine
@@ -126,13 +126,12 @@ func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExpo
minedTwo := make(chan struct{}) minedTwo := make(chan struct{})
go func() { go func() {
doneMinedTwo := false
defer close(done) defer close(done)
prevExpect := 0 prevExpect := 0
for atomic.LoadInt32(&mine) != 0 { for atomic.LoadInt32(&mine) != 0 {
wait := make(chan int, 2) wait := make(chan int, 2)
mdone := func(mined bool, err error) { mdone := func(mined bool) {
go func() { go func() {
n := 0 n := 0
if mined { if mined {
@@ -176,9 +175,9 @@ func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExpo
time.Sleep(blocktime) time.Sleep(blocktime)
} }
if prevExpect == 2 && expect == 2 && !doneMinedTwo { if prevExpect == 2 && expect == 2 && minedTwo != nil {
close(minedTwo) close(minedTwo)
doneMinedTwo = true minedTwo = nil
} }
prevExpect = expect prevExpect = expect
+1 -1
View File
@@ -18,7 +18,7 @@ type TestNode struct {
type TestStorageNode struct { type TestStorageNode struct {
api.StorageMiner api.StorageMiner
MineOne func(context.Context, func(bool, error)) error MineOne func(context.Context, func(bool)) error
} }
var PresealGenesis = -1 var PresealGenesis = -1
+2 -2
View File
@@ -43,7 +43,7 @@ func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSect
defer close(done) defer close(done)
for mine { for mine {
time.Sleep(blocktime) time.Sleep(blocktime)
if err := sn[0].MineOne(ctx, func(bool, error) {}); err != nil { if err := sn[0].MineOne(ctx, func(bool) {}); err != nil {
t.Error(err) t.Error(err)
} }
} }
@@ -123,7 +123,7 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
defer close(done) defer close(done)
for mine { for mine {
time.Sleep(blocktime) time.Sleep(blocktime)
if err := sn[0].MineOne(ctx, func(bool, error) {}); err != nil { if err := sn[0].MineOne(ctx, func(bool) {}); err != nil {
t.Error(err) t.Error(err)
} }
} }
-42
View File
@@ -2,11 +2,7 @@ package api
import ( import (
"encoding/json" "encoding/json"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/libp2p/go-libp2p-core/peer"
ma "github.com/multiformats/go-multiaddr" ma "github.com/multiformats/go-multiaddr"
) )
@@ -37,41 +33,3 @@ type ObjStat struct {
Size uint64 Size uint64
Links uint64 Links uint64
} }
type PubsubScore struct {
ID peer.ID
Score float64
}
type MinerInfo struct {
Owner address.Address // Must be an ID-address.
Worker address.Address // Must be an ID-address.
NewWorker address.Address // Must be an ID-address.
WorkerChangeEpoch abi.ChainEpoch
PeerId peer.ID
Multiaddrs []abi.Multiaddrs
SealProofType abi.RegisteredSealProof
SectorSize abi.SectorSize
WindowPoStPartitionSectors uint64
}
func NewApiMinerInfo(info miner.MinerInfo) MinerInfo {
mi := MinerInfo{
Owner: info.Owner,
Worker: info.Worker,
NewWorker: address.Undef,
WorkerChangeEpoch: -1,
PeerId: peer.ID(info.PeerId),
Multiaddrs: info.Multiaddrs,
SealProofType: info.SealProofType,
SectorSize: info.SectorSize,
WindowPoStPartitionSectors: info.WindowPoStPartitionSectors,
}
if info.PendingWorkerKey != nil {
mi.NewWorker = info.PendingWorkerKey.NewWorker
mi.WorkerChangeEpoch = info.PendingWorkerKey.EffectiveAt
}
return mi
}
-13
View File
@@ -13,10 +13,6 @@ import (
) )
func BuiltinBootstrap() ([]peer.AddrInfo, error) { func BuiltinBootstrap() ([]peer.AddrInfo, error) {
if DisableBuiltinAssets {
return nil, nil
}
var out []peer.AddrInfo var out []peer.AddrInfo
b := rice.MustFindBox("bootstrap") b := rice.MustFindBox("bootstrap")
@@ -38,12 +34,3 @@ func BuiltinBootstrap() ([]peer.AddrInfo, error) {
}) })
return out, err return out, err
} }
func DrandBootstrap() ([]peer.AddrInfo, error) {
addrs := []string{
"/dnsaddr/pl-eu.testnet.drand.sh/",
"/dnsaddr/pl-us.testnet.drand.sh/",
"/dnsaddr/pl-sin.testnet.drand.sh/",
}
return addrutil.ParseAddresses(context.TODO(), addrs)
}
+6 -12
View File
@@ -1,12 +1,6 @@
/dns4/bootstrap-0-sin.fil-test.net/tcp/1347/p2p/12D3KooWPdUquftaQvoQEtEdsRBAhwD6jopbF2oweVTzR59VbHEd /dns4/t01000.miner.interopnet.kittyhawk.wtf/tcp/1347/p2p/12D3KooWNMVRk3KkMANV67A4zPxB83FtvLouwsYGitEofY1ympJs
/ip4/86.109.15.57/tcp/1347/p2p/12D3KooWPdUquftaQvoQEtEdsRBAhwD6jopbF2oweVTzR59VbHEd /ip4/34.217.110.132/tcp/1347/p2p/12D3KooWNMVRk3KkMANV67A4zPxB83FtvLouwsYGitEofY1ympJs
/dns4/bootstrap-0-dfw.fil-test.net/tcp/1347/p2p/12D3KooWQSCkHCzosEyrh8FgYfLejKgEPM5VB6qWzZE3yDAuXn8d /dns4/peer0.interopnet.kittyhawk.wtf/tcp/1347/p2p/12D3KooWM1ufVLkBAyyf8Jn5DMdmW5gA7upSvCUatoneHp6yUEtd
/ip4/139.178.84.45/tcp/1347/p2p/12D3KooWQSCkHCzosEyrh8FgYfLejKgEPM5VB6qWzZE3yDAuXn8d /ip4/54.187.182.170/tcp/1347/p2p/12D3KooWM1ufVLkBAyyf8Jn5DMdmW5gA7upSvCUatoneHp6yUEtd
/dns4/bootstrap-0-fra.fil-test.net/tcp/1347/p2p/12D3KooWEXN2eQmoyqnNjde9PBAQfQLHN67jcEdWU6JougWrgXJK /dns4/peer1.interopnet.kittyhawk.wtf/tcp/1347/p2p/12D3KooWLxMPSbs7XEPhyUiSo6RpTTRAkRiD1bp6uKYxyZx4QSZR
/ip4/136.144.49.17/tcp/1347/p2p/12D3KooWEXN2eQmoyqnNjde9PBAQfQLHN67jcEdWU6JougWrgXJK /ip4/52.24.84.39/tcp/1347/p2p/12D3KooWLxMPSbs7XEPhyUiSo6RpTTRAkRiD1bp6uKYxyZx4QSZR
/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
-15
View File
@@ -1,15 +0,0 @@
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.
+5 -4
View File
@@ -12,17 +12,18 @@ import (
func init() { func init() {
power.ConsensusMinerMinPower = big.NewInt(2048) power.ConsensusMinerMinPower = big.NewInt(2048)
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
abi.RegisteredSealProof_StackedDrg2KiBV1: {}, abi.RegisteredProof_StackedDRG2KiBSeal: {},
} }
verifreg.MinVerifiedDealSize = big.NewInt(256) verifreg.MinVerifiedDealSize = big.NewInt(256)
BuildType |= Build2k BuildType |= Build2k
} }
const BlockDelaySecs = uint64(2) // Seconds
const BlockDelay = 2
const PropagationDelaySecs = uint64(3) const PropagationDelay = 3
// SlashablePowerDelay is the number of epochs after ElectionPeriodStart, after // SlashablePowerDelay is the number of epochs after ElectionPeriodStart, after
// which the miner is slashed // which the miner is slashed
@@ -1,9 +1,10 @@
// +build !testground
package build package build
import ( import (
"math/big" "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/abi"
"github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin"
@@ -12,6 +13,32 @@ import (
"github.com/filecoin-project/lotus/node/modules/dtypes" "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 // Storage
@@ -21,7 +48,8 @@ const UnixfsLinksPerLevel = 1024
// ///// // /////
// Consensus / Network // Consensus / Network
const AllowableClockDriftSecs = uint64(1) // Seconds
const AllowableClockDrift = 1
// Epochs // Epochs
const ForkLengthThreshold = Finality const ForkLengthThreshold = Finality
@@ -31,12 +59,11 @@ var BlocksPerEpoch = uint64(builtin.ExpectedLeadersPerEpoch)
// Epochs // Epochs
const Finality = miner.ChainFinalityish const Finality = miner.ChainFinalityish
const MessageConfidence = uint64(5)
// constants for Weight calculation // constants for Weight calculation
// The ratio of weight contributed by short-term vs long-term factors in a given round // The ratio of weight contributed by short-term vs long-term factors in a given round
const WRatioNum = int64(1) const WRatioNum = int64(1)
const WRatioDen = uint64(2) const WRatioDen = 2
// ///// // /////
// Proofs // Proofs
@@ -54,25 +81,25 @@ const MaxSealLookback = SealRandomnessLookbackLimit + 2000 // TODO: Get from spe
// Mining // Mining
// Epochs // Epochs
const TicketRandomnessLookback = abi.ChainEpoch(1) const TicketRandomnessLookback = 1
const WinningPoStSectorSetLookback = abi.ChainEpoch(10) const WinningPoStSectorSetLookback = 10
// ///// // /////
// Devnet settings // Devnet settings
const TotalFilecoin = uint64(2_000_000_000) const TotalFilecoin = 2_000_000_000
const MiningRewardTotal = uint64(1_400_000_000) const MiningRewardTotal = 1_400_000_000
const FilecoinPrecision = uint64(1_000_000_000_000_000_000) const FilecoinPrecision = 1_000_000_000_000_000_000
var InitialRewardBalance *big.Int var InitialRewardBalance *big.Int
// TODO: Move other important consts here // TODO: Move other important consts here
func init() { func init() {
InitialRewardBalance = big.NewInt(int64(MiningRewardTotal)) InitialRewardBalance = big.NewInt(MiningRewardTotal)
InitialRewardBalance = InitialRewardBalance.Mul(InitialRewardBalance, big.NewInt(int64(FilecoinPrecision))) InitialRewardBalance = InitialRewardBalance.Mul(InitialRewardBalance, big.NewInt(FilecoinPrecision))
} }
// Sync // Sync
@@ -93,11 +120,4 @@ const VerifSigCacheSize = 32000
const BlockMessageLimit = 512 const BlockMessageLimit = 512
const BlockGasLimit = 100_000_000_000 const BlockGasLimit = 100_000_000_000
var DrandConfig = dtypes.DrandConfig{ var DrandChain = `{"public_key":"922a2e93828ff83345bae533f5172669a26c02dc76d6bf59c80892e12ab1455c229211886f35bb56af6d5bea981024df","period":25,"genesis_time":1590445175,"hash":"138a324aa6540f93d0dad002aa89454b1bec2b6e948682cde6bd4db40f4b7c9b"}`
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"}`,
}
-38
View File
@@ -1,38 +0,0 @@
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))
}
-73
View File
@@ -1,73 +0,0 @@
// +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.ChainFinalityish
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"}`,
}
)
+8 -7
View File
@@ -1,6 +1,5 @@
// +build !debug // +build !debug
// +build !2k // +build !2k
// +build !testground
package build package build
@@ -13,13 +12,15 @@ import (
) )
func init() { func init() {
power.ConsensusMinerMinPower = big.NewInt(1024 << 30) power.ConsensusMinerMinPower = big.NewInt(1024 << 20)
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
abi.RegisteredSealProof_StackedDrg32GiBV1: {}, abi.RegisteredProof_StackedDRG512MiBSeal: {},
abi.RegisteredSealProof_StackedDrg64GiBV1: {}, abi.RegisteredProof_StackedDRG32GiBSeal: {},
abi.RegisteredProof_StackedDRG64GiBSeal: {},
} }
} }
const BlockDelaySecs = uint64(builtin.EpochDurationSeconds) // Seconds
const BlockDelay = builtin.EpochDurationSeconds
const PropagationDelaySecs = uint64(6) const PropagationDelay = 6
+90 -90
View File
@@ -1,152 +1,152 @@
{ {
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0170db1f394b35d995252228ee359194b13199d259380541dc529fb0099096b0.params": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0170db1f394b35d995252228ee359194b13199d259380541dc529fb0099096b0.params": {
"cid": "QmeDRyxek34F1H6xJY6AkFdWvPsy5F6dKTrebV3ZtWT4ky", "cid": "QmYkygifkXnrnsN4MJsjBFHTQJHx294CyikDgDK8nYxdGh",
"digest": "f5827f2d8801c62c831e0f972f6dc8bb", "digest": "df3f30442a6d6b4192f5071fb17e820c",
"sector_size": 2048 "sector_size": 2048
}, },
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0170db1f394b35d995252228ee359194b13199d259380541dc529fb0099096b0.vk": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0170db1f394b35d995252228ee359194b13199d259380541dc529fb0099096b0.vk": {
"cid": "QmUw1ZmG4BBbX19MsbH3zAEGKUc42iFJc5ZAyomDHeJTsA", "cid": "QmdXyqbmy2bkJA9Kyhh6z25GrTCq48LwX6c1mxPsm54wi7",
"digest": "398fecdb4b2de445125852bc3c080b35", "digest": "0bea3951abf9557a3569f68e52a30c6c",
"sector_size": 2048 "sector_size": 2048
}, },
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.params": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.params": {
"cid": "QmUeNKp9YZpiAFm81RV5KuxH1FDGJx2DuwcbU2XNSZLLSv", "cid": "Qmf5XZZtP5VcYTf65MbKjLVabcS6cYMbr2rFShmfJzh5e5",
"digest": "2b6d2972ac9e862e8134d98fb695b0c5", "digest": "655e6277638edc8c658094f6f0b33d54",
"sector_size": 536870912 "sector_size": 536870912
}, },
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.vk": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.vk": {
"cid": "QmQaQmTXX995Akd66ggtJY5bNx6Gkxk8P34JTdMMq8393G", "cid": "QmPuhdWnAXBks43emnkqi9FQzyU1gASKyz23zrD27BPGs8",
"digest": "3688c9eb256b7b17f411dad78d5ef74a", "digest": "57690e3a6a94c3f704802a674b34f36b",
"sector_size": 536870912 "sector_size": 536870912
}, },
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.params": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.params": {
"cid": "QmfEYTMSkwGJTumQx26iKXGNKiYh3mmAC4SkdybZpJCj5p", "cid": "QmPNVgTN7N5vDtD5u7ERMTLcvUtrKRBfYVUDr6uW3pKhX7",
"digest": "09bff16aed893349d94485cfae366a9c", "digest": "3d390654f58e603b896ac70c653f5676",
"sector_size": 2048 "sector_size": 2048
}, },
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.vk": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.vk": {
"cid": "QmP4ThPieSUJyRanjibWpT5R5cCMzMAU4j8Y7kBn7CSW1Q", "cid": "Qmbj61Zez7v5xA7nSCnmWbyLYznWJDWeusz7Yg8EcgVdoN",
"digest": "142f2f7e8f1b1779290315cabfd2c803", "digest": "8c170a164743c39576a7f47a1b51e6f3",
"sector_size": 2048 "sector_size": 2048
}, },
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.params": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.params": {
"cid": "QmcAixrHsz29DgvtZiMc2kQjvPRvWxYUp36QYmRDZbmREm", "cid": "QmRApb8RZoBK3cqicT7V3ydXg8yVvqPFMPrQNXP33aBihp",
"digest": "8f987f64d434365562180b96ec12e299", "digest": "b1b58ff9a297b82885e8a7dfb035f83c",
"sector_size": 8388608 "sector_size": 8388608
}, },
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.vk": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.vk": {
"cid": "QmT4iFnbL6r4txS5PXsiV7NTzbhCxHy54PvdkJJGV2VFXb", "cid": "QmcytF1dTdqMFoyXi931j1RgmGtLfR9LLLaBznRt1tPQyD",
"digest": "94b6c24ac01924f4feeecedd16b5d77d", "digest": "1a09e00c641f192f55af3433a028f050",
"sector_size": 8388608 "sector_size": 8388608
}, },
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.params": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.params": {
"cid": "QmbjFst6SFCK1KsTQrfwPdxf3VTNa1raed574tEZZ9PoyQ", "cid": "QmPvr54tWaVeP4WnekivzUAJitTqsQfvikBvAHNEaDNQSw",
"digest": "2c245fe8179839dd6c6cdea207c67ae8", "digest": "9380e41368ed4083dbc922b290d3b786",
"sector_size": 8388608 "sector_size": 8388608
}, },
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.vk": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.vk": {
"cid": "QmQJKmvZN1a5cQ1Nw6CDyXs3nuRPzvyU5NvCFMUL2BfcZC", "cid": "QmXyVLVDRCcxA9SjT7PeK8HFtyxZ2ZH3SHa8KoGLw8VGJt",
"digest": "56ae47bfda53bb8d22981ed8d8d27d72", "digest": "f0731a7e20f90704bd38fc5d27882f6d",
"sector_size": 8388608 "sector_size": 8388608
}, },
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.params": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.params": {
"cid": "QmQCABxeTpdvXTyjDyk7nPBxkQzCh7MXfGztWnSXEPKMLW", "cid": "Qmf5f6ko3dqj7qauzXpZqxM9B2x2sL977K6gE2ppNwuJPv",
"digest": "7e6b2eb5ecbb11ac651ad66ebbb2075a", "digest": "273ebb8c896326b7c292bee8b775fd38",
"sector_size": 536870912 "sector_size": 536870912
}, },
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.vk": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.vk": {
"cid": "QmPBweyugh5Sx4umk8ULhgEGbjY8xmWLfU6M7EMpc8Mad6", "cid": "QmfP3MQe8koW63n5MkDENENVHxib78MJYYyZvbneCsuze8",
"digest": "94a8d9e25a9ab9674d339833664eba25", "digest": "3dd94da9da64e51b3445bc528d84e76d",
"sector_size": 536870912 "sector_size": 536870912
}, },
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.params": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.params": {
"cid": "QmY5yax1E9KymBnCeHksE9Zi8NieZbmwcpoDGoabkeeb9h", "cid": "QmYEeeCE8uT2bsVkxcqqUYeMmMEbe6rfmo8wQCv7jFHqqm",
"digest": "c909ea9e3fe25ab9b391a64593afdbba", "digest": "c947f2021304ed43b7216f7a8436e294",
"sector_size": 34359738368 "sector_size": 34359738368
}, },
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.vk": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.vk": {
"cid": "QmXnPo4yH5mwMguwrvqgRfduSttbmPrXtbBfbwU21wQWHt", "cid": "QmXB63ExriFjB4ywWnXTnFwCcLFfCeEP3h15qtL5i7F4aX",
"digest": "caf900461e988bbf86dbcaca087b7864", "digest": "ab20d7b253e7e9a0d2ccdf7599ec8ec3",
"sector_size": 34359738368 "sector_size": 34359738368
}, },
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.params": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.params": {
"cid": "QmZtzzPWwmZEgR7MSMvXRbt9KVK8k4XZ5RLWHybHJW9SdE", "cid": "QmW5Yxg3L1NSzuQVcRMHMbG3uvVoi4dTLzVaDpnEUPQpnA",
"digest": "a2844f0703f186d143a06146a04577d8", "digest": "079ba19645828ae42b22b0e3f4866e8d",
"sector_size": 34359738368 "sector_size": 34359738368
}, },
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.vk": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.vk": {
"cid": "QmWxEA7EdQCUJTzjNpxg5XTF45D2uVyYnN1QRUb5TRYU8M", "cid": "QmQzZ5dJ11tcSBees38WX41tZLXS9BqpEti253m5QcnTNs",
"digest": "2306247a1e616dbe07f01b88196c2044", "digest": "c76125a50a7de315165de359b5174ae4",
"sector_size": 34359738368 "sector_size": 34359738368
}, },
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.params": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.params": {
"cid": "QmP676KwuvyF9Y64uJnXvLtvD1xcuWQ6wD23RzYtQ6dd4f", "cid": "QmNk3wga1tS53FUu1QnkK8ehWA2cqpCnSEAPv3KLxdJxNa",
"digest": "215b1c667a4f46a1d0178338df568615", "digest": "421e4790c0b80e0107a7ff67acf14084",
"sector_size": 68719476736 "sector_size": 68719476736
}, },
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.vk": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.vk": {
"cid": "QmPvPwbJtcSGyqB1rQJhSF5yvFbX9ZBSsHVej5F8JUyHUJ", "cid": "QmVQCHGsrUtbn9RjHs1e6GXfeXDW5m9w4ge48PSX3Z2as2",
"digest": "0c9c423b28b1455fcbc329a1045fd4dd", "digest": "8b60e9cc1470a6729c687d6cf0a1f79c",
"sector_size": 68719476736 "sector_size": 68719476736
}, },
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.params": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.params": {
"cid": "QmUxPQfvckzm1t6MFRdDZ1fDK5UJzAjK7pTZ97cwyachdr", "cid": "QmTL3VvydaMFWKvE5VzxjgKsJYgL9JMM4JVYNtQxdj9JK1",
"digest": "965132f51ae445b0e6d32692b7561995", "digest": "2685f31124b22ea6b2857e5a5e87ffa3",
"sector_size": 68719476736 "sector_size": 68719476736
}, },
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.vk": { "v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.vk": {
"cid": "QmTxq2EBnQWb5R8tS4MHdchj4vNfLYGoSXxwJFvs5xgW4K", "cid": "QmSVWbLqQYbUbbJyfsRMzEib2rfSqMtnPks1Nw22omcBQm",
"digest": "fc8c3d26e0e56373ad96cb41520d55a6", "digest": "efe703cd2839597c7ca5c2a906b74296",
"sector_size": 68719476736 "sector_size": 68719476736
}, },
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.params": { "v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.params": {
"cid": "QmRjgZHERgqGoRagR788Kh6ybi26csVYa8mqbqhmZm57Jx", "cid": "QmU9dH31nZZUJnsogR4Ld4ySUcH6wm2RgmGiujwnqtbU6k",
"digest": "cfc7b0897d1eee48c586f7beb89e67f7", "digest": "fcef8e87ae2afd7a28aae44347b804cf",
"sector_size": 2048 "sector_size": 2048
}, },
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.vk": { "v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.vk": {
"cid": "QmNjvnvFP7KgovHUddULoB19fBHT81iz7NcUbzEHZUUPsm", "cid": "QmdJ15DMGPooye5NaPcRfXUdHUDibcN7hKjbmTGuu1K4AQ",
"digest": "fb59bd061c987eac7068008c44de346b", "digest": "2ee2b3518229680db15161d4f582af37",
"sector_size": 2048 "sector_size": 2048
}, },
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.params": { "v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.params": {
"cid": "QmTpRPBA4dt8fgGpcVzi4L1KA1U2eBHCE8WVmS2GUygMvT", "cid": "QmZgtxcY3tMXXQxZTA7ZTUDXLVUnfxNcerXgeW4gG2NnfP",
"digest": "36d465915b0afbf96bd08e7915e00952", "digest": "3273c7135cb75684248b475781b738ee",
"sector_size": 536870912 "sector_size": 536870912
}, },
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.vk": { "v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.vk": {
"cid": "QmRzDyVfQCLsxspoVsed5bcQRsG6KiktngJfcNBL3TJPZe", "cid": "QmSS6ZkAV2aGZcgKgdPpEEgihXF1ryZX8PSAZDWSoeL1d4",
"digest": "99d16df0eb6a7e227a4f4570c4f6b6f1", "digest": "1519b5f61d9044a59f2bdc57537c094b",
"sector_size": 536870912 "sector_size": 536870912
}, },
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.params": { "v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.params": {
"cid": "QmV8ZjTSGzDUWmFvsq9NSyPBR7eDDUcvCPNgj2yE7HMAFu", "cid": "QmQBGXeiNn6hVwbR6qFarQqiNGDdKk4h9ucfyvcXyfYz2N",
"digest": "34f3ddf1d1c9f41c0cd73b91e8b4bc27", "digest": "7d5f896f435c38e93bcda6dd168d860b",
"sector_size": 8388608 "sector_size": 8388608
}, },
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.vk": { "v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.vk": {
"cid": "QmTa3VbjTiqJWU6r4WKayaQrUaaBsrpp5UDqYvPDd2C5hs", "cid": "QmPrZgBVGMckEAeu5eSJnLmiAwcPQjKjZe5ir6VaQ5AxKs",
"digest": "ec62d59651daa5631d3d1e9c782dd940", "digest": "fe6d2de44580a0db5a4934688899b92f",
"sector_size": 8388608 "sector_size": 8388608
}, },
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.params": { "v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.params": {
"cid": "Qmf8ngfArxrv9tFWDqBcNegdBMymvuakwyHKd1pbW3pbsb", "cid": "QmZL2cq45XJn5BFzagAZwgFmLrcM1W6CXoiEF9C5j5tjEF",
"digest": "a16d6f4c6424fb280236739f84b24f97", "digest": "acdfed9f0512bc85a01a9fb871d475d5",
"sector_size": 34359738368 "sector_size": 34359738368
}, },
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.vk": { "v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.vk": {
"cid": "QmfQgVFerArJ6Jupwyc9tKjLD9n1J9ajLHBdpY465tRM7M", "cid": "QmQ4zB7nNa1tDYNifBkExRnZtwtxZw775iaqvVsZyRi6Q2",
"digest": "7a139d82b8a02e35279d657e197f5c1f", "digest": "524a2f3e9d6826593caebc41bb545c40",
"sector_size": 34359738368 "sector_size": 34359738368
}, },
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.params": { "v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.params": {
"cid": "QmfDha8271nXJn14Aq3qQeghjMBWbs6HNSGa6VuzCVk4TW", "cid": "QmY7DitNKXFeLQt9QoVQkfjM1EvRnprqUVxjmkTXkHDNka",
"digest": "5d3cd3f107a3bea8a96d1189efd2965c", "digest": "f27271c0537ba65ade2ec045f8fbd069",
"sector_size": 68719476736 "sector_size": 68719476736
}, },
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.vk": { "v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.vk": {
"cid": "QmRVtTtiFzHJTHurYzaCvetGAchux9cktixT4aGHthN6Zt", "cid": "QmUJsvoCuQ4LszPmeRVAkMYb5qY95ctz3UXKhu8xLzyFKo",
"digest": "62c366405404e60f171e661492740b1c", "digest": "576b292938c6c9d0a0e721bd867a543b",
"sector_size": 68719476736 "sector_size": 68719476736
} }
} }
+3 -3
View File
@@ -25,7 +25,7 @@ func buildType() string {
} }
// BuildVersion is the local build version, set by build system // BuildVersion is the local build version, set by build system
const BuildVersion = "0.4.1" const BuildVersion = "0.4.0"
func UserVersion() string { func UserVersion() string {
return BuildVersion + buildType() + CurrentCommit return BuildVersion + buildType() + CurrentCommit
@@ -53,9 +53,9 @@ func (ve Version) EqMajorMinor(v2 Version) bool {
} }
// APIVersion is a semver version of the rpc api exposed // APIVersion is a semver version of the rpc api exposed
var APIVersion Version = newVer(0, 6, 0) var APIVersion Version = newVer(0, 3, 0)
//nolint:varcheck,deadcode //nolint:varcheck
const ( const (
majorMask = 0xff0000 majorMask = 0xff0000
minorMask = 0xffff00 minorMask = 0xffff00
+5 -36
View File
@@ -1,8 +1,6 @@
package chain package chain
import ( import (
"fmt"
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
lru "github.com/hashicorp/golang-lru" lru "github.com/hashicorp/golang-lru"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
@@ -12,35 +10,6 @@ type BadBlockCache struct {
badBlocks *lru.ARCCache 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 { func NewBadBlockCache() *BadBlockCache {
cache, err := lru.NewARC(build.BadBlockCacheSize) cache, err := lru.NewARC(build.BadBlockCacheSize)
if err != nil { if err != nil {
@@ -52,15 +21,15 @@ func NewBadBlockCache() *BadBlockCache {
} }
} }
func (bts *BadBlockCache) Add(c cid.Cid, bbr BadBlockReason) { func (bts *BadBlockCache) Add(c cid.Cid, reason string) {
bts.badBlocks.Add(c, bbr) bts.badBlocks.Add(c, reason)
} }
func (bts *BadBlockCache) Has(c cid.Cid) (BadBlockReason, bool) { func (bts *BadBlockCache) Has(c cid.Cid) (string, bool) {
rval, ok := bts.badBlocks.Get(c) rval, ok := bts.badBlocks.Get(c)
if !ok { if !ok {
return BadBlockReason{}, false return "", false
} }
return rval.(BadBlockReason), true return rval.(string), true
} }
-4
View File
@@ -17,10 +17,6 @@ type Response struct {
Err error 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 { type RandomBeacon interface {
Entry(context.Context, uint64) <-chan Response Entry(context.Context, uint64) <-chan Response
VerifyEntry(types.BeaconEntry, types.BeaconEntry) error VerifyEntry(types.BeaconEntry, types.BeaconEntry) error
+31 -31
View File
@@ -8,9 +8,8 @@ import (
dchain "github.com/drand/drand/chain" dchain "github.com/drand/drand/chain"
dclient "github.com/drand/drand/client" dclient "github.com/drand/drand/client"
hclient "github.com/drand/drand/client/http" gclient "github.com/drand/drand/cmd/relay-gossip/client"
dlog "github.com/drand/drand/log" dlog "github.com/drand/drand/log"
gclient "github.com/drand/drand/lp2p/client"
"github.com/drand/kyber" "github.com/drand/kyber"
kzap "github.com/go-kit/kit/log/zap" kzap "github.com/go-kit/kit/log/zap"
"go.uber.org/zap/zapcore" "go.uber.org/zap/zapcore"
@@ -19,15 +18,31 @@ import (
logging "github.com/ipfs/go-log" logging "github.com/ipfs/go-log"
pubsub "github.com/libp2p/go-libp2p-pubsub" 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/beacon"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/filecoin-project/specs-actors/actors/abi"
) )
var log = logging.Logger("drand") 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 { type drandPeer struct {
addr string addr string
tls bool tls bool
@@ -41,13 +56,6 @@ func (dp *drandPeer) IsTLS() bool {
return dp.tls 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 { type DrandBeacon struct {
client dclient.Client client dclient.Client
@@ -64,34 +72,18 @@ type DrandBeacon struct {
localCache map[uint64]types.BeaconEntry localCache map[uint64]types.BeaconEntry
} }
func NewDrandBeacon(genesisTs, interval uint64, ps *pubsub.PubSub, config dtypes.DrandConfig) (*DrandBeacon, error) { func NewDrandBeacon(genesisTs, interval uint64, ps *pubsub.PubSub) (*DrandBeacon, error) {
if genesisTs == 0 { if genesisTs == 0 {
panic("what are you doing this cant be zero") 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( dlogger := dlog.NewKitLoggerFrom(kzap.NewZapSugarLogger(
log.SugaredLogger.Desugar(), zapcore.InfoLevel)) 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{ opts := []dclient.Option{
dclient.WithChainInfo(drandChain), dclient.WithChainInfo(drandChain),
dclient.WithHTTPEndpoints(drandServers),
dclient.WithCacheSize(1024), dclient.WithCacheSize(1024),
dclient.WithLogger(dlogger), dclient.WithLogger(dlogger),
dclient.WithAutoWatch(),
} }
if ps != nil { if ps != nil {
@@ -100,11 +92,19 @@ func NewDrandBeacon(genesisTs, interval uint64, ps *pubsub.PubSub, config dtypes
log.Info("drand beacon without pubsub") log.Info("drand beacon without pubsub")
} }
client, err := dclient.Wrap(clients, opts...) client, err := dclient.New(opts...)
if err != nil { if err != nil {
return nil, xerrors.Errorf("creating drand client") 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{ db := &DrandBeacon{
client: client, client: client,
localCache: make(map[uint64]types.BeaconEntry), localCache: make(map[uint64]types.BeaconEntry),
+2 -5
View File
@@ -5,15 +5,12 @@ import (
"testing" "testing"
dchain "github.com/drand/drand/chain" dchain "github.com/drand/drand/chain"
hclient "github.com/drand/drand/client/http" dclient "github.com/drand/drand/client"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/filecoin-project/lotus/build"
) )
func TestPrintGroupInfo(t *testing.T) { func TestPrintGroupInfo(t *testing.T) {
server := build.DrandConfig.Servers[0] c, err := dclient.NewHTTPClient(drandServers[0], nil, nil)
c, err := hclient.New(server, nil, nil)
assert.NoError(t, err) assert.NoError(t, err)
cg := c.(interface { cg := c.(interface {
FetchChainInfo(groupHash []byte) (*dchain.Info, error) FetchChainInfo(groupHash []byte) (*dchain.Info, error)
-19
View File
@@ -10,7 +10,6 @@ import (
"golang.org/x/xerrors" "golang.org/x/xerrors"
cborutil "github.com/filecoin-project/go-cbor-util" cborutil "github.com/filecoin-project/go-cbor-util"
"github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
@@ -28,24 +27,6 @@ const BlockSyncProtocolID = "/fil/sync/blk/0.0.1"
const BlockSyncMaxRequestLength = 800 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 { type BlockSyncService struct {
cs *store.ChainStore cs *store.ChainStore
} }
+9 -21
View File
@@ -64,11 +64,6 @@ 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) { func (bs *BlockSync) GetBlocks(ctx context.Context, tsk types.TipSetKey, count int) ([]*types.TipSet, error) {
ctx, span := trace.StartSpan(ctx, "bsync.GetBlocks") ctx, span := trace.StartSpan(ctx, "bsync.GetBlocks")
defer span.End() defer span.End()
@@ -85,9 +80,7 @@ func (bs *BlockSync) GetBlocks(ctx context.Context, tsk types.TipSetKey, count i
Options: BSOptBlocks, Options: BSOptBlocks,
} }
// this peerset is sorted by latency and failure counting.
peers := bs.getPeers() peers := bs.getPeers()
// randomize the first few peers so we don't always pick the same peer // randomize the first few peers so we don't always pick the same peer
shufflePrefix(peers) shufflePrefix(peers)
@@ -363,7 +356,6 @@ func (bs *BlockSync) RemovePeer(p peer.ID) {
bs.syncPeers.removePeer(p) bs.syncPeers.removePeer(p)
} }
// getPeers returns a preference-sorted set of peers to query.
func (bs *BlockSync) getPeers() []peer.ID { func (bs *BlockSync) getPeers() []peer.ID {
return bs.syncPeers.prefSortedPeers() return bs.syncPeers.prefSortedPeers()
} }
@@ -569,30 +561,26 @@ func (bpt *bsPeerTracker) logSuccess(p peer.ID, dur time.Duration) {
bpt.lk.Lock() bpt.lk.Lock()
defer bpt.lk.Unlock() defer bpt.lk.Unlock()
var pi *peerStats if pi, ok := bpt.peers[p]; !ok {
var ok bool
if pi, ok = bpt.peers[p]; !ok {
log.Warnw("log success called on peer not in tracker", "peerid", p.String()) log.Warnw("log success called on peer not in tracker", "peerid", p.String())
return return
} } else {
pi.successes++
pi.successes++ logTime(pi, dur)
logTime(pi, dur) }
} }
func (bpt *bsPeerTracker) logFailure(p peer.ID, dur time.Duration) { func (bpt *bsPeerTracker) logFailure(p peer.ID, dur time.Duration) {
bpt.lk.Lock() bpt.lk.Lock()
defer bpt.lk.Unlock() defer bpt.lk.Unlock()
if pi, ok := bpt.peers[p]; !ok {
var pi *peerStats
var ok bool
if pi, ok = bpt.peers[p]; !ok {
log.Warn("log failure called on peer not in tracker", "peerid", p.String()) log.Warn("log failure called on peer not in tracker", "peerid", p.String())
return return
} else {
pi.failures++
logTime(pi, dur)
} }
pi.failures++
logTime(pi, dur)
} }
func (bpt *bsPeerTracker) removePeer(p peer.ID) { func (bpt *bsPeerTracker) removePeer(p peer.ID) {
+19 -8
View File
@@ -19,7 +19,7 @@ import (
var log = logging.Logger("events") var log = logging.Logger("events")
// HeightHandler `curH`-`ts.Height` = `confidence` // `curH`-`ts.Height` = `confidence`
type HeightHandler func(ctx context.Context, ts *types.TipSet, curH abi.ChainEpoch) error type HeightHandler func(ctx context.Context, ts *types.TipSet, curH abi.ChainEpoch) error
type RevertHandler func(ctx context.Context, ts *types.TipSet) error type RevertHandler func(ctx context.Context, ts *types.TipSet) error
@@ -31,7 +31,7 @@ type heightHandler struct {
revert RevertHandler revert RevertHandler
} }
type eventAPI interface { type eventApi interface {
ChainNotify(context.Context) (<-chan []*api.HeadChange, error) ChainNotify(context.Context) (<-chan []*api.HeadChange, error)
ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error) ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error)
ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error)
@@ -42,7 +42,7 @@ type eventAPI interface {
} }
type Events struct { type Events struct {
api eventAPI api eventApi
tsc *tipSetCache tsc *tipSetCache
lk sync.Mutex lk sync.Mutex
@@ -51,10 +51,10 @@ type Events struct {
readyOnce sync.Once readyOnce sync.Once
heightEvents heightEvents
*hcEvents calledEvents
} }
func NewEvents(ctx context.Context, api eventAPI) *Events { func NewEvents(ctx context.Context, api eventApi) *Events {
gcConfidence := 2 * build.ForkLengthThreshold gcConfidence := 2 * build.ForkLengthThreshold
tsc := newTSCache(gcConfidence, api.ChainGetTipSetByHeight) tsc := newTSCache(gcConfidence, api.ChainGetTipSetByHeight)
@@ -74,7 +74,18 @@ func NewEvents(ctx context.Context, api eventAPI) *Events {
htHeights: map[abi.ChainEpoch][]uint64{}, htHeights: map[abi.ChainEpoch][]uint64{},
}, },
hcEvents: newHCEvents(ctx, api, tsc, uint64(gcConfidence)), 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{},
},
} }
e.ready.Add(1) e.ready.Add(1)
@@ -132,7 +143,7 @@ func (e *Events) listenHeadChangesOnce(ctx context.Context) error {
} }
e.readyOnce.Do(func() { e.readyOnce.Do(func() {
e.lastTs = cur[0].Val e.at = cur[0].Val.Height()
e.ready.Done() e.ready.Done()
}) })
@@ -175,5 +186,5 @@ func (e *Events) headChange(rev, app []*types.TipSet) error {
return err return err
} }
return e.processHeadChangeEvent(rev, app) return e.headChangeCalled(rev, app)
} }
+116 -371
View File
@@ -13,9 +13,8 @@ import (
) )
const NoTimeout = math.MaxInt64 const NoTimeout = math.MaxInt64
const NoHeight = abi.ChainEpoch(-1)
type triggerID = uint64 type triggerId = uint64
// msgH is the block height at which a message was present / event has happened // msgH is the block height at which a message was present / event has happened
type msgH = abi.ChainEpoch type msgH = abi.ChainEpoch
@@ -24,60 +23,53 @@ type msgH = abi.ChainEpoch
// message (msgH+confidence) // message (msgH+confidence)
type triggerH = abi.ChainEpoch type triggerH = abi.ChainEpoch
type eventData interface{} // `ts` is the tipset, in which the `msg` is included.
// 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` // `curH`-`ts.Height` = `confidence`
type EventHandler func(data eventData, prevTs, ts *types.TipSet, curH abi.ChainEpoch) (more bool, err error) type CalledHandler func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (more bool, err error)
// CheckFunc is used for atomicity guarantees. If the condition the callbacks // CheckFunc is used for atomicity guarantees. If the condition the callbacks
// wait for has already happened in tipset `ts` // wait for has already happened in tipset `ts`
// //
// If `done` is true, timeout won't be triggered // If `done` is true, timeout won't be triggered
// If `more` is false, no messages will be sent to EventHandler (RevertHandler // If `more` is false, no messages will be sent to CalledHandler (RevertHandler
// may still be called) // may still be called)
type CheckFunc func(ts *types.TipSet) (done bool, more bool, err error) type CheckFunc func(ts *types.TipSet) (done bool, more bool, err error)
// Keep track of information for an event handler type MatchFunc func(msg *types.Message) (bool, error)
type handlerInfo struct {
type callHandler struct {
confidence int confidence int
timeout abi.ChainEpoch timeout abi.ChainEpoch
disabled bool // TODO: GC after gcConfidence reached disabled bool // TODO: GC after gcConfidence reached
handle EventHandler handle CalledHandler
revert RevertHandler revert RevertHandler
} }
// When a change occurs, a queuedEvent is created and put into a queue
// until the required confidence is reached
type queuedEvent struct { type queuedEvent struct {
trigger triggerID trigger triggerId
prevH abi.ChainEpoch h abi.ChainEpoch
h abi.ChainEpoch msg *types.Message
data eventData
called bool called bool
} }
// Manages chain head change events, which may be forward (new tipset added to type calledEvents struct {
// chain) or backward (chain branch discarded in favour of heavier branch) cs eventApi
type hcEvents struct {
cs eventAPI
tsc *tipSetCache tsc *tipSetCache
ctx context.Context ctx context.Context
gcConfidence uint64 gcConfidence uint64
lastTs *types.TipSet at abi.ChainEpoch
lk sync.Mutex lk sync.Mutex
ctr triggerID ctr triggerId
triggers map[triggerID]*handlerInfo triggers map[triggerId]*callHandler
matchers map[triggerId][]MatchFunc
// maps block heights to events // maps block heights to events
// [triggerH][msgH][event] // [triggerH][msgH][event]
@@ -86,81 +78,29 @@ type hcEvents struct {
// [msgH][triggerH] // [msgH][triggerH]
revertQueue map[msgH][]triggerH revertQueue map[msgH][]triggerH
// [timeoutH+confidence][triggerID]{calls} // [timeoutH+confidence][triggerId]{calls}
timeouts map[abi.ChainEpoch]map[triggerID]int timeouts map[abi.ChainEpoch]map[triggerId]int
messageEvents
watcherEvents
} }
func newHCEvents(ctx context.Context, cs eventAPI, tsc *tipSetCache, gcConfidence uint64) *hcEvents { func (e *calledEvents) headChangeCalled(rev, app []*types.TipSet) error {
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 { for _, ts := range rev {
e.handleReverts(ts) e.handleReverts(ts)
e.lastTs = ts e.at = ts.Height()
} }
for _, ts := range app { for _, ts := range app {
// Check if the head change caused any state changes that we were // called triggers
// waiting for e.checkNewCalls(ts)
stateChanges := e.watcherEvents.checkStateChanges(e.lastTs, ts) for ; e.at <= ts.Height(); e.at++ {
e.applyWithConfidence(ts, e.at)
// 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) e.applyTimeouts(ts)
} }
// Update the latest known tipset
e.lastTs = ts
} }
return nil return nil
} }
func (e *hcEvents) handleReverts(ts *types.TipSet) { func (e *calledEvents) handleReverts(ts *types.TipSet) {
reverts, ok := e.revertQueue[ts.Height()] reverts, ok := e.revertQueue[ts.Height()]
if !ok { if !ok {
return // nothing to do return // nothing to do
@@ -176,7 +116,7 @@ func (e *hcEvents) handleReverts(ts *types.TipSet) {
trigger := e.triggers[event.trigger] trigger := e.triggers[event.trigger]
if err := trigger.revert(e.ctx, ts); err != nil { if err := trigger.revert(e.ctx, ts); err != nil {
log.Errorf("reverting chain trigger (@H %d, triggered @ %d) failed: %s", ts.Height(), triggerH, err) log.Errorf("reverting chain trigger (call %s.%d() @H %d, called @ %d) failed: %s", event.msg.To, event.msg.Method, ts.Height(), triggerH, err)
} }
} }
delete(e.confQueue[triggerH], ts.Height()) delete(e.confQueue[triggerH], ts.Height())
@@ -184,15 +124,42 @@ func (e *hcEvents) handleReverts(ts *types.TipSet) {
delete(e.revertQueue, ts.Height()) delete(e.revertQueue, ts.Height())
} }
// Queue up events until the chain has reached a height that reflects the func (e *calledEvents) checkNewCalls(ts *types.TipSet) {
// desired confidence pts, err := e.cs.ChainGetTipSet(e.ctx, ts.Parents()) // we actually care about messages in the parent tipset here
func (e *hcEvents) queueForConfidence(trigID uint64, data eventData, prevTs, ts *types.TipSet) { if err != nil {
trigger := e.triggers[trigID] log.Errorf("getting parent tipset in checkNewCalls: %s", err)
return
prevH := NoHeight
if prevTs != nil {
prevH = prevTs.Height()
} }
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(triggerId uint64, msg *types.Message, ts *types.TipSet) {
trigger := e.triggers[triggerId]
appliedH := ts.Height() appliedH := ts.Height()
triggerH := appliedH + abi.ChainEpoch(trigger.confidence) triggerH := appliedH + abi.ChainEpoch(trigger.confidence)
@@ -204,20 +171,18 @@ func (e *hcEvents) queueForConfidence(trigID uint64, data eventData, prevTs, ts
} }
byOrigH[appliedH] = append(byOrigH[appliedH], &queuedEvent{ byOrigH[appliedH] = append(byOrigH[appliedH], &queuedEvent{
trigger: trigID, trigger: triggerId,
prevH: prevH,
h: appliedH, h: appliedH,
data: data, msg: msg,
}) })
e.revertQueue[appliedH] = append(e.revertQueue[appliedH], triggerH) e.revertQueue[appliedH] = append(e.revertQueue[appliedH], triggerH)
} }
// Apply any events that were waiting for this chain height for confidence func (e *calledEvents) applyWithConfidence(ts *types.TipSet, height abi.ChainEpoch) {
func (e *hcEvents) applyWithConfidence(ts *types.TipSet, height abi.ChainEpoch) {
byOrigH, ok := e.confQueue[height] byOrigH, ok := e.confQueue[height]
if !ok { if !ok {
return // no triggers at this height return // no triggers at thin height
} }
for origH, events := range byOrigH { for origH, events := range byOrigH {
@@ -236,20 +201,15 @@ func (e *hcEvents) applyWithConfidence(ts *types.TipSet, height abi.ChainEpoch)
continue continue
} }
// Previous tipset - this is relevant for example in a state change rec, err := e.cs.StateGetReceipt(e.ctx, event.msg.Cid(), ts.Key())
// from one tipset to another if err != nil {
var prevTs *types.TipSet log.Error(err)
if event.prevH != NoHeight { return
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.data, prevTs, triggerTs, height) more, err := trigger.handle(event.msg, rec, triggerTs, height)
if err != nil { if err != nil {
log.Errorf("chain trigger (@H %d, triggered @ %d) failed: %s", origH, height, err) log.Errorf("chain trigger (call %s.%d() @H %d, called @ %d) failed: %s", event.msg.To, event.msg.Method, origH, height, err)
continue // don't revert failed calls continue // don't revert failed calls
} }
@@ -265,18 +225,17 @@ func (e *hcEvents) applyWithConfidence(ts *types.TipSet, height abi.ChainEpoch)
} }
} }
// Apply any timeouts that expire at this height func (e *calledEvents) applyTimeouts(ts *types.TipSet) {
func (e *hcEvents) applyTimeouts(ts *types.TipSet) {
triggers, ok := e.timeouts[ts.Height()] triggers, ok := e.timeouts[ts.Height()]
if !ok { if !ok {
return // nothing to do return // nothing to do
} }
for triggerID, calls := range triggers { for triggerId, calls := range triggers {
if calls > 0 { if calls > 0 {
continue // don't timeout if the method was called continue // don't timeout if the method was called
} }
trigger := e.triggers[triggerID] trigger := e.triggers[triggerId]
if trigger.disabled { if trigger.disabled {
continue continue
} }
@@ -296,225 +255,12 @@ func (e *hcEvents) applyTimeouts(ts *types.TipSet) {
} }
} }
// Listen for an event func (e *calledEvents) messagesForTs(ts *types.TipSet, consume func(*types.Message)) {
// - 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
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 {
res[tid] = msg
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{}{} seen := map[cid.Cid]struct{}{}
for _, tsb := range ts.Blocks() { for _, tsb := range ts.Blocks() {
msgs, err := me.cs.ChainGetBlockMessages(context.TODO(), tsb.Cid()) msgs, err := e.cs.ChainGetBlockMessages(context.TODO(), tsb.Cid())
if err != nil { if err != nil {
log.Errorf("messagesForTs MessagesForBlock failed (ts.H=%d, Bcid:%s, B.Mcid:%s): %s", ts.Height(), tsb.Cid(), tsb.Messages, err) 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 // this is quite bad, but probably better than missing all the other updates
@@ -543,27 +289,20 @@ func (me *messageEvents) messagesForTs(ts *types.TipSet, consume func(*types.Mes
} }
} }
// MsgHandler arguments: // Called registers a callbacks which are triggered when a specified method is
// `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) (bool, error)
// Called registers a callback which is triggered when a specified method is
// called on an actor, or a timeout is reached. // called on an actor, or a timeout is reached.
// //
// * `CheckFunc` callback is invoked immediately with a recent tipset, it // * `CheckFunc` callback is invoked immediately with a recent tipset, it
// returns two booleans - `done`, and `more`. // returns two booleans - `done`, and `more`.
// //
// * `done` should be true when some on-chain action we are waiting for has // * `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. // happened. When `done` is set to true, timeout trigger is disabled.
// //
// * `more` should be false when we don't want to receive new notifications // * `more` should be false when we don't want to receive new notifications
// through MsgHandler. Note that notifications may still be delivered to // through CalledHandler. Note that notifications may still be delivered to
// RevertHandler // RevertHandler
// //
// * `MsgHandler` is called when the specified event was observed on-chain, // * `CalledHandler` is called when the specified event was observed on-chain,
// and a confidence threshold was reached, or the specified `timeout` height // and a confidence threshold was reached, or the specified `timeout` height
// was reached with no events observed. When this callback is invoked on a // 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 // timeout, `msg` is set to nil. This callback returns a boolean specifying
@@ -574,38 +313,44 @@ type MsgMatchFunc func(msg *types.Message) (bool, error)
// containing the message. The tipset passed as the argument is the tipset // 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 // that is being dropped. Note that the message dropped may be re-applied
// in a different tipset in small amount of time. // 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 {
// * `MsgMatchFunc` is called against each message. If there is a match, the e.lk.Lock()
// message is queued up until the confidence interval has elapsed (and defer e.lk.Unlock()
// `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")
}
rec, err := me.cs.StateGetReceipt(me.ctx, msg.Cid(), ts.Key()) ts := e.tsc.best()
if err != nil { done, more, err := check(ts)
return false, err
}
return msgHnd(msg, rec, ts, height)
}
id, err := me.hcAPI.onHeadChanged(check, hnd, rev, confidence, timeout)
if err != nil { if err != nil {
return err return xerrors.Errorf("called check error (h: %d): %w", ts.Height(), err)
}
if done {
timeout = NoTimeout
} }
me.lk.Lock() id := e.ctr
defer me.lk.Unlock() e.ctr++
me.matchers[id] = append(me.matchers[id], mf)
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{}
}
e.timeouts[timeout+abi.ChainEpoch(confidence)][id] = 0
}
return nil return nil
} }
// Convenience function for checking and matching messages func (e *calledEvents) CalledMsg(ctx context.Context, hnd CalledHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, msg types.ChainMsg) error {
func (me *messageEvents) CalledMsg(ctx context.Context, hnd MsgHandler, 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()))
return me.Called(me.CheckMsg(ctx, msg, hnd), hnd, rev, confidence, timeout, me.MatchMsg(msg.VMMessage()))
} }
+8 -16
View File
@@ -15,26 +15,23 @@ type heightEvents struct {
tsc *tipSetCache tsc *tipSetCache
gcConfidence abi.ChainEpoch gcConfidence abi.ChainEpoch
ctr triggerID ctr triggerId
heightTriggers map[triggerID]*heightHandler heightTriggers map[triggerId]*heightHandler
htTriggerHeights map[triggerH][]triggerID htTriggerHeights map[triggerH][]triggerId
htHeights map[msgH][]triggerID htHeights map[msgH][]triggerId
ctx context.Context ctx context.Context
} }
func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error { func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error {
ctx, span := trace.StartSpan(e.ctx, "events.HeightHeadChange") ctx, span := trace.StartSpan(e.ctx, "events.HeightHeadChange")
defer span.End() defer span.End()
span.AddAttributes(trace.Int64Attribute("endHeight", int64(app[0].Height()))) span.AddAttributes(trace.Int64Attribute("endHeight", int64(app[0].Height())))
span.AddAttributes(trace.Int64Attribute("reverts", int64(len(rev)))) span.AddAttributes(trace.Int64Attribute("reverts", int64(len(rev))))
span.AddAttributes(trace.Int64Attribute("applies", int64(len(app)))) span.AddAttributes(trace.Int64Attribute("applies", int64(len(app))))
e.lk.Lock()
defer e.lk.Unlock()
for _, ts := range rev { for _, ts := range rev {
// TODO: log error if h below gcconfidence // TODO: log error if h below gcconfidence
// revert height-based triggers // revert height-based triggers
@@ -43,10 +40,7 @@ func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error {
for _, tid := range e.htHeights[h] { for _, tid := range e.htHeights[h] {
ctx, span := trace.StartSpan(ctx, "events.HeightRevert") ctx, span := trace.StartSpan(ctx, "events.HeightRevert")
rev := e.heightTriggers[tid].revert err := e.heightTriggers[tid].revert(ctx, ts)
e.lk.Unlock()
err := rev(ctx, ts)
e.lk.Lock()
e.heightTriggers[tid].called = false e.heightTriggers[tid].called = false
span.End() span.End()
@@ -93,6 +87,7 @@ func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error {
if hnd.called { if hnd.called {
return nil return nil
} }
hnd.called = true
triggerH := h - abi.ChainEpoch(hnd.confidence) triggerH := h - abi.ChainEpoch(hnd.confidence)
@@ -103,11 +98,8 @@ func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error {
ctx, span := trace.StartSpan(ctx, "events.HeightApply") ctx, span := trace.StartSpan(ctx, "events.HeightApply")
span.AddAttributes(trace.BoolAttribute("immediate", false)) span.AddAttributes(trace.BoolAttribute("immediate", false))
handle := hnd.handle
e.lk.Unlock() err = hnd.handle(ctx, incTs, h)
err = handle(ctx, incTs, h)
e.lk.Lock()
hnd.called = true
span.End() span.End()
if err != nil { if err != nil {
+5 -249
View File
@@ -211,14 +211,15 @@ func (fcs *fakeCS) advance(rev, app int, msgs map[int]cid.Cid, nulls ...int) { /
fcs.sub(revs, apps) fcs.sub(revs, apps)
fcs.sync.Lock() fcs.sync.Lock()
fcs.sync.Unlock() //nolint:staticcheck fcs.sync.Unlock()
} }
func (fcs *fakeCS) notifDone() { func (fcs *fakeCS) notifDone() {
fcs.sync.Unlock() fcs.sync.Unlock()
} }
var _ eventAPI = &fakeCS{} var _ eventApi = &fakeCS{}
func TestAt(t *testing.T) { func TestAt(t *testing.T) {
fcs := &fakeCS{ fcs := &fakeCS{
@@ -1004,6 +1005,8 @@ func TestRemoveTriggersOnMessage(t *testing.T) {
return false, true, nil return false, true, nil
}, func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (bool, error) { }, func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (bool, error) {
require.Equal(t, false, applied) require.Equal(t, false, applied)
fmt.Println(msg == nil)
fmt.Println(curH)
applied = true applied = true
return more, nil return more, nil
}, func(_ context.Context, ts *types.TipSet) error { }, func(_ context.Context, ts *types.TipSet) error {
@@ -1065,250 +1068,3 @@ func TestRemoveTriggersOnMessage(t *testing.T) {
require.Equal(t, true, applied) require.Equal(t, true, applied)
require.Equal(t, false, reverted) 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
View File
@@ -1,25 +0,0 @@
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
View File
@@ -1,106 +0,0 @@
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
View File
@@ -1,155 +0,0 @@
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,
}
}
-490
View File
@@ -1,490 +0,0 @@
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
_, err := oldDealStateArray.Get(uint64(dealID), &oldDeal)
if err != nil {
return false, nil, err
}
oldDealPtr = &oldDeal
_, err = newDealStateArray.Get(uint64(dealID), &newDeal)
if err != nil {
return false, nil, err
}
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.Info.Expiration != siTo.Info.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
}
}
-483
View File
@@ -1,483 +0,0 @@
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,
}
newDeal2 := &market.DealState{
SectorStartEpoch: 4,
LastUpdatedEpoch: 6,
SlashEpoch: 6,
}
// added
newDeal3 := &market.DealState{
SectorStartEpoch: 1,
LastUpdatedEpoch: 2,
SlashEpoch: 3,
}
newDeals := map[abi.DealID]*market.DealState{
abi.DealID(1): newDeal1,
abi.DealID(2): newDeal2,
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.SlashEpoch != 0 || deal2.To.SlashEpoch != 6 {
t.Fatal("Unexpected change to SlashEpoch")
}
// 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, 0)
require.Len(t, changedDeals.Modified, 2)
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.Modified[1].ID)
require.Equal(t, oldDeal2, changedDeals.Modified[1].From)
require.Equal(t, newDeal2, changedDeals.Modified[1].To)
})
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"), big.NewInt(0), abi.ChainEpoch(0), abi.ChainEpoch(10))
si1 := newSectorOnChainInfo(1, tutils.MakeCID("1"), big.NewInt(1), abi.ChainEpoch(1), abi.ChainEpoch(11))
si2 := newSectorOnChainInfo(2, tutils.MakeCID("2"), 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"), big.NewInt(3), abi.ChainEpoch(3), abi.ChainEpoch(12))
// 0 delete
// 1 extend
// 2 same
// 3 added
si1Ext := si1
si1Ext.Info.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)
emptyDeadlines := miner.ConstructDeadlines()
emptyDeadlinesCid, err := store.Put(context.Background(), emptyDeadlines)
require.NoError(t, err)
state, err := miner.ConstructState(emptyArrayCid, emptyMap, emptyDeadlinesCid, owner, worker, abi.PeerID{'1'}, nil, abi.RegisteredSealProof_StackedDrg64GiBV1, 0)
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.Info.SectorNumber), &sector)
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{
Info: *info,
ActivationEpoch: activation,
DealWeight: weight,
VerifiedDealWeight: weight,
}
}
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,
}
}
+5 -5
View File
@@ -8,11 +8,11 @@ import (
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
) )
func (me *messageEvents) CheckMsg(ctx context.Context, smsg types.ChainMsg, hnd MsgHandler) CheckFunc { func (e *calledEvents) CheckMsg(ctx context.Context, smsg types.ChainMsg, hnd CalledHandler) CheckFunc {
msg := smsg.VMMessage() msg := smsg.VMMessage()
return func(ts *types.TipSet) (done bool, more bool, err error) { return func(ts *types.TipSet) (done bool, more bool, err error) {
fa, err := me.cs.StateGetActor(ctx, msg.From, ts.Key()) fa, err := e.cs.StateGetActor(ctx, msg.From, ts.Key())
if err != nil { if err != nil {
return false, true, err return false, true, err
} }
@@ -22,7 +22,7 @@ func (me *messageEvents) CheckMsg(ctx context.Context, smsg types.ChainMsg, hnd
return false, true, nil return false, true, nil
} }
rec, err := me.cs.StateGetReceipt(ctx, smsg.VMMessage().Cid(), ts.Key()) rec, err := e.cs.StateGetReceipt(ctx, smsg.VMMessage().Cid(), ts.Key())
if err != nil { if err != nil {
return false, true, xerrors.Errorf("getting receipt in CheckMsg: %w", err) return false, true, xerrors.Errorf("getting receipt in CheckMsg: %w", err)
} }
@@ -33,10 +33,10 @@ func (me *messageEvents) CheckMsg(ctx context.Context, smsg types.ChainMsg, hnd
} }
} }
func (me *messageEvents) MatchMsg(inmsg *types.Message) MsgMatchFunc { func (e *calledEvents) MatchMsg(inmsg *types.Message) MatchFunc {
return func(msg *types.Message) (bool, error) { return func(msg *types.Message) (bool, error) {
if msg.From == inmsg.From && msg.Nonce == inmsg.Nonce && !inmsg.Equals(msg) { 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 false, xerrors.Errorf("matching msg %s from %s, nonce %d: got duplicate origin/nonce msg %s", inmsg.Cid(), inmsg.From, inmsg.Nonce, msg.Nonce)
} }
return inmsg.Equals(msg), nil return inmsg.Equals(msg), nil
+19 -14
View File
@@ -45,10 +45,6 @@ var log = logging.Logger("gen")
const msgsPerBlock = 20 const msgsPerBlock = 20
var ValidWpostForTesting = []abi.PoStProof{{
ProofBytes: []byte("valid proof"),
}}
type ChainGen struct { type ChainGen struct {
msgsPerBlock int msgsPerBlock int
@@ -93,8 +89,8 @@ func (m mybs) Get(c cid.Cid) (block.Block, error) {
} }
func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) { func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
saminer.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ saminer.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
abi.RegisteredSealProof_StackedDrg2KiBV1: {}, abi.RegisteredProof_StackedDRG2KiBSeal: {},
} }
mr := repo.NewMemory(nil) mr := repo.NewMemory(nil)
@@ -145,7 +141,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
return nil, err return nil, err
} }
genm1, k1, err := seed.PreSeal(maddr1, abi.RegisteredSealProof_StackedDrg2KiBV1, 0, numSectors, m1temp, []byte("some randomness"), nil, true) genm1, k1, err := seed.PreSeal(maddr1, abi.RegisteredProof_StackedDRG2KiBPoSt, 0, numSectors, m1temp, []byte("some randomness"), nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -157,7 +153,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
return nil, err return nil, err
} }
genm2, k2, err := seed.PreSeal(maddr2, abi.RegisteredSealProof_StackedDrg2KiBV1, 0, numSectors, m2temp, []byte("some randomness"), nil, true) genm2, k2, err := seed.PreSeal(maddr2, abi.RegisteredProof_StackedDRG2KiBPoSt, 0, numSectors, m2temp, []byte("some randomness"), nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -196,7 +192,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
*genm2, *genm2,
}, },
NetworkName: "", NetworkName: "",
Timestamp: uint64(time.Now().Add(-500 * time.Duration(build.BlockDelaySecs) * time.Second).Unix()), Timestamp: uint64(time.Now().Add(-500 * build.BlockDelay * time.Second).Unix()),
} }
genb, err := genesis2.MakeGenesisBlock(context.TODO(), bs, sys, tpl) genb, err := genesis2.MakeGenesisBlock(context.TODO(), bs, sys, tpl)
@@ -223,7 +219,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
miners := []address.Address{maddr1, maddr2} miners := []address.Address{maddr1, maddr2}
beac := beacon.NewMockBeacon(time.Second) beac := beacon.NewMockBeacon(time.Second)
//beac, err := drand.NewDrandBeacon(tpl.Timestamp, build.BlockDelaySecs) //beac, err := drand.NewDrandBeacon(tpl.Timestamp, build.BlockDelay)
//if err != nil { //if err != nil {
//return nil, xerrors.Errorf("creating drand beacon: %w", err) //return nil, xerrors.Errorf("creating drand beacon: %w", err)
//} //}
@@ -414,7 +410,7 @@ func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, vrfticke
if cg.Timestamper != nil { if cg.Timestamper != nil {
ts = cg.Timestamper(parents, height-parents.Height()) ts = cg.Timestamper(parents, height-parents.Height())
} else { } else {
ts = parents.MinTimestamp() + uint64(height-parents.Height())*build.BlockDelaySecs ts = parents.MinTimestamp() + uint64((height-parents.Height())*build.BlockDelay)
} }
fblk, err := MinerCreateBlock(context.TODO(), cg.sm, cg.w, &api.BlockTemplate{ fblk, err := MinerCreateBlock(context.TODO(), cg.sm, cg.w, &api.BlockTemplate{
@@ -435,7 +431,7 @@ func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, vrfticke
return fblk, err return fblk, err
} }
// ResyncBankerNonce is used for dealing with messages made when // This function is awkward. It's used to deal with messages made when
// simulating forks // simulating forks
func (cg *ChainGen) ResyncBankerNonce(ts *types.TipSet) error { func (cg *ChainGen) ResyncBankerNonce(ts *types.TipSet) error {
act, err := cg.sm.GetActor(cg.banker, ts) act, err := cg.sm.GetActor(cg.banker, ts)
@@ -537,7 +533,16 @@ func (wpp *wppProvider) GenerateCandidates(ctx context.Context, _ abi.PoStRandom
} }
func (wpp *wppProvider) ComputeProof(context.Context, []abi.SectorInfo, abi.PoStRandomness) ([]abi.PoStProof, error) { func (wpp *wppProvider) ComputeProof(context.Context, []abi.SectorInfo, abi.PoStRandomness) ([]abi.PoStProof, error) {
return ValidWpostForTesting, nil return []abi.PoStProof{{
ProofBytes: []byte("valid proof"),
}}, nil
}
type ProofInput struct {
sectors []abi.SectorInfo
hvrf []byte
challengedSectors []uint64
vrfout []byte
} }
func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch, func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch,
@@ -613,6 +618,6 @@ func (m genFakeVerifier) VerifyWindowPoSt(ctx context.Context, info abi.WindowPo
panic("not supported") panic("not supported")
} }
func (m genFakeVerifier) GenerateWinningPoStSectorChallenge(ctx context.Context, proof abi.RegisteredPoStProof, id abi.ActorID, randomness abi.PoStRandomness, u uint64) ([]uint64, error) { func (m genFakeVerifier) GenerateWinningPoStSectorChallenge(ctx context.Context, proof abi.RegisteredProof, id abi.ActorID, randomness abi.PoStRandomness, u uint64) ([]uint64, error) {
panic("not supported") panic("not supported")
} }
+2 -2
View File
@@ -14,8 +14,8 @@ import (
) )
func init() { func init() {
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
abi.RegisteredSealProof_StackedDrg2KiBV1: {}, abi.RegisteredProof_StackedDRG2KiBSeal: {},
} }
power.ConsensusMinerMinPower = big.NewInt(2048) power.ConsensusMinerMinPower = big.NewInt(2048)
verifreg.MinVerifiedDealSize = big.NewInt(256) verifreg.MinVerifiedDealSize = big.NewInt(256)
+7 -10
View File
@@ -71,7 +71,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
constructorParams := &power.CreateMinerParams{ constructorParams := &power.CreateMinerParams{
Owner: m.Worker, Owner: m.Worker,
Worker: m.Worker, Worker: m.Worker,
Peer: []byte(m.PeerId), Peer: m.PeerId,
SealProofType: spt, SealProofType: spt,
} }
@@ -204,12 +204,12 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
{ {
newSectorInfo := &miner.SectorOnChainInfo{ newSectorInfo := &miner.SectorOnChainInfo{
Info: miner.SectorPreCommitInfo{ Info: miner.SectorPreCommitInfo{
SealProof: preseal.ProofType, RegisteredProof: preseal.ProofType,
SectorNumber: preseal.SectorID, SectorNumber: preseal.SectorID,
SealedCID: preseal.CommR, SealedCID: preseal.CommR,
SealRandEpoch: 0, SealRandEpoch: 0,
DealIDs: []abi.DealID{dealIDs[pi]}, DealIDs: []abi.DealID{dealIDs[pi]},
Expiration: preseal.Deal.EndEpoch, Expiration: preseal.Deal.EndEpoch,
}, },
ActivationEpoch: 0, ActivationEpoch: 0,
DealWeight: dealWeight.DealWeight, DealWeight: dealWeight.DealWeight,
@@ -242,9 +242,6 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
st.TotalQualityAdjPower = big.Sub(st.TotalQualityAdjPower, big.NewInt(1)) st.TotalQualityAdjPower = big.Sub(st.TotalQualityAdjPower, big.NewInt(1))
return nil return nil
}) })
if err != nil {
return cid.Undef, xerrors.Errorf("mutating state: %w", err)
}
c, err := vm.Flush(ctx) c, err := vm.Flush(ctx)
if err != nil { if err != nil {
-11
View File
@@ -150,17 +150,6 @@ func aggregateSignatures(sigs []crypto.Signature) (*crypto.Signature, error) {
} }
aggSig := bls.Aggregate(blsSigs) 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{ return &crypto.Signature{
Type: crypto.SigTypeBLS, Type: crypto.SigTypeBLS,
Data: aggSig[:], Data: aggSig[:],
+1 -1
View File
@@ -187,7 +187,7 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa
mp := &MessagePool{ mp := &MessagePool{
closer: make(chan struct{}), closer: make(chan struct{}),
repubTk: time.NewTicker(time.Duration(build.BlockDelaySecs) * 10 * time.Second), repubTk: time.NewTicker(build.BlockDelay * 10 * time.Second),
localAddrs: make(map[address.Address]struct{}), localAddrs: make(map[address.Address]struct{}),
pending: make(map[address.Address]*msgSet), pending: make(map[address.Address]*msgSet),
minGasPrice: types.NewInt(0), minGasPrice: types.NewInt(0),
+17 -17
View File
@@ -16,7 +16,7 @@ import (
"github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore"
) )
type testMpoolAPI struct { type testMpoolApi struct {
cb func(rev, app []*types.TipSet) error cb func(rev, app []*types.TipSet) error
bmsgs map[cid.Cid][]*types.SignedMessage bmsgs map[cid.Cid][]*types.SignedMessage
@@ -25,68 +25,68 @@ type testMpoolAPI struct {
tipsets []*types.TipSet tipsets []*types.TipSet
} }
func newTestMpoolAPI() *testMpoolAPI { func newTestMpoolApi() *testMpoolApi {
return &testMpoolAPI{ return &testMpoolApi{
bmsgs: make(map[cid.Cid][]*types.SignedMessage), bmsgs: make(map[cid.Cid][]*types.SignedMessage),
statenonce: make(map[address.Address]uint64), statenonce: make(map[address.Address]uint64),
} }
} }
func (tma *testMpoolAPI) applyBlock(t *testing.T, b *types.BlockHeader) { func (tma *testMpoolApi) applyBlock(t *testing.T, b *types.BlockHeader) {
t.Helper() t.Helper()
if err := tma.cb(nil, []*types.TipSet{mock.TipSet(b)}); err != nil { if err := tma.cb(nil, []*types.TipSet{mock.TipSet(b)}); err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func (tma *testMpoolAPI) revertBlock(t *testing.T, b *types.BlockHeader) { func (tma *testMpoolApi) revertBlock(t *testing.T, b *types.BlockHeader) {
t.Helper() t.Helper()
if err := tma.cb([]*types.TipSet{mock.TipSet(b)}, nil); err != nil { if err := tma.cb([]*types.TipSet{mock.TipSet(b)}, nil); err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func (tma *testMpoolAPI) setStateNonce(addr address.Address, v uint64) { func (tma *testMpoolApi) setStateNonce(addr address.Address, v uint64) {
tma.statenonce[addr] = v tma.statenonce[addr] = v
} }
func (tma *testMpoolAPI) setBlockMessages(h *types.BlockHeader, msgs ...*types.SignedMessage) { func (tma *testMpoolApi) setBlockMessages(h *types.BlockHeader, msgs ...*types.SignedMessage) {
tma.bmsgs[h.Cid()] = msgs tma.bmsgs[h.Cid()] = msgs
tma.tipsets = append(tma.tipsets, mock.TipSet(h)) tma.tipsets = append(tma.tipsets, mock.TipSet(h))
} }
func (tma *testMpoolAPI) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) *types.TipSet { func (tma *testMpoolApi) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) *types.TipSet {
tma.cb = cb tma.cb = cb
return nil return nil
} }
func (tma *testMpoolAPI) PutMessage(m types.ChainMsg) (cid.Cid, error) { func (tma *testMpoolApi) PutMessage(m types.ChainMsg) (cid.Cid, error) {
return cid.Undef, nil return cid.Undef, nil
} }
func (tma *testMpoolAPI) PubSubPublish(string, []byte) error { func (tma *testMpoolApi) PubSubPublish(string, []byte) error {
return nil return nil
} }
func (tma *testMpoolAPI) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) { func (tma *testMpoolApi) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
return &types.Actor{ return &types.Actor{
Nonce: tma.statenonce[addr], Nonce: tma.statenonce[addr],
Balance: types.NewInt(90000000), Balance: types.NewInt(90000000),
}, nil }, nil
} }
func (tma *testMpoolAPI) StateAccountKey(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { func (tma *testMpoolApi) StateAccountKey(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
if addr.Protocol() != address.BLS && addr.Protocol() != address.SECP256K1 { if addr.Protocol() != address.BLS && addr.Protocol() != address.SECP256K1 {
return address.Undef, fmt.Errorf("given address was not a key addr") return address.Undef, fmt.Errorf("given address was not a key addr")
} }
return addr, nil return addr, nil
} }
func (tma *testMpoolAPI) MessagesForBlock(h *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) { func (tma *testMpoolApi) MessagesForBlock(h *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) {
return nil, tma.bmsgs[h.Cid()], nil return nil, tma.bmsgs[h.Cid()], nil
} }
func (tma *testMpoolAPI) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, error) { func (tma *testMpoolApi) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, error) {
if len(ts.Blocks()) != 1 { if len(ts.Blocks()) != 1 {
panic("cant deal with multiblock tipsets in this test") panic("cant deal with multiblock tipsets in this test")
} }
@@ -108,7 +108,7 @@ func (tma *testMpoolAPI) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg,
return out, nil return out, nil
} }
func (tma *testMpoolAPI) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) { func (tma *testMpoolApi) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) {
for _, ts := range tma.tipsets { for _, ts := range tma.tipsets {
if types.CidArrsEqual(tsk.Cids(), ts.Cids()) { if types.CidArrsEqual(tsk.Cids(), ts.Cids()) {
return ts, nil return ts, nil
@@ -138,7 +138,7 @@ func mustAdd(t *testing.T, mp *MessagePool, msg *types.SignedMessage) {
} }
func TestMessagePool(t *testing.T) { func TestMessagePool(t *testing.T) {
tma := newTestMpoolAPI() tma := newTestMpoolApi()
w, err := wallet.NewWallet(wallet.NewMemKeyStore()) w, err := wallet.NewWallet(wallet.NewMemKeyStore())
if err != nil { if err != nil {
@@ -179,7 +179,7 @@ func TestMessagePool(t *testing.T) {
} }
func TestRevertMessages(t *testing.T) { func TestRevertMessages(t *testing.T) {
tma := newTestMpoolAPI() tma := newTestMpoolApi()
w, err := wallet.NewWallet(wallet.NewMemKeyStore()) w, err := wallet.NewWallet(wallet.NewMemKeyStore())
if err != nil { if err != nil {
+2 -2
View File
@@ -21,7 +21,7 @@ import (
var log = logging.Logger("statetree") var log = logging.Logger("statetree")
// StateTree stores actors state by their ID. // Stores actors state by their ID.
type StateTree struct { type StateTree struct {
root *hamt.Node root *hamt.Node
Store cbor.IpldStore Store cbor.IpldStore
@@ -149,7 +149,7 @@ func (st *StateTree) SetActor(addr address.Address, act *types.Actor) error {
return nil return nil
} }
// LookupID gets the ID address of this actor's `addr` stored in the `InitActor`. // `LookupID` gets the ID address of this actor's `addr` stored in the `InitActor`.
func (st *StateTree) LookupID(addr address.Address) (address.Address, error) { func (st *StateTree) LookupID(addr address.Address) (address.Address, error) {
if addr.Protocol() == address.ID { if addr.Protocol() == address.ID {
return addr, nil return addr, nil
+5 -5
View File
@@ -62,11 +62,11 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate
} }
return &api.InvocResult{ return &api.InvocResult{
Msg: msg, Msg: msg,
MsgRct: &ret.MessageReceipt, MsgRct: &ret.MessageReceipt,
ExecutionTrace: ret.ExecutionTrace, InternalExecutions: ret.InternalExecutions,
Error: errs, Error: errs,
Duration: ret.Duration, Duration: ret.Duration,
}, nil }, nil
} }
+2 -2
View File
@@ -37,8 +37,8 @@ import (
) )
func init() { func init() {
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
abi.RegisteredSealProof_StackedDrg2KiBV1: {}, abi.RegisteredProof_StackedDRG2KiBSeal: {},
} }
power.ConsensusMinerMinPower = big.NewInt(2048) power.ConsensusMinerMinPower = big.NewInt(2048)
verifreg.MinVerifiedDealSize = big.NewInt(256) verifreg.MinVerifiedDealSize = big.NewInt(256)
+19 -49
View File
@@ -121,10 +121,10 @@ func (sm *StateManager) ExecutionTrace(ctx context.Context, ts *types.TipSet) (c
var trace []*api.InvocResult var trace []*api.InvocResult
st, _, err := sm.computeTipSetState(ctx, ts.Blocks(), func(mcid cid.Cid, msg *types.Message, ret *vm.ApplyRet) error { st, _, err := sm.computeTipSetState(ctx, ts.Blocks(), func(mcid cid.Cid, msg *types.Message, ret *vm.ApplyRet) error {
ir := &api.InvocResult{ ir := &api.InvocResult{
Msg: msg, Msg: msg,
MsgRct: &ret.MessageReceipt, MsgRct: &ret.MessageReceipt,
ExecutionTrace: ret.ExecutionTrace, InternalExecutions: ret.InternalExecutions,
Duration: ret.Duration, Duration: ret.Duration,
} }
if ret.ActorErr != nil { if ret.ActorErr != nil {
ir.Error = ret.ActorErr.Error() ir.Error = ret.ActorErr.Error()
@@ -184,9 +184,10 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, pstate cid.Cid, bms []B
var err error var err error
params, err := actors.SerializeParams(&reward.AwardBlockRewardParams{ params, err := actors.SerializeParams(&reward.AwardBlockRewardParams{
Miner: b.Miner, Miner: b.Miner,
Penalty: penalty, Penalty: penalty,
GasReward: gasReward, GasReward: gasReward,
TicketCount: 1, // TODO: no longer need ticket count here.
}) })
if err != nil { if err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("failed to serialize award params: %w", err) return cid.Undef, cid.Undef, xerrors.Errorf("failed to serialize award params: %w", err)
@@ -325,7 +326,7 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.Bl
blkmsgs = append(blkmsgs, bm) blkmsgs = append(blkmsgs, bm)
} }
return sm.ApplyBlocks(ctx, pstate, blkmsgs, blks[0].Height, r, cb) return sm.ApplyBlocks(ctx, pstate, blkmsgs, abi.ChainEpoch(blks[0].Height), r, cb)
} }
func (sm *StateManager) parentState(ts *types.TipSet) cid.Cid { func (sm *StateManager) parentState(ts *types.TipSet) cid.Cid {
@@ -404,8 +405,8 @@ func (sm *StateManager) LoadActorStateRaw(ctx context.Context, a address.Address
return act, nil return act, nil
} }
// ResolveToKeyAddress is similar to `vm.ResolveToKeyAddr` but does not allow `Actor` type of addresses. // Similar to `vm.ResolveToKeyAddr` but does not allow `Actor` type of addresses. Uses the `TipSet` `ts`
// Uses the `TipSet` `ts` to generate the VM state. // to generate the VM state.
func (sm *StateManager) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { func (sm *StateManager) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
switch addr.Protocol() { switch addr.Protocol() {
case address.BLS, address.SECP256K1: case address.BLS, address.SECP256K1:
@@ -479,10 +480,7 @@ func (sm *StateManager) GetReceipt(ctx context.Context, msg cid.Cid, ts *types.T
return r, nil return r, nil
} }
// WaitForMessage blocks until a message appears on chain. It looks backwards in the chain to see if this has already func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid) (*types.TipSet, *types.MessageReceipt, error) {
// happened. It guarantees that the message has been on chain for at least confidence epochs without being reverted
// before returning.
func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confidence uint64) (*types.TipSet, *types.MessageReceipt, error) {
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
defer cancel() defer cancel()
@@ -530,11 +528,6 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confid
close(backSearchWait) close(backSearchWait)
}() }()
var candidateTs *types.TipSet
var candidateRcp *types.MessageReceipt
heightOfHead := head[0].Val.Height()
reverts := map[types.TipSetKey]bool{}
for { for {
select { select {
case notif, ok := <-tsub: case notif, ok := <-tsub:
@@ -544,44 +537,21 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confid
for _, val := range notif { for _, val := range notif {
switch val.Type { switch val.Type {
case store.HCRevert: case store.HCRevert:
if val.Val.Equals(candidateTs) { continue
candidateTs = nil
candidateRcp = nil
}
if backSearchWait != nil {
reverts[val.Val.Key()] = true
}
case store.HCApply: case store.HCApply:
if candidateTs != nil && val.Val.Height() >= candidateTs.Height()+abi.ChainEpoch(confidence) {
return candidateTs, candidateRcp, nil
}
r, err := sm.tipsetExecutedMessage(val.Val, mcid, msg.VMMessage()) r, err := sm.tipsetExecutedMessage(val.Val, mcid, msg.VMMessage())
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
if r != nil { if r != nil {
if confidence == 0 { return val.Val, r, nil
return val.Val, r, err
}
candidateTs = val.Val
candidateRcp = r
} }
heightOfHead = val.Val.Height()
} }
} }
case <-backSearchWait: case <-backSearchWait:
// check if we found the message in the chain and that is hasn't been reverted since we started searching if backTs != nil {
if backTs != nil && !reverts[backTs.Key()] { return backTs, backRcp, nil
// if head is at or past confidence interval, return immediately
if heightOfHead >= backTs.Height()+abi.ChainEpoch(confidence) {
return backTs, backRcp, nil
}
// wait for confidence interval
candidateTs = backTs
candidateRcp = backRcp
} }
reverts = nil
backSearchWait = nil backSearchWait = nil
case <-ctx.Done(): case <-ctx.Done():
return nil, nil, ctx.Err() return nil, nil, ctx.Err()
@@ -640,9 +610,9 @@ func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet
return nil, nil, err return nil, nil, err
} }
// we either have no messages from the sender, or the latest message we found has a lower nonce than the one being searched for, if act.Nonce < m.VMMessage().Nonce {
// either way, no reason to lookback, it ain't there // nonce on chain is before message nonce we're looking for, its
if act.Nonce == 0 || act.Nonce < m.VMMessage().Nonce { // not going to be here
return nil, nil, nil return nil, nil, nil
} }
+12 -115
View File
@@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"context" "context"
"os" "os"
"reflect"
cid "github.com/ipfs/go-cid" cid "github.com/ipfs/go-cid"
blockstore "github.com/ipfs/go-ipfs-blockstore" blockstore "github.com/ipfs/go-ipfs-blockstore"
@@ -14,20 +13,13 @@ import (
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
amt "github.com/filecoin-project/go-amt-ipld/v2" 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/sector-storage/ffiwrapper"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin" "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" 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/market"
"github.com/filecoin-project/specs-actors/actors/builtin/miner" "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/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/crypto"
"github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/specs-actors/actors/util/adt"
@@ -45,7 +37,7 @@ func GetNetworkName(ctx context.Context, sm *StateManager, st cid.Cid) (dtypes.N
var state init_.State var state init_.State
_, err := sm.LoadActorStateRaw(ctx, builtin.InitActorAddr, &state, st) _, err := sm.LoadActorStateRaw(ctx, builtin.InitActorAddr, &state, st)
if err != nil { if err != nil {
return "", xerrors.Errorf("(get sset) failed to load init actor state: %w", err) return "", xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
} }
return dtypes.NetworkName(state.NetworkName), nil return dtypes.NetworkName(state.NetworkName), nil
@@ -181,34 +173,13 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S
return nil, xerrors.Errorf("(get sectors) failed to load miner actor state: %w", err) return nil, xerrors.Errorf("(get sectors) failed to load miner actor state: %w", err)
} }
cst := cbor.NewCborStore(sm.cs.Blockstore()) // TODO: Optimization: we could avoid loaditg the whole proving set here if we had AMT.GetNth with bitfield filtering
var deadlines miner.Deadlines sectorSet, err := GetProvingSetRaw(ctx, sm, mas)
if err := cst.Get(ctx, mas.Deadlines, &deadlines); err != nil {
return nil, xerrors.Errorf("failed to load deadlines: %w", err)
}
notProving, err := abi.BitFieldUnion(mas.Faults, mas.Recoveries)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to union faults and recoveries: %w", err) return nil, xerrors.Errorf("getting proving set: %w", err)
} }
allSectors, err := bitfield.MultiMerge(append(deadlines.Due[:], mas.NewSectors)...) if len(sectorSet) == 0 {
if err != nil {
return nil, xerrors.Errorf("merging deadline bitfields failed: %w", err)
}
provingSectors, err := bitfield.SubtractBitField(allSectors, notProving)
if err != nil {
return nil, xerrors.Errorf("failed to subtract non-proving sectors from set: %w", err)
}
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 return nil, nil
} }
@@ -227,34 +198,17 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S
return nil, xerrors.Errorf("getting miner ID: %w", err) return nil, xerrors.Errorf("getting miner ID: %w", err)
} }
ids, err := pv.GenerateWinningPoStSectorChallenge(ctx, wpt, abi.ActorID(mid), rand, numProvSect) ids, err := pv.GenerateWinningPoStSectorChallenge(ctx, wpt, abi.ActorID(mid), rand, uint64(len(sectorSet)))
if err != nil { if err != nil {
return nil, xerrors.Errorf("generating winning post challenges: %w", err) 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, cst, mas.Sectors)
if err != nil {
return nil, xerrors.Errorf("failed to load sectors amt: %w", err)
}
out := make([]abi.SectorInfo, len(ids)) out := make([]abi.SectorInfo, len(ids))
for i, n := range 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{ out[i] = abi.SectorInfo{
SealProof: spt, RegisteredProof: wpt,
SectorNumber: sinfo.Info.SectorNumber, SectorNumber: sectorSet[n].ID,
SealedCID: sinfo.Info.SealedCID, SealedCID: sectorSet[n].Info.Info.SealedCID,
} }
} }
@@ -332,7 +286,7 @@ func GetMinerRecoveries(ctx context.Context, sm *StateManager, ts *types.TipSet,
return mas.Recoveries, nil return mas.Recoveries, nil
} }
func GetStorageDeal(ctx context.Context, sm *StateManager, dealID abi.DealID, ts *types.TipSet) (*api.MarketDeal, error) { func GetStorageDeal(ctx context.Context, sm *StateManager, dealId abi.DealID, ts *types.TipSet) (*api.MarketDeal, error) {
var state market.State var state market.State
if _, err := sm.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil { if _, err := sm.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil {
return nil, err return nil, err
@@ -344,7 +298,7 @@ func GetStorageDeal(ctx context.Context, sm *StateManager, dealID abi.DealID, ts
} }
var dp market.DealProposal var dp market.DealProposal
if err := da.Get(ctx, uint64(dealID), &dp); err != nil { if err := da.Get(ctx, uint64(dealId), &dp); err != nil {
return nil, err return nil, err
} }
@@ -353,7 +307,7 @@ func GetStorageDeal(ctx context.Context, sm *StateManager, dealID abi.DealID, ts
return nil, err return nil, err
} }
st, found, err := sa.Get(dealID) st, found, err := sa.Get(dealId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -585,60 +539,3 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBe
BeaconEntries: entries, BeaconEntries: entries,
}, nil }, 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) {
act, err := sm.GetActor(to, ts)
if err != nil {
return nil, err
}
m := MethodsMap[act.Code][method]
return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil
}
-3
View File
@@ -32,11 +32,8 @@ func (fts *FullTipSet) Cids() []cid.Cid {
return cids return cids
} }
// TipSet returns a narrower view of this FullTipSet elliding the block
// messages.
func (fts *FullTipSet) TipSet() *types.TipSet { func (fts *FullTipSet) TipSet() *types.TipSet {
if fts.tipset != nil { if fts.tipset != nil {
// FIXME: fts.tipset is actually never set. Should it memoize?
return fts.tipset return fts.tipset
} }
-161
View File
@@ -1,161 +0,0 @@
package store
import (
"context"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/specs-actors/actors/abi"
lru "github.com/hashicorp/golang-lru"
"golang.org/x/xerrors"
)
type ChainIndex struct {
skipCache *lru.ARCCache
loadTipSet loadTipSetFunc
skipLength abi.ChainEpoch
}
type loadTipSetFunc func(types.TipSetKey) (*types.TipSet, error)
func NewChainIndex(lts loadTipSetFunc) *ChainIndex {
sc, _ := lru.NewARC(8192)
return &ChainIndex{
skipCache: sc,
loadTipSet: lts,
skipLength: 20,
}
}
type lbEntry struct {
ts *types.TipSet
parentHeight abi.ChainEpoch
targetHeight abi.ChainEpoch
target types.TipSetKey
}
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)
}
rounded, err := ci.roundDown(from)
if err != nil {
return nil, err
}
cur := rounded.Key()
for {
cval, ok := ci.skipCache.Get(cur)
if !ok {
fc, err := ci.fillCache(cur)
if err != nil {
return nil, err
}
cval = fc
}
lbe := cval.(*lbEntry)
if lbe.ts.Height() == to || lbe.parentHeight < to {
return lbe.ts, nil
} else if to > lbe.targetHeight {
return ci.walkBack(lbe.ts, to)
}
cur = lbe.target
}
}
func (ci *ChainIndex) GetTipsetByHeightWithoutCache(from *types.TipSet, to abi.ChainEpoch) (*types.TipSet, error) {
return ci.walkBack(from, to)
}
func (ci *ChainIndex) fillCache(tsk types.TipSetKey) (*lbEntry, error) {
ts, err := ci.loadTipSet(tsk)
if err != nil {
return nil, err
}
if ts.Height() == 0 {
return &lbEntry{
ts: ts,
parentHeight: 0,
}, nil
}
// will either be equal to ts.Height, or at least > ts.Parent.Height()
rheight := ci.roundHeight(ts.Height())
parent, err := ci.loadTipSet(ts.Parents())
if err != nil {
return nil, err
}
rheight -= ci.skipLength
var skipTarget *types.TipSet
if parent.Height() < rheight {
skipTarget = parent
} else {
skipTarget, err = ci.walkBack(parent, rheight)
if err != nil {
return nil, xerrors.Errorf("fillCache walkback: %w", err)
}
}
lbe := &lbEntry{
ts: ts,
parentHeight: parent.Height(),
targetHeight: skipTarget.Height(),
target: skipTarget.Key(),
}
ci.skipCache.Add(tsk, lbe)
return lbe, nil
}
// floors to nearest skipLength multiple
func (ci *ChainIndex) roundHeight(h abi.ChainEpoch) abi.ChainEpoch {
return (h / ci.skipLength) * ci.skipLength
}
func (ci *ChainIndex) roundDown(ts *types.TipSet) (*types.TipSet, error) {
target := ci.roundHeight(ts.Height())
rounded, err := ci.walkBack(ts, target)
if err != nil {
return nil, err
}
return rounded, nil
}
func (ci *ChainIndex) walkBack(from *types.TipSet, to abi.ChainEpoch) (*types.TipSet, error) {
if to > from.Height() {
return nil, xerrors.Errorf("looking for tipset with height greater than start point")
}
if to == from.Height() {
return from, nil
}
ts := from
for {
pts, err := ci.loadTipSet(ts.Parents())
if err != nil {
return nil, err
}
if to > pts.Height() {
// in case pts is lower than the epoch we're looking for (null blocks)
// return a tipset above that height
return ts, nil
}
if to == pts.Height() {
return pts, nil
}
ts = pts
}
}
-80
View File
@@ -1,80 +0,0 @@
package store_test
import (
"bytes"
"context"
"testing"
"github.com/filecoin-project/lotus/chain/gen"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types/mock"
"github.com/filecoin-project/specs-actors/actors/abi"
datastore "github.com/ipfs/go-datastore"
syncds "github.com/ipfs/go-datastore/sync"
blockstore "github.com/ipfs/go-ipfs-blockstore"
"github.com/stretchr/testify/assert"
)
func TestIndexSeeks(t *testing.T) {
cg, err := gen.NewGenerator()
if err != nil {
t.Fatal(err)
}
gencar, err := cg.GenesisCar()
if err != nil {
t.Fatal(err)
}
gen := cg.Genesis()
ctx := context.TODO()
nbs := blockstore.NewBlockstore(syncds.MutexWrap(datastore.NewMapDatastore()))
cs := store.NewChainStore(nbs, syncds.MutexWrap(datastore.NewMapDatastore()), nil)
_, err = cs.Import(bytes.NewReader(gencar))
if err != nil {
t.Fatal(err)
}
cur := mock.TipSet(gen)
if err := cs.PutTipSet(ctx, mock.TipSet(gen)); err != nil {
t.Fatal(err)
}
cs.SetGenesis(gen)
// Put 113 blocks from genesis
for i := 0; i < 113; i++ {
nextts := mock.TipSet(mock.MkBlock(cur, 1, 1))
if err := cs.PutTipSet(ctx, nextts); err != nil {
t.Fatal(err)
}
cur = nextts
}
// Put 50 null epochs + 1 block
skip := mock.MkBlock(cur, 1, 1)
skip.Height += 50
skipts := mock.TipSet(skip)
if err := cs.PutTipSet(ctx, skipts); err != nil {
t.Fatal(err)
}
ts, err := cs.GetTipsetByHeight(ctx, skip.Height-10, skipts, false)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, abi.ChainEpoch(164), ts.Height())
for i := 0; i <= 113; i++ {
ts3, err := cs.GetTipsetByHeight(ctx, abi.ChainEpoch(i), skipts, false)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, abi.ChainEpoch(i), ts3.Height())
}
}
+47 -105
View File
@@ -18,9 +18,9 @@ import (
"github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/chain/vm"
"github.com/filecoin-project/lotus/journal"
"github.com/filecoin-project/lotus/metrics" "github.com/filecoin-project/lotus/metrics"
"go.opencensus.io/stats" "go.opencensus.io/stats"
"go.opencensus.io/trace" "go.opencensus.io/trace"
@@ -48,20 +48,7 @@ import (
var log = logging.Logger("chainstore") var log = logging.Logger("chainstore")
var chainHeadKey = dstore.NewKey("head") 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 { type ChainStore struct {
bs bstore.Blockstore bs bstore.Blockstore
ds dstore.Datastore ds dstore.Datastore
@@ -75,10 +62,8 @@ type ChainStore struct {
tstLk sync.Mutex tstLk sync.Mutex
tipsets map[abi.ChainEpoch][]cid.Cid tipsets map[abi.ChainEpoch][]cid.Cid
cindex *ChainIndex reorgCh chan<- reorg
headChangeNotifs []func(rev, app []*types.TipSet) error
reorgCh chan<- reorg
reorgNotifeeCh chan ReorgNotifee
mmCache *lru.ARCCache mmCache *lru.ARCCache
tsCache *lru.ARCCache tsCache *lru.ARCCache
@@ -99,9 +84,7 @@ func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls runtime.Sys
vmcalls: vmcalls, vmcalls: vmcalls,
} }
ci := NewChainIndex(cs.LoadTipSet) cs.reorgCh = cs.reorgWorker(context.TODO())
cs.cindex = ci
hcnf := func(rev, app []*types.TipSet) error { hcnf := func(rev, app []*types.TipSet) error {
cs.pubLk.Lock() cs.pubLk.Lock()
@@ -134,8 +117,7 @@ func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls runtime.Sys
return nil return nil
} }
cs.reorgNotifeeCh = make(chan ReorgNotifee) cs.headChangeNotifs = append(cs.headChangeNotifs, hcnf, hcmetric)
cs.reorgCh = cs.reorgWorker(context.TODO(), []ReorgNotifee{hcnf, hcmetric})
return cs return cs
} }
@@ -224,24 +206,8 @@ func (cs *ChainStore) SubHeadChanges(ctx context.Context) chan []*api.HeadChange
return out return out
} }
func (cs *ChainStore) SubscribeHeadChanges(f ReorgNotifee) { func (cs *ChainStore) SubscribeHeadChanges(f func(rev, app []*types.TipSet) error) {
cs.reorgNotifeeCh <- f cs.headChangeNotifs = append(cs.headChangeNotifs, 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 { func (cs *ChainStore) SetGenesis(b *types.BlockHeader) error {
@@ -276,9 +242,6 @@ func (cs *ChainStore) PutTipSet(ctx context.Context, ts *types.TipSet) error {
return nil 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 { func (cs *ChainStore) MaybeTakeHeavierTipSet(ctx context.Context, ts *types.TipSet) error {
cs.heaviestLk.Lock() cs.heaviestLk.Lock()
defer cs.heaviestLk.Unlock() defer cs.heaviestLk.Unlock()
@@ -305,19 +268,13 @@ type reorg struct {
new *types.TipSet new *types.TipSet
} }
func (cs *ChainStore) reorgWorker(ctx context.Context, initialNotifees []ReorgNotifee) chan<- reorg { func (cs *ChainStore) reorgWorker(ctx context.Context) chan<- reorg {
out := make(chan reorg, 32) out := make(chan reorg, 32)
notifees := make([]ReorgNotifee, len(initialNotifees))
copy(notifees, initialNotifees)
go func() { go func() {
defer log.Warn("reorgWorker quit") defer log.Warn("reorgWorker quit")
for { for {
select { select {
case n := <-cs.reorgNotifeeCh:
notifees = append(notifees, n)
case r := <-out: case r := <-out:
revert, apply, err := cs.ReorgOps(r.old, r.new) revert, apply, err := cs.ReorgOps(r.old, r.new)
if err != nil { if err != nil {
@@ -325,21 +282,13 @@ func (cs *ChainStore) reorgWorker(ctx context.Context, initialNotifees []ReorgNo
continue 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 // reverse the apply array
for i := len(apply)/2 - 1; i >= 0; i-- { for i := len(apply)/2 - 1; i >= 0; i-- {
opp := len(apply) - 1 - i opp := len(apply) - 1 - i
apply[i], apply[opp] = apply[opp], apply[i] apply[i], apply[opp] = apply[opp], apply[i]
} }
for _, hcf := range notifees { for _, hcf := range cs.headChangeNotifs {
if err := hcf(revert, apply); err != nil { if err := hcf(revert, apply); err != nil {
log.Error("head change func errored (BAD): ", err) log.Error("head change func errored (BAD): ", err)
} }
@@ -352,9 +301,6 @@ func (cs *ChainStore) reorgWorker(ctx context.Context, initialNotifees []ReorgNo
return out 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 { func (cs *ChainStore) takeHeaviestTipSet(ctx context.Context, ts *types.TipSet) error {
_, span := trace.StartSpan(ctx, "takeHeaviestTipSet") _, span := trace.StartSpan(ctx, "takeHeaviestTipSet")
defer span.End() defer span.End()
@@ -392,7 +338,6 @@ func (cs *ChainStore) SetHead(ts *types.TipSet) error {
return cs.takeHeaviestTipSet(context.TODO(), ts) 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) { func (cs *ChainStore) Contains(ts *types.TipSet) (bool, error) {
for _, c := range ts.Cids() { for _, c := range ts.Cids() {
has, err := cs.bs.Has(c) has, err := cs.bs.Has(c)
@@ -407,8 +352,6 @@ func (cs *ChainStore) Contains(ts *types.TipSet) (bool, error) {
return true, nil 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) { func (cs *ChainStore) GetBlock(c cid.Cid) (*types.BlockHeader, error) {
sb, err := cs.bs.Get(c) sb, err := cs.bs.Get(c)
if err != nil { if err != nil {
@@ -444,7 +387,7 @@ func (cs *ChainStore) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) {
return ts, nil return ts, nil
} }
// IsAncestorOf returns true if 'a' is an ancestor of 'b' // returns true if 'a' is an ancestor of 'b'
func (cs *ChainStore) IsAncestorOf(a, b *types.TipSet) (bool, error) { func (cs *ChainStore) IsAncestorOf(a, b *types.TipSet) (bool, error) {
if b.Height() <= a.Height() { if b.Height() <= a.Height() {
return false, nil return false, nil
@@ -501,7 +444,6 @@ func (cs *ChainStore) ReorgOps(a, b *types.TipSet) ([]*types.TipSet, []*types.Ti
return leftChain, rightChain, nil return leftChain, rightChain, nil
} }
// GetHeaviestTipSet returns the current heaviest tipset known (i.e. our head).
func (cs *ChainStore) GetHeaviestTipSet() *types.TipSet { func (cs *ChainStore) GetHeaviestTipSet() *types.TipSet {
cs.heaviestLk.Lock() cs.heaviestLk.Lock()
defer cs.heaviestLk.Unlock() defer cs.heaviestLk.Unlock()
@@ -968,35 +910,30 @@ func DrawRandomness(rbase []byte, pers crypto.DomainSeparationTag, round abi.Cha
return h.Sum(nil), nil return h.Sum(nil), nil
} }
func (cs *ChainStore) GetRandomness(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { func (cs *ChainStore) GetRandomness(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) (out []byte, err error) {
_, span := trace.StartSpan(ctx, "store.GetRandomness") _, span := trace.StartSpan(ctx, "store.GetRandomness")
defer span.End() defer span.End()
span.AddAttributes(trace.Int64Attribute("round", int64(round))) span.AddAttributes(trace.Int64Attribute("round", int64(round)))
ts, err := cs.LoadTipSet(types.NewTipSetKey(blks...)) //defer func() {
if err != nil { //log.Infof("getRand %v %d %d %x -> %x", blks, pers, round, entropy, out)
return nil, err //}()
for {
nts, err := cs.LoadTipSet(types.NewTipSetKey(blks...))
if err != nil {
return nil, err
}
mtb := nts.MinTicketBlock()
// if at (or just past -- for null epochs) appropriate epoch
// or at genesis (works for negative epochs)
if nts.Height() <= round || mtb.Height == 0 {
return DrawRandomness(nts.MinTicketBlock().Ticket.VRFProof, pers, round, entropy)
}
blks = mtb.Parents
} }
if round > ts.Height() {
return nil, xerrors.Errorf("cannot draw randomness from the future")
}
searchHeight := round
if searchHeight < 0 {
searchHeight = 0
}
randTs, err := cs.GetTipsetByHeight(ctx, searchHeight, ts, true)
if err != nil {
return nil, err
}
mtb := randTs.MinTicketBlock()
// if at (or just past -- for null epochs) appropriate epoch
// or at genesis (works for negative epochs)
return DrawRandomness(mtb.Ticket.VRFProof, pers, round, entropy)
} }
// GetTipsetByHeight returns the tipset on the chain behind 'ts' at the given // GetTipsetByHeight returns the tipset on the chain behind 'ts' at the given
@@ -1009,31 +946,35 @@ func (cs *ChainStore) GetTipsetByHeight(ctx context.Context, h abi.ChainEpoch, t
} }
if h > ts.Height() { if h > ts.Height() {
return nil, xerrors.Errorf("looking for tipset with height greater than start point") return nil, xerrors.Errorf("looking for tipset with height less than start point")
} }
if h == ts.Height() { if h == ts.Height() {
return ts, nil return ts, nil
} }
lbts, err := cs.cindex.GetTipsetByHeight(ctx, ts, h) if ts.Height()-h > build.ForkLengthThreshold {
if err != nil { log.Warnf("expensive call to GetTipsetByHeight, seeking %d levels", ts.Height()-h)
return nil, err
} }
if lbts.Height() < h { for {
log.Warnf("chain index returned the wrong tipset at height %d, using slow retrieval", h) pts, err := cs.LoadTipSet(ts.Parents())
lbts, err = cs.cindex.GetTipsetByHeightWithoutCache(ts, h)
if err != nil { if err != nil {
return nil, err return nil, err
} }
}
if lbts.Height() == h || !prev { if h > pts.Height() {
return lbts, nil if prev {
} return pts, nil
}
return ts, nil
}
if h == pts.Height() {
return pts, nil
}
return cs.LoadTipSet(lbts.Parents()) ts = pts
}
} }
func recurseLinks(bs blockstore.Blockstore, root cid.Cid, in []cid.Cid) ([]cid.Cid, error) { func recurseLinks(bs blockstore.Blockstore, root cid.Cid, in []cid.Cid) ([]cid.Cid, error) {
@@ -1213,6 +1154,7 @@ func (cr *chainRand) GetRandomness(ctx context.Context, pers crypto.DomainSepara
func (cs *ChainStore) GetTipSetFromKey(tsk types.TipSetKey) (*types.TipSet, error) { func (cs *ChainStore) GetTipSetFromKey(tsk types.TipSetKey) (*types.TipSet, error) {
if tsk.IsEmpty() { if tsk.IsEmpty() {
return cs.GetHeaviestTipSet(), nil return cs.GetHeaviestTipSet(), nil
} else {
return cs.LoadTipSet(tsk)
} }
return cs.LoadTipSet(tsk)
} }
+2 -2
View File
@@ -22,8 +22,8 @@ import (
) )
func init() { func init() {
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
abi.RegisteredSealProof_StackedDrg2KiBV1: {}, abi.RegisteredProof_StackedDRG2KiBSeal: {},
} }
power.ConsensusMinerMinPower = big.NewInt(2048) power.ConsensusMinerMinPower = big.NewInt(2048)
verifreg.MinVerifiedDealSize = big.NewInt(256) verifreg.MinVerifiedDealSize = big.NewInt(256)
+7 -3
View File
@@ -57,9 +57,12 @@ func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *cha
return return
} }
src := msg.GetFrom() //nolint:golint
src := peer.ID(msg.GetFrom())
go func() { go func() {
log.Infof("New block over pubsub: %s", blk.Cid())
start := time.Now() start := time.Now()
log.Debug("about to fetch messages for block from pubsub") log.Debug("about to fetch messages for block from pubsub")
bmsgs, err := s.Bsync.FetchMessagesByCids(context.TODO(), blk.BlsMessages) bmsgs, err := s.Bsync.FetchMessagesByCids(context.TODO(), blk.BlsMessages)
@@ -143,7 +146,8 @@ func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub
// track validation time // track validation time
begin := time.Now() begin := time.Now()
defer func() { defer func() {
log.Debugf("block validation time: %s", time.Since(begin)) end := time.Now()
log.Infof("block validation time: %s", end.Sub(begin))
}() }()
stats.Record(ctx, metrics.BlockReceived.M(1)) stats.Record(ctx, metrics.BlockReceived.M(1))
@@ -203,7 +207,7 @@ func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub
} }
} }
err = sigs.CheckBlockSignature(ctx, blk.Header, key) err = sigs.CheckBlockSignature(blk.Header, ctx, key)
if err != nil { if err != nil {
log.Errorf("block signature verification failed: %s", err) log.Errorf("block signature verification failed: %s", err)
recordFailure("signature_verification_failed") recordFailure("signature_verification_failed")
+80 -245
View File
@@ -8,6 +8,7 @@ import (
"os" "os"
"sort" "sort"
"strings" "strings"
"sync"
"time" "time"
"github.com/Gurpartap/async" "github.com/Gurpartap/async"
@@ -49,37 +50,10 @@ import (
"github.com/filecoin-project/lotus/metrics" "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 log = logging.Logger("chain")
var LocalIncoming = "incoming" 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 hasnt deviated one finality
// threshold from our head (900 epochs, parameter determined by spec-actors)".
type Syncer struct { type Syncer struct {
// The interface for accessing and putting tipsets into local storage // The interface for accessing and putting tipsets into local storage
store *store.ChainStore store *store.ChainStore
@@ -112,7 +86,6 @@ type Syncer struct {
verifier ffiwrapper.Verifier 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) { 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() gen, err := sm.ChainStore().GetGenesis()
if err != nil { if err != nil {
@@ -161,11 +134,6 @@ func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
return false 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 { for _, b := range fts.Blocks {
if reason, ok := syncer.bad.Has(b.Cid()); ok { if reason, ok := syncer.bad.Has(b.Cid()); ok {
log.Warnf("InformNewHead called on block marked as bad: %s (reason: %s)", b.Cid(), reason) log.Warnf("InformNewHead called on block marked as bad: %s (reason: %s)", b.Cid(), reason)
@@ -215,11 +183,6 @@ func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
return true 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) { func (syncer *Syncer) IncomingBlocks(ctx context.Context) (<-chan *types.BlockHeader, error) {
sub := syncer.incoming.Sub(LocalIncoming) sub := syncer.incoming.Sub(LocalIncoming)
out := make(chan *types.BlockHeader, 10) out := make(chan *types.BlockHeader, 10)
@@ -247,15 +210,11 @@ func (syncer *Syncer) IncomingBlocks(ctx context.Context) (<-chan *types.BlockHe
return out, nil 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 { func (syncer *Syncer) ValidateMsgMeta(fblk *types.FullBlock) error {
if msgc := len(fblk.BlsMessages) + len(fblk.SecpkMessages); msgc > build.BlockMessageLimit { 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) 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 var bcids, scids []cbg.CBORMarshaler
for _, m := range fblk.BlsMessages { for _, m := range fblk.BlsMessages {
c := cbg.CborCid(m.Cid()) c := cbg.CborCid(m.Cid())
@@ -273,14 +232,11 @@ func (syncer *Syncer) ValidateMsgMeta(fblk *types.FullBlock) error {
blockstore := syncer.store.Blockstore() blockstore := syncer.store.Blockstore()
bs := cbor.NewCborStore(blockstore) bs := cbor.NewCborStore(blockstore)
// Compute the root CID of the combined message trie.
smroot, err := computeMsgMeta(bs, bcids, scids) smroot, err := computeMsgMeta(bs, bcids, scids)
if err != nil { if err != nil {
return xerrors.Errorf("validating msgmeta, compute failed: %w", err) 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 { 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) return xerrors.Errorf("messages in full block did not match msgmeta root in header (%s != %s)", fblk.Header.Messages, smroot)
} }
@@ -349,10 +305,6 @@ func zipTipSetAndMessages(bs cbor.IpldStore, ts *types.TipSet, allbmsgs []*types
fts := &store.FullTipSet{} fts := &store.FullTipSet{}
for bi, b := range ts.Blocks() { 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 smsgs []*types.SignedMessage
var smsgCids []cbg.CBORMarshaler var smsgCids []cbg.CBORMarshaler
for _, m := range smi[bi] { for _, m := range smi[bi] {
@@ -369,6 +321,10 @@ func zipTipSetAndMessages(bs cbor.IpldStore, ts *types.TipSet, allbmsgs []*types
bmsgCids = append(bmsgCids, &c) 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) mrcid, err := computeMsgMeta(bs, bmsgCids, smsgCids)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -390,8 +346,6 @@ func zipTipSetAndMessages(bs cbor.IpldStore, ts *types.TipSet, allbmsgs []*types
return fts, nil 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) { func computeMsgMeta(bs cbor.IpldStore, bmsgCids, smsgCids []cbg.CBORMarshaler) (cid.Cid, error) {
ctx := context.TODO() ctx := context.TODO()
bmroot, err := amt.FromArray(ctx, bs, bmsgCids) bmroot, err := amt.FromArray(ctx, bs, bmsgCids)
@@ -415,24 +369,14 @@ func computeMsgMeta(bs cbor.IpldStore, bmsgCids, smsgCids []cbg.CBORMarshaler) (
return mrcid, nil 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) { func (syncer *Syncer) FetchTipSet(ctx context.Context, p peer.ID, tsk types.TipSetKey) (*store.FullTipSet, error) {
if fts, err := syncer.tryLoadFullTipSet(tsk); err == nil { if fts, err := syncer.tryLoadFullTipSet(tsk); err == nil {
return fts, nil return fts, nil
} }
// fall back to the network.
return syncer.Bsync.GetFullTipSet(ctx, p, tsk) 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) { func (syncer *Syncer) tryLoadFullTipSet(tsk types.TipSetKey) (*store.FullTipSet, error) {
ts, err := syncer.store.LoadTipSet(tsk) ts, err := syncer.store.LoadTipSet(tsk)
if err != nil { if err != nil {
@@ -457,12 +401,6 @@ func (syncer *Syncer) tryLoadFullTipSet(tsk types.TipSetKey) (*store.FullTipSet,
return fts, nil 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 { func (syncer *Syncer) Sync(ctx context.Context, maybeHead *types.TipSet) error {
ctx, span := trace.StartSpan(ctx, "chain.Sync") ctx, span := trace.StartSpan(ctx, "chain.Sync")
defer span.End() defer span.End()
@@ -491,8 +429,6 @@ func (syncer *Syncer) Sync(ctx context.Context, maybeHead *types.TipSet) error {
return xerrors.Errorf("collectChain failed: %w", err) return xerrors.Errorf("collectChain failed: %w", err)
} }
// At this point we have accepted and synced to the new `maybeHead`
// (`StageSyncComplete`).
if err := syncer.store.PutTipSet(ctx, maybeHead); err != nil { if err := syncer.store.PutTipSet(ctx, maybeHead); err != nil {
span.AddAttributes(trace.StringAttribute("put_error", err.Error())) span.AddAttributes(trace.StringAttribute("put_error", err.Error()))
span.SetStatus(trace.Status{ span.SetStatus(trace.Status{
@@ -529,27 +465,16 @@ func (syncer *Syncer) ValidateTipSet(ctx context.Context, fts *store.FullTipSet)
return nil return nil
} }
var futures []async.ErrorFuture
for _, b := range fts.Blocks { for _, b := range fts.Blocks {
b := b // rebind to a scoped variable if err := syncer.ValidateBlock(ctx, b); err != nil {
if isPermanent(err) {
futures = append(futures, async.Err(func() error { syncer.bad.Add(b.Cid(), err.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)
} }
return xerrors.Errorf("validating block %s: %w", b.Cid(), err)
}
if err := syncer.sm.ChainStore().AddToTipSetTracker(b.Header); err != nil { if err := syncer.sm.ChainStore().AddToTipSetTracker(b.Header); err != nil {
return xerrors.Errorf("failed to add validated header to tipset tracker: %w", err) 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 return nil
@@ -601,36 +526,10 @@ func blockSanityChecks(h *types.BlockHeader) error {
return nil return nil
} }
// ValidateBlock should match up with 'Semantical Validation' in validation.md in the spec // Should match up with 'Semantical Validation' in validation.md in the spec
func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (err error) { func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) 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 := time.Now()
defer func() {
dur := time.Since(validationStart)
durMilli := dur.Seconds() * float64(1000)
stats.Record(ctx, metrics.BlockValidationDurationMilliseconds.M(durMilli))
log.Infow("block validation", "took", dur, "height", b.Header.Height)
}()
ctx, span := trace.StartSpan(ctx, "validateBlock") ctx, span := trace.StartSpan(ctx, "validateBlock")
defer span.End() defer span.End()
if build.InsecurePoStValidation { 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 test validation is enabled, if you see this outside of a test, it is a severe bug!")
} }
@@ -666,18 +565,18 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
// fast checks first // fast checks first
now := uint64(time.Now().Unix()) now := uint64(time.Now().Unix())
if h.Timestamp > now+build.AllowableClockDriftSecs { if h.Timestamp > now+build.AllowableClockDrift {
return xerrors.Errorf("block was from the future (now=%d, blk=%d): %w", now, h.Timestamp, ErrTemporal) return xerrors.Errorf("block was from the future (now=%d, blk=%d): %w", now, h.Timestamp, ErrTemporal)
} }
if h.Timestamp > now { 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, time.Now().Unix())
} }
if h.Timestamp < baseTs.MinTimestamp()+(build.BlockDelaySecs*uint64(h.Height-baseTs.Height())) { if h.Timestamp < baseTs.MinTimestamp()+(build.BlockDelay*uint64(h.Height-baseTs.Height())) {
log.Warn("timestamp funtimes: ", h.Timestamp, baseTs.MinTimestamp(), h.Height, baseTs.Height()) log.Warn("timestamp funtimes: ", h.Timestamp, baseTs.MinTimestamp(), h.Height, baseTs.Height())
diff := (baseTs.MinTimestamp() + (build.BlockDelaySecs * uint64(h.Height-baseTs.Height()))) - h.Timestamp diff := (baseTs.MinTimestamp() + (build.BlockDelay * 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.BlockDelaySecs, 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.BlockDelay, h.Height-baseTs.Height(), diff)
} }
msgsCheck := async.Err(func() error { msgsCheck := async.Err(func() error {
@@ -740,7 +639,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
return xerrors.Errorf("could not draw randomness: %w", err) return xerrors.Errorf("could not draw randomness: %w", err)
} }
if err := VerifyElectionPoStVRF(ctx, waddr, vrfBase, h.ElectionProof.VRFProof); err != nil { if err := gen.VerifyVRF(ctx, waddr, vrfBase, h.ElectionProof.VRFProof); err != nil {
return xerrors.Errorf("validating block election proof failed: %w", err) return xerrors.Errorf("validating block election proof failed: %w", err)
} }
@@ -766,7 +665,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
}) })
blockSigCheck := async.Err(func() error { blockSigCheck := async.Err(func() error {
if err := sigs.CheckBlockSignature(ctx, h, waddr); err != nil { if err := sigs.CheckBlockSignature(h, ctx, waddr); err != nil {
return xerrors.Errorf("check block signature failed: %w", err) return xerrors.Errorf("check block signature failed: %w", err)
} }
return nil return nil
@@ -801,7 +700,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
return xerrors.Errorf("failed to compute vrf base for ticket: %w", err) return xerrors.Errorf("failed to compute vrf base for ticket: %w", err)
} }
err = VerifyElectionPoStVRF(ctx, waddr, vrfBase, h.Ticket.VRFProof) err = gen.VerifyVRF(ctx, waddr, vrfBase, h.Ticket.VRFProof)
if err != nil { if err != nil {
return xerrors.Errorf("validating block tickets failed: %w", err) return xerrors.Errorf("validating block tickets failed: %w", err)
} }
@@ -849,11 +748,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
} }
} }
if err := syncer.store.MarkBlockAsValidated(ctx, b.Cid()); err != nil { return merr
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 { func (syncer *Syncer) VerifyWinningPoStProof(ctx context.Context, h *types.BlockHeader, prevBeacon types.BeaconEntry, lbst cid.Cid, waddr address.Address) error {
@@ -951,7 +846,7 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
// Phase 1: syntactic validation, as defined in the spec // Phase 1: syntactic validation, as defined in the spec
minGas := vm.PricelistByEpoch(baseTs.Height()).OnChainMessage(msg.ChainLength()) minGas := vm.PricelistByEpoch(baseTs.Height()).OnChainMessage(msg.ChainLength())
if err := m.ValidForBlockInclusion(minGas.Total()); err != nil { if err := m.ValidForBlockInclusion(minGas); err != nil {
return err return err
} }
@@ -1043,14 +938,23 @@ func (syncer *Syncer) verifyBlsAggregate(ctx context.Context, sig *crypto.Signat
trace.Int64Attribute("msgCount", int64(len(msgs))), trace.Int64Attribute("msgCount", int64(len(msgs))),
) )
bmsgs := make([]bls.Message, len(msgs)) var wg sync.WaitGroup
for i, m := range msgs {
bmsgs[i] = m.Bytes() 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)
} }
wg.Wait()
var bsig bls.Signature var bsig bls.Signature
copy(bsig[:], sig.Data) copy(bsig[:], sig.Data)
if !bls.HashVerify(&bsig, bmsgs, pubks) { if !bls.Verify(&bsig, digests, pubks) {
return xerrors.New("bls aggregate signature failed to verify") return xerrors.New("bls aggregate signature failed to verify")
} }
@@ -1067,70 +971,41 @@ func extractSyncState(ctx context.Context) *SyncerState {
return nil return nil
} }
// collectHeaders collects the headers from the blocks between any two tipsets. func (syncer *Syncer) collectHeaders(ctx context.Context, from *types.TipSet, to *types.TipSet) ([]*types.TipSet, error) {
//
// `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") ctx, span := trace.StartSpan(ctx, "collectHeaders")
defer span.End() defer span.End()
ss := extractSyncState(ctx) ss := extractSyncState(ctx)
span.AddAttributes( span.AddAttributes(
trace.Int64Attribute("incomingHeight", int64(incoming.Height())), trace.Int64Attribute("fromHeight", int64(from.Height())),
trace.Int64Attribute("knownHeight", int64(known.Height())), trace.Int64Attribute("toHeight", int64(to.Height())),
) )
// Check if the parents of the from block are in the denylist. markBad := func(fmts string, args ...interface{}) {
// i.e. if a fork of the chain has been requested that we know to be bad. for _, b := range from.Cids() {
for _, pcid := range incoming.Parents().Cids() { syncer.bad.Add(b, fmt.Sprintf(fmts, args...))
}
}
for _, pcid := range from.Parents().Cids() {
if reason, ok := syncer.bad.Has(pcid); ok { if reason, ok := syncer.bad.Has(pcid); ok {
newReason := reason.Linked("linked to %s", pcid) markBad("linked to %s", pcid)
for _, b := range incoming.Cids() { return nil, xerrors.Errorf("chain linked to block marked previously as bad (%s, %s) (reason: %s)", from.Cids(), pcid, reason)
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 // ensure consistency of beacon entires
targetBE := incoming.Blocks()[0].BeaconEntries targetBE := from.Blocks()[0].BeaconEntries
sorted := sort.SliceIsSorted(targetBE, func(i, j int) bool { sorted := sort.SliceIsSorted(targetBE, func(i, j int) bool {
return targetBE[i].Round < targetBE[j].Round return targetBE[i].Round < targetBE[j].Round
}) })
if !sorted { if !sorted {
syncer.bad.Add(incoming.Cids()[0], NewBadBlockReason(incoming.Cids(), "wrong order of beacon entires")) syncer.bad.Add(from.Cids()[0], "wrong order of beacon entires")
return nil, xerrors.Errorf("wrong order of beacon entires") return nil, xerrors.Errorf("wrong order of beacon entires")
} }
for _, bh := range incoming.Blocks()[1:] { for _, bh := range from.Blocks()[1:] {
if len(targetBE) != len(bh.BeaconEntries) { if len(targetBE) != len(bh.BeaconEntries) {
// cannot mark bad, I think @Kubuxu // cannot mark bad, I think @Kubuxu
return nil, xerrors.Errorf("tipset contained different number for beacon entires") return nil, xerrors.Errorf("tipset contained different number for beacon entires")
@@ -1145,12 +1020,12 @@ func (syncer *Syncer) collectHeaders(ctx context.Context, incoming *types.TipSet
} }
} }
blockSet := []*types.TipSet{incoming} blockSet := []*types.TipSet{from}
at := incoming.Parents() at := from.Parents()
// we want to sync all the blocks until the height above the block we have // we want to sync all the blocks until the height above the block we have
untilHeight := known.Height() + 1 untilHeight := to.Height() + 1
ss.SetHeight(blockSet[len(blockSet)-1].Height()) ss.SetHeight(blockSet[len(blockSet)-1].Height())
@@ -1160,12 +1035,11 @@ loop:
for blockSet[len(blockSet)-1].Height() > untilHeight { for blockSet[len(blockSet)-1].Height() > untilHeight {
for _, bc := range at.Cids() { for _, bc := range at.Cids() {
if reason, ok := syncer.bad.Has(bc); ok { if reason, ok := syncer.bad.Has(bc); ok {
newReason := reason.Linked("change contained %s", bc)
for _, b := range acceptedBlocks { for _, b := range acceptedBlocks {
syncer.bad.Add(b, newReason) syncer.bad.Add(b, fmt.Sprintf("chain contained %s", bc))
} }
return nil, xerrors.Errorf("chain contained block marked previously as bad (%s, %s) (reason: %s)", incoming.Cids(), bc, reason) return nil, xerrors.Errorf("chain contained block marked previously as bad (%s, %s) (reason: %s)", from.Cids(), bc, reason)
} }
} }
@@ -1183,8 +1057,8 @@ loop:
} }
// NB: GetBlocks validates that the blocks are in-fact the ones we // NB: GetBlocks validates that the blocks are in-fact the ones we
// requested, and that they are correctly linked to one another. It does // requested, and that they are correctly linked to eachother. It does
// not validate any state transitions. // not validate any state transitions
window := 500 window := 500
if gap := int(blockSet[len(blockSet)-1].Height() - untilHeight); gap < window { if gap := int(blockSet[len(blockSet)-1].Height() - untilHeight); gap < window {
window = gap window = gap
@@ -1209,12 +1083,11 @@ loop:
} }
for _, bc := range b.Cids() { for _, bc := range b.Cids() {
if reason, ok := syncer.bad.Has(bc); ok { if reason, ok := syncer.bad.Has(bc); ok {
newReason := reason.Linked("change contained %s", bc)
for _, b := range acceptedBlocks { for _, b := range acceptedBlocks {
syncer.bad.Add(b, newReason) syncer.bad.Add(b, fmt.Sprintf("chain contained %s", bc))
} }
return nil, xerrors.Errorf("chain contained block marked previously as bad (%s, %s) (reason: %s)", incoming.Cids(), bc, reason) return nil, xerrors.Errorf("chain contained block marked previously as bad (%s, %s) (reason: %s)", from.Cids(), bc, reason)
} }
} }
blockSet = append(blockSet, b) blockSet = append(blockSet, b)
@@ -1226,23 +1099,22 @@ loop:
at = blks[len(blks)-1].Parents() at = blks[len(blks)-1].Parents()
} }
// base is the tipset in the candidate chain at the height equal to our known tipset height. // We have now ascertained that this is *not* a 'fast forward'
if base := blockSet[len(blockSet)-1]; !types.CidArrsEqual(base.Parents().Cids(), known.Cids()) { if !types.CidArrsEqual(blockSet[len(blockSet)-1].Parents().Cids(), to.Cids()) {
if base.Parents() == known.Parents() { last := blockSet[len(blockSet)-1]
if last.Parents() == to.Parents() {
// common case: receiving a block thats potentially part of the same tipset as our best block // common case: receiving a block thats potentially part of the same tipset as our best block
return blockSet, nil return blockSet, nil
} }
// 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)", from.Cids(), from.Height(), to.Cids(), to.Height())
fork, err := syncer.syncFork(ctx, last, to)
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 err != nil {
if xerrors.Is(err, ErrForkTooLong) { if xerrors.Is(err, ErrForkTooLong) {
// TODO: we're marking this block bad in the same way that we mark invalid blocks bad. Maybe distinguish? // 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") log.Warn("adding forked chain to our bad tipset cache")
for _, b := range incoming.Blocks() { for _, b := range from.Blocks() {
syncer.bad.Add(b.Cid(), NewBadBlockReason(incoming.Cids(), "fork past finality")) syncer.bad.Add(b.Cid(), "fork past finality")
} }
} }
return nil, xerrors.Errorf("failed to sync fork: %w", err) return nil, xerrors.Errorf("failed to sync fork: %w", err)
@@ -1256,19 +1128,13 @@ loop:
var ErrForkTooLong = fmt.Errorf("fork longer than threshold") var ErrForkTooLong = fmt.Errorf("fork longer than threshold")
// syncFork tries to obtain the chain fragment that links a fork into a common func (syncer *Syncer) syncFork(ctx context.Context, from *types.TipSet, to *types.TipSet) ([]*types.TipSet, error) {
// ancestor in our view of the chain. tips, err := syncer.Bsync.GetBlocks(ctx, from.Parents(), int(build.ForkLengthThreshold))
//
// 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 { if err != nil {
return nil, err return nil, err
} }
nts, err := syncer.store.LoadTipSet(known.Parents()) nts, err := syncer.store.LoadTipSet(to.Parents())
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to load next local tipset: %w", err) return nil, xerrors.Errorf("failed to load next local tipset: %w", err)
} }
@@ -1278,7 +1144,7 @@ func (syncer *Syncer) syncFork(ctx context.Context, incoming *types.TipSet, know
if !syncer.Genesis.Equals(nts) { 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("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; incoming: %s") return nil, xerrors.Errorf("synced chain forked at genesis, refusing to sync")
} }
if nts.Equals(tips[cur]) { if nts.Equals(tips[cur]) {
@@ -1413,25 +1279,6 @@ func persistMessages(bs bstore.Blockstore, bst *blocksync.BSTipSet) error {
return nil 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 { func (syncer *Syncer) collectChain(ctx context.Context, ts *types.TipSet) error {
ctx, span := trace.StartSpan(ctx, "collectChain") ctx, span := trace.StartSpan(ctx, "collectChain")
defer span.End() defer span.End()
@@ -1478,11 +1325,12 @@ func (syncer *Syncer) collectChain(ctx context.Context, ts *types.TipSet) error
return nil return nil
} }
func VerifyElectionPoStVRF(ctx context.Context, worker address.Address, rand []byte, evrf []byte) error { func VerifyElectionPoStVRF(ctx context.Context, evrf []byte, rand []byte, worker address.Address) error {
if build.InsecurePoStValidation { if err := gen.VerifyVRF(ctx, worker, rand, evrf); err != nil {
return nil return xerrors.Errorf("failed to verify post_randomness vrf: %w", err)
} }
return gen.VerifyVRF(ctx, worker, rand, evrf)
return nil
} }
func (syncer *Syncer) State() []SyncerState { func (syncer *Syncer) State() []SyncerState {
@@ -1493,17 +1341,14 @@ func (syncer *Syncer) State() []SyncerState {
return out return out
} }
// MarkBad manually adds a block to the "bad blocks" cache.
func (syncer *Syncer) MarkBad(blk cid.Cid) { func (syncer *Syncer) MarkBad(blk cid.Cid) {
syncer.bad.Add(blk, NewBadBlockReason([]cid.Cid{blk}, "manually marked bad")) syncer.bad.Add(blk, "manually marked bad")
} }
func (syncer *Syncer) CheckBadBlockCache(blk cid.Cid) (string, bool) { func (syncer *Syncer) CheckBadBlockCache(blk cid.Cid) (string, bool) {
bbr, ok := syncer.bad.Has(blk) return 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 cur := ts
for i := 0; i < 20; i++ { for i := 0; i < 20; i++ {
cbe := cur.Blocks()[0].BeaconEntries cbe := cur.Blocks()[0].BeaconEntries
@@ -1524,13 +1369,3 @@ func (syncer *Syncer) getLatestBeaconEntry(_ context.Context, ts *types.TipSet)
return nil, xerrors.Errorf("found NO beacon entries in the 20 blocks prior to given 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(time.Now().Unix())
return epoch > (abi.ChainEpoch((now-g.Timestamp)/build.BlockDelaySecs) + MaxHeightDrift)
}
+1 -2
View File
@@ -35,7 +35,6 @@ type SyncManager struct {
syncStates []*SyncerState syncStates []*SyncerState
// Normally this handler is set to `(*Syncer).Sync()`.
doSync func(context.Context, *types.TipSet) error doSync func(context.Context, *types.TipSet) error
stop chan struct{} stop chan struct{}
@@ -281,7 +280,7 @@ func (sm *SyncManager) syncScheduler() {
} }
func (sm *SyncManager) scheduleIncoming(ts *types.TipSet) { func (sm *SyncManager) scheduleIncoming(ts *types.TipSet) {
log.Debug("scheduling incoming tipset sync: ", ts.Cids()) log.Info("scheduling incoming tipset sync: ", ts.Cids())
if sm.getBootstrapState() == BSStateSelected { if sm.getBootstrapState() == BSStateSelected {
sm.setBootstrapState(BSStateScheduled) sm.setBootstrapState(BSStateScheduled)
sm.syncTargets <- ts sm.syncTargets <- ts
+3 -3
View File
@@ -34,8 +34,8 @@ import (
func init() { func init() {
build.InsecurePoStValidation = true build.InsecurePoStValidation = true
os.Setenv("TRUST_PARAMS", "1") os.Setenv("TRUST_PARAMS", "1")
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
abi.RegisteredSealProof_StackedDrg2KiBV1: {}, abi.RegisteredProof_StackedDRG2KiBSeal: {},
} }
power.ConsensusMinerMinPower = big.NewInt(2048) power.ConsensusMinerMinPower = big.NewInt(2048)
verifreg.MinVerifiedDealSize = big.NewInt(256) verifreg.MinVerifiedDealSize = big.NewInt(256)
@@ -408,7 +408,7 @@ func TestSyncBadTimestamp(t *testing.T) {
base := tu.g.CurTipset base := tu.g.CurTipset
tu.g.Timestamper = func(pts *types.TipSet, tl abi.ChainEpoch) uint64 { tu.g.Timestamper = func(pts *types.TipSet, tl abi.ChainEpoch) uint64 {
return pts.MinTimestamp() + (build.BlockDelaySecs / 2) return pts.MinTimestamp() + (build.BlockDelay / 2)
} }
fmt.Println("BASE: ", base.Cids()) fmt.Println("BASE: ", base.Cids())
+1 -1
View File
@@ -76,7 +76,7 @@ func SizeStr(bi BigInt) string {
} }
f, _ := r.Float64() f, _ := r.Float64()
return fmt.Sprintf("%.4g %s", f, byteSizeUnits[i]) return fmt.Sprintf("%.3g %s", f, byteSizeUnits[i])
} }
var deciUnits = []string{"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"} var deciUnits = []string{"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"}
+2 -25
View File
@@ -3,12 +3,7 @@ package types
import ( import (
"bytes" "bytes"
"math/big" "math/big"
"math/rand"
"strings"
"testing" "testing"
"time"
"github.com/docker/go-units"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@@ -43,7 +38,7 @@ func TestBigIntSerializationRoundTrip(t *testing.T) {
func TestFilRoundTrip(t *testing.T) { func TestFilRoundTrip(t *testing.T) {
testValues := []string{ testValues := []string{
"0 FIL", "1 FIL", "1.001 FIL", "100.10001 FIL", "101100 FIL", "5000.01 FIL", "5000 FIL", "0", "1", "1.001", "100.10001", "101100", "5000.01", "5000",
} }
for _, v := range testValues { for _, v := range testValues {
@@ -65,10 +60,8 @@ func TestSizeStr(t *testing.T) {
}{ }{
{0, "0 B"}, {0, "0 B"},
{1, "1 B"}, {1, "1 B"},
{1016, "1016 B"},
{1024, "1 KiB"}, {1024, "1 KiB"},
{1000 * 1024, "1000 KiB"}, {2000, "1.95 KiB"},
{2000, "1.953 KiB"},
{5 << 20, "5 MiB"}, {5 << 20, "5 MiB"},
{11 << 60, "11 EiB"}, {11 << 60, "11 EiB"},
} }
@@ -78,22 +71,6 @@ func TestSizeStr(t *testing.T) {
} }
} }
func TestSizeStrUnitsSymmetry(t *testing.T) {
s := rand.NewSource(time.Now().UnixNano())
r := rand.New(s)
for i := 0; i < 1000000; 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) { func TestSizeStrBig(t *testing.T) {
ZiB := big.NewInt(50000) ZiB := big.NewInt(50000)
ZiB = ZiB.Lsh(ZiB, 70) ZiB = ZiB.Lsh(ZiB, 70)
+4 -4
View File
@@ -74,8 +74,8 @@ type BlockHeader struct {
validated bool // true if the signature has been validated validated bool // true if the signature has been validated
} }
func (blk *BlockHeader) ToStorageBlock() (block.Block, error) { func (b *BlockHeader) ToStorageBlock() (block.Block, error) {
data, err := blk.Serialize() data, err := b.Serialize()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -89,8 +89,8 @@ func (blk *BlockHeader) ToStorageBlock() (block.Block, error) {
return block.NewBlockWithCid(data, c) return block.NewBlockWithCid(data, c)
} }
func (blk *BlockHeader) Cid() cid.Cid { func (b *BlockHeader) Cid() cid.Cid {
sb, err := blk.ToStorageBlock() sb, err := b.ToStorageBlock()
if err != nil { if err != nil {
panic(err) // Not sure i'm entirely comfortable with this one, needs to be checked panic(err) // Not sure i'm entirely comfortable with this one, needs to be checked
} }
+5 -4
View File
@@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"github.com/stretchr/testify/require"
"reflect" "reflect"
"testing" "testing"
@@ -80,7 +79,7 @@ func TestInteropBH(t *testing.T) {
} }
posts := []abi.PoStProof{ posts := []abi.PoStProof{
{abi.RegisteredPoStProof_StackedDrgWinning2KiBV1, []byte{0x07}}, {abi.RegisteredProof_StackedDRG2KiBWinningPoSt, []byte{0x07}},
} }
bh := &BlockHeader{ bh := &BlockHeader{
@@ -117,8 +116,10 @@ func TestInteropBH(t *testing.T) {
} }
// acquired from go-filecoin // acquired from go-filecoin
gfc := "8f5501d04cb15021bf6bd003073d79e2238d4e61f1ad22814301020381420a0b818205410c818200410781d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc430003e802d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc410001f603" gfc := "8f5501d04cb15021bf6bd003073d79e2238d4e61f1ad22814301020381420a0b818205410c818209410781d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc430003e802d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc410001f603"
require.Equal(t, gfc, hex.EncodeToString(bhsb)) if gfc != hex.EncodeToString(bhsb) {
t.Fatal("not equal!")
}
} }
func BenchmarkBlockHeaderMarshal(b *testing.B) { func BenchmarkBlockHeaderMarshal(b *testing.B) {
+5 -99
View File
@@ -1,103 +1,9 @@
package types package types
import ( type ExecutionResult struct {
"encoding/json" Msg *Message
"fmt" MsgRct *MessageReceipt
"runtime" Error string
"strings"
"time"
)
type ExecutionTrace struct { Subcalls []*ExecutionResult
Msg *Message
MsgRct *MessageReceipt
Error string
Duration time.Duration
GasCharges []*GasTrace
Subcalls []ExecutionTrace
}
type GasTrace struct {
Name string
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 `json:"tt"`
Extra interface{} `json:"ex,omitempty"`
Callers []uintptr `json:"-"`
}
type Loc struct {
File string
Line int
Function string
}
func (l Loc) Show() bool {
ignorePrefix := []string{
"reflect.",
"github.com/filecoin-project/lotus/chain/vm.(*Invoker).transform",
"github.com/filecoin-project/go-amt-ipld/",
}
for _, pre := range ignorePrefix {
if strings.HasPrefix(l.Function, pre) {
return false
}
}
return true
}
func (l Loc) String() string {
file := strings.Split(l.File, "/")
fn := strings.Split(l.Function, "/")
var fnpkg string
if len(fn) > 2 {
fnpkg = strings.Join(fn[len(fn)-2:], "/")
} else {
fnpkg = l.Function
}
return fmt.Sprintf("%s@%s:%d", fnpkg, file[len(file)-1], l.Line)
}
func (l Loc) Important() bool {
if strings.HasPrefix(l.Function, "github.com/filecoin-project/specs-actors/actors/builtin") {
return true
}
return false
}
func (gt *GasTrace) MarshalJSON() ([]byte, error) {
type GasTraceCopy GasTrace
if len(gt.Location) == 0 {
if len(gt.Callers) != 0 {
frames := runtime.CallersFrames(gt.Callers)
for {
frame, more := frames.Next()
if frame.Function == "github.com/filecoin-project/lotus/chain/vm.(*VM).ApplyMessage" {
break
}
l := Loc{
File: frame.File,
Line: frame.Line,
Function: frame.Function,
}
gt.Location = append(gt.Location, l)
if !more {
break
}
}
}
}
cpy := (*GasTraceCopy)(gt)
return json.Marshal(cpy)
} }
+5 -26
View File
@@ -11,11 +11,11 @@ import (
type FIL BigInt type FIL BigInt
func (f FIL) String() string { func (f FIL) String() string {
r := new(big.Rat).SetFrac(f.Int, big.NewInt(int64(build.FilecoinPrecision))) r := new(big.Rat).SetFrac(f.Int, big.NewInt(build.FilecoinPrecision))
if r.Sign() == 0 { if r.Sign() == 0 {
return "0 FIL" return "0"
} }
return strings.TrimRight(strings.TrimRight(r.FloatString(18), "0"), ".") + " FIL" return strings.TrimRight(strings.TrimRight(r.FloatString(18), "0"), ".")
} }
func (f FIL) Format(s fmt.State, ch rune) { func (f FIL) Format(s fmt.State, ch rune) {
@@ -28,35 +28,14 @@ func (f FIL) Format(s fmt.State, ch rune) {
} }
func ParseFIL(s string) (FIL, error) { 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) r, ok := new(big.Rat).SetString(s)
if !ok { if !ok {
return FIL{}, fmt.Errorf("failed to parse %q as a decimal number", s) return FIL{}, fmt.Errorf("failed to parse %q as a decimal number", s)
} }
if !attofil { r = r.Mul(r, big.NewRat(build.FilecoinPrecision, 1))
r = r.Mul(r, big.NewRat(int64(build.FilecoinPrecision), 1))
}
if !r.IsInt() { if !r.IsInt() {
var pref string return FIL{}, fmt.Errorf("invalid FIL value: %q", s)
if attofil {
pref = "atto"
}
return FIL{}, fmt.Errorf("invalid %sFIL value: %q", pref, s)
} }
return FIL{r.Num()}, nil return FIL{r.Num()}, nil
+10 -7
View File
@@ -21,7 +21,6 @@ type ChainMsg interface {
Cid() cid.Cid Cid() cid.Cid
VMMessage() *Message VMMessage() *Message
ToStorageBlock() (block.Block, error) ToStorageBlock() (block.Block, error)
// FIXME: This is the *message* length, this name is misleading.
ChainLength() int ChainLength() int
} }
@@ -42,16 +41,20 @@ type Message struct {
Params []byte Params []byte
} }
func (m *Message) Caller() address.Address { func (t *Message) BlockMiner() address.Address {
return m.From panic("implement me")
} }
func (m *Message) Receiver() address.Address { func (t *Message) Caller() address.Address {
return m.To return t.From
} }
func (m *Message) ValueReceived() abi.TokenAmount { func (t *Message) Receiver() address.Address {
return m.Value return t.To
}
func (t *Message) ValueReceived() abi.TokenAmount {
return t.Value
} }
func DecodeMessage(b []byte) (*Message, error) { func DecodeMessage(b []byte) (*Message, error) {
+1 -6
View File
@@ -49,11 +49,6 @@ func MkBlock(parents *types.TipSet, weightInc uint64, ticketNonce uint64) *types
panic(err) panic(err)
} }
pstateRoot := c
if parents != nil {
pstateRoot = parents.Blocks()[0].ParentStateRoot
}
var pcids []cid.Cid var pcids []cid.Cid
var height abi.ChainEpoch var height abi.ChainEpoch
weight := types.NewInt(weightInc) weight := types.NewInt(weightInc)
@@ -77,7 +72,7 @@ func MkBlock(parents *types.TipSet, weightInc uint64, ticketNonce uint64) *types
ParentWeight: weight, ParentWeight: weight,
Messages: c, Messages: c,
Height: height, Height: height,
ParentStateRoot: pstateRoot, ParentStateRoot: c,
BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte("boo! im a signature")}, BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte("boo! im a signature")},
} }
} }
+8 -8
View File
@@ -9,12 +9,12 @@ import (
"github.com/multiformats/go-multihash" "github.com/multiformats/go-multihash"
) )
func (sm *SignedMessage) ToStorageBlock() (block.Block, error) { func (m *SignedMessage) ToStorageBlock() (block.Block, error) {
if sm.Signature.Type == crypto.SigTypeBLS { if m.Signature.Type == crypto.SigTypeBLS {
return sm.Message.ToStorageBlock() return m.Message.ToStorageBlock()
} }
data, err := sm.Serialize() data, err := m.Serialize()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -28,12 +28,12 @@ func (sm *SignedMessage) ToStorageBlock() (block.Block, error) {
return block.NewBlockWithCid(data, c) return block.NewBlockWithCid(data, c)
} }
func (sm *SignedMessage) Cid() cid.Cid { func (m *SignedMessage) Cid() cid.Cid {
if sm.Signature.Type == crypto.SigTypeBLS { if m.Signature.Type == crypto.SigTypeBLS {
return sm.Message.Cid() return m.Message.Cid()
} }
sb, err := sm.ToStorageBlock() sb, err := m.ToStorageBlock()
if err != nil { if err != nil {
panic(err) panic(err)
} }
+2 -6
View File
@@ -23,6 +23,8 @@ type TipSet struct {
height abi.ChainEpoch height abi.ChainEpoch
} }
// why didnt i just export the fields? Because the struct has methods with the
// same names already
type ExpTipSet struct { type ExpTipSet struct {
Cids []cid.Cid Cids []cid.Cid
Blocks []*BlockHeader Blocks []*BlockHeader
@@ -30,8 +32,6 @@ type ExpTipSet struct {
} }
func (ts *TipSet) MarshalJSON() ([]byte, error) { func (ts *TipSet) MarshalJSON() ([]byte, error) {
// why didnt i just export the fields? Because the struct has methods with the
// same names already
return json.Marshal(ExpTipSet{ return json.Marshal(ExpTipSet{
Cids: ts.cids, Cids: ts.cids,
Blocks: ts.blks, Blocks: ts.blks,
@@ -112,10 +112,6 @@ func NewTipSet(blks []*BlockHeader) (*TipSet, error) {
return nil, fmt.Errorf("cannot create tipset with mismatching heights") 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 { for i, cid := range b.Parents {
if cid != blks[0].Parents[i] { if cid != blks[0].Parents[i] {
return nil, fmt.Errorf("cannot create tipset with mismatching parents") return nil, fmt.Errorf("cannot create tipset with mismatching parents")
+3 -3
View File
@@ -61,9 +61,9 @@ func TestTipSetKey(t *testing.T) {
t.Run("JSON", func(t *testing.T) { t.Run("JSON", func(t *testing.T) {
k0 := NewTipSetKey() k0 := NewTipSetKey()
verifyJSON(t, "[]", k0) verifyJson(t, "[]", k0)
k3 := NewTipSetKey(c1, c2, c3) k3 := NewTipSetKey(c1, c2, c3)
verifyJSON(t, `[`+ verifyJson(t, `[`+
`{"/":"bafy2bzacecesrkxghscnq7vatble2hqdvwat6ed23vdu4vvo3uuggsoaya7ki"},`+ `{"/":"bafy2bzacecesrkxghscnq7vatble2hqdvwat6ed23vdu4vvo3uuggsoaya7ki"},`+
`{"/":"bafy2bzacebxfyh2fzoxrt6kcgc5dkaodpcstgwxxdizrww225vrhsizsfcg4g"},`+ `{"/":"bafy2bzacebxfyh2fzoxrt6kcgc5dkaodpcstgwxxdizrww225vrhsizsfcg4g"},`+
`{"/":"bafy2bzacedwviarjtjraqakob5pslltmuo5n3xev3nt5zylezofkbbv5jclyu"}`+ `{"/":"bafy2bzacedwviarjtjraqakob5pslltmuo5n3xev3nt5zylezofkbbv5jclyu"}`+
@@ -71,7 +71,7 @@ func TestTipSetKey(t *testing.T) {
}) })
} }
func verifyJSON(t *testing.T, expected string, k TipSetKey) { func verifyJson(t *testing.T, expected string, k TipSetKey) {
bytes, err := json.Marshal(k) bytes, err := json.Marshal(k)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, expected, string(bytes)) assert.Equal(t, expected, string(bytes))
+16 -77
View File
@@ -12,74 +12,34 @@ import (
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
) )
const (
GasStorageMulti = 1
GasComputeMulti = 1
)
type GasCharge struct {
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{
Name: name,
ComputeGas: computeGas,
StorageGas: storageGas,
}
}
// Pricelist provides prices for operations in the VM. // Pricelist provides prices for operations in the VM.
// //
// Note: this interface should be APPEND ONLY since last chain checkpoint // Note: this interface should be APPEND ONLY since last chain checkpoint
type Pricelist interface { type Pricelist interface {
// OnChainMessage returns the gas used for storing a message of a given size in the chain. // OnChainMessage returns the gas used for storing a message of a given size in the chain.
OnChainMessage(msgSize int) GasCharge OnChainMessage(msgSize int) int64
// OnChainReturnValue returns the gas used for storing the response of a message in the chain. // OnChainReturnValue returns the gas used for storing the response of a message in the chain.
OnChainReturnValue(dataSize int) GasCharge OnChainReturnValue(dataSize int) int64
// OnMethodInvocation returns the gas used when invoking a method. // OnMethodInvocation returns the gas used when invoking a method.
OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) GasCharge OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) int64
// OnIpldGet returns the gas used for storing an object // OnIpldGet returns the gas used for storing an object
OnIpldGet(dataSize int) GasCharge OnIpldGet(dataSize int) int64
// OnIpldPut returns the gas used for storing an object // OnIpldPut returns the gas used for storing an object
OnIpldPut(dataSize int) GasCharge OnIpldPut(dataSize int) int64
// OnCreateActor returns the gas used for creating an actor // OnCreateActor returns the gas used for creating an actor
OnCreateActor() GasCharge OnCreateActor() int64
// OnDeleteActor returns the gas used for deleting an actor // OnDeleteActor returns the gas used for deleting an actor
OnDeleteActor() GasCharge OnDeleteActor() int64
OnVerifySignature(sigType crypto.SigType, planTextSize int) (GasCharge, error) OnVerifySignature(sigType crypto.SigType, planTextSize int) (int64, error)
OnHashing(dataSize int) GasCharge OnHashing(dataSize int) int64
OnComputeUnsealedSectorCid(proofType abi.RegisteredSealProof, pieces []abi.PieceInfo) GasCharge OnComputeUnsealedSectorCid(proofType abi.RegisteredProof, pieces []abi.PieceInfo) int64
OnVerifySeal(info abi.SealVerifyInfo) GasCharge OnVerifySeal(info abi.SealVerifyInfo) int64
OnVerifyPost(info abi.WindowPoStVerifyInfo) GasCharge OnVerifyPost(info abi.WindowPoStVerifyInfo) int64
OnVerifyConsensusFault() GasCharge OnVerifyConsensusFault() int64
} }
var prices = map[abi.ChainEpoch]Pricelist{ var prices = map[abi.ChainEpoch]Pricelist{
@@ -133,7 +93,7 @@ func PricelistByEpoch(epoch abi.ChainEpoch) Pricelist {
type pricedSyscalls struct { type pricedSyscalls struct {
under vmr.Syscalls under vmr.Syscalls
pl Pricelist pl Pricelist
chargeGas func(GasCharge) chargeGas func(int64)
} }
// Verifies that a signature is valid for an address and plaintext. // Verifies that a signature is valid for an address and plaintext.
@@ -143,40 +103,30 @@ func (ps pricedSyscalls) VerifySignature(signature crypto.Signature, signer addr
return err return err
} }
ps.chargeGas(c) ps.chargeGas(c)
defer ps.chargeGas(gasOnActorExec)
return ps.under.VerifySignature(signature, signer, plaintext) return ps.under.VerifySignature(signature, signer, plaintext)
} }
// Hashes input data using blake2b with 256 bit output. // Hashes input data using blake2b with 256 bit output.
func (ps pricedSyscalls) HashBlake2b(data []byte) [32]byte { func (ps pricedSyscalls) HashBlake2b(data []byte) [32]byte {
ps.chargeGas(ps.pl.OnHashing(len(data))) ps.chargeGas(ps.pl.OnHashing(len(data)))
defer ps.chargeGas(gasOnActorExec)
return ps.under.HashBlake2b(data) return ps.under.HashBlake2b(data)
} }
// Computes an unsealed sector CID (CommD) from its constituent piece CIDs (CommPs) and sizes. // Computes an unsealed sector CID (CommD) from its constituent piece CIDs (CommPs) and sizes.
func (ps pricedSyscalls) ComputeUnsealedSectorCID(reg abi.RegisteredSealProof, pieces []abi.PieceInfo) (cid.Cid, error) { func (ps pricedSyscalls) ComputeUnsealedSectorCID(reg abi.RegisteredProof, pieces []abi.PieceInfo) (cid.Cid, error) {
ps.chargeGas(ps.pl.OnComputeUnsealedSectorCid(reg, pieces)) ps.chargeGas(ps.pl.OnComputeUnsealedSectorCid(reg, pieces))
defer ps.chargeGas(gasOnActorExec)
return ps.under.ComputeUnsealedSectorCID(reg, pieces) return ps.under.ComputeUnsealedSectorCID(reg, pieces)
} }
// Verifies a sector seal proof. // Verifies a sector seal proof.
func (ps pricedSyscalls) VerifySeal(vi abi.SealVerifyInfo) error { func (ps pricedSyscalls) VerifySeal(vi abi.SealVerifyInfo) error {
ps.chargeGas(ps.pl.OnVerifySeal(vi)) ps.chargeGas(ps.pl.OnVerifySeal(vi))
defer ps.chargeGas(gasOnActorExec)
return ps.under.VerifySeal(vi) return ps.under.VerifySeal(vi)
} }
// Verifies a proof of spacetime. // Verifies a proof of spacetime.
func (ps pricedSyscalls) VerifyPoSt(vi abi.WindowPoStVerifyInfo) error { func (ps pricedSyscalls) VerifyPoSt(vi abi.WindowPoStVerifyInfo) error {
ps.chargeGas(ps.pl.OnVerifyPost(vi)) ps.chargeGas(ps.pl.OnVerifyPost(vi))
defer ps.chargeGas(gasOnActorExec)
return ps.under.VerifyPoSt(vi) return ps.under.VerifyPoSt(vi)
} }
@@ -192,21 +142,10 @@ func (ps pricedSyscalls) VerifyPoSt(vi abi.WindowPoStVerifyInfo) error {
// Returns nil and an error if the headers don't prove a fault. // 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) { func (ps pricedSyscalls) VerifyConsensusFault(h1 []byte, h2 []byte, extra []byte) (*runtime.ConsensusFault, error) {
ps.chargeGas(ps.pl.OnVerifyConsensusFault()) ps.chargeGas(ps.pl.OnVerifyConsensusFault())
defer ps.chargeGas(gasOnActorExec)
return ps.under.VerifyConsensusFault(h1, h2, extra) return ps.under.VerifyConsensusFault(h1, h2, extra)
} }
func (ps pricedSyscalls) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) { func (ps pricedSyscalls) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) {
var gasChargeSum GasCharge ps.chargeGas(0) // TODO: this is only called by the cron actor. Should we even charge gas?
gasChargeSum.Name = "BatchVerifySeals"
count := int64(0)
for _, svis := range inp {
count += int64(len(svis))
}
gasChargeSum = gasChargeSum.WithExtra(count).WithVirtual(129778623*count+716683250, 0)
ps.chargeGas(gasChargeSum) // TODO: this is only called by the cron actor. Should we even charge gas?
defer ps.chargeGas(gasOnActorExec)
return ps.under.BatchVerifySeals(inp) return ps.under.BatchVerifySeals(inp)
} }
+27 -61
View File
@@ -2,9 +2,7 @@ package vm
import ( import (
"fmt" "fmt"
"github.com/filecoin-project/specs-actors/actors/abi" "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"
"github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/crypto"
) )
@@ -86,112 +84,80 @@ type pricelistV0 struct {
var _ Pricelist = (*pricelistV0)(nil) var _ Pricelist = (*pricelistV0)(nil)
// OnChainMessage returns the gas used for storing a message of a given size in the chain. // OnChainMessage returns the gas used for storing a message of a given size in the chain.
func (pl *pricelistV0) OnChainMessage(msgSize int) GasCharge { func (pl *pricelistV0) OnChainMessage(msgSize int) int64 {
return newGasCharge("OnChainMessage", 0, pl.onChainMessageBase+pl.onChainMessagePerByte*int64(msgSize)).WithVirtual(77302, 0) return pl.onChainMessageBase + pl.onChainMessagePerByte*int64(msgSize)
} }
// OnChainReturnValue returns the gas used for storing the response of a message in the chain. // OnChainReturnValue returns the gas used for storing the response of a message in the chain.
func (pl *pricelistV0) OnChainReturnValue(dataSize int) GasCharge { func (pl *pricelistV0) OnChainReturnValue(dataSize int) int64 {
return newGasCharge("OnChainReturnValue", 0, int64(dataSize)*pl.onChainReturnValuePerByte).WithVirtual(107294, 0) return int64(dataSize) * pl.onChainReturnValuePerByte
} }
// OnMethodInvocation returns the gas used when invoking a method. // OnMethodInvocation returns the gas used when invoking a method.
func (pl *pricelistV0) OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) GasCharge { func (pl *pricelistV0) OnMethodInvocation(value abi.TokenAmount, methodNum abi.MethodNum) int64 {
ret := pl.sendBase ret := pl.sendBase
extra := ""
virtGas := int64(1072944)
if value != abi.NewTokenAmount(0) { if value != abi.NewTokenAmount(0) {
// TODO: fix this, it is comparing pointers instead of values
// see vv
ret += pl.sendTransferFunds ret += pl.sendTransferFunds
} }
if big.Cmp(value, abi.NewTokenAmount(0)) != 0 {
virtGas += 497495
if methodNum == builtin.MethodSend {
// transfer only
virtGas += 973940
}
extra += "t"
}
if methodNum != builtin.MethodSend { if methodNum != builtin.MethodSend {
ret += pl.sendInvokeMethod ret += pl.sendInvokeMethod
extra += "i"
// running actors is cheaper becase we hand over to actors
virtGas += -295779
} }
return newGasCharge("OnMethodInvocation", ret, 0).WithVirtual(virtGas, 0).WithExtra(extra) return ret
} }
// OnIpldGet returns the gas used for storing an object // OnIpldGet returns the gas used for storing an object
func (pl *pricelistV0) OnIpldGet(dataSize int) GasCharge { func (pl *pricelistV0) OnIpldGet(dataSize int) int64 {
return newGasCharge("OnIpldGet", pl.ipldGetBase+int64(dataSize)*pl.ipldGetPerByte, 0). return pl.ipldGetBase + int64(dataSize)*pl.ipldGetPerByte
WithExtra(dataSize).WithVirtual(433685, 0)
} }
// OnIpldPut returns the gas used for storing an object // OnIpldPut returns the gas used for storing an object
func (pl *pricelistV0) OnIpldPut(dataSize int) GasCharge { func (pl *pricelistV0) OnIpldPut(dataSize int) int64 {
return newGasCharge("OnIpldPut", pl.ipldPutBase, int64(dataSize)*pl.ipldPutPerByte). return pl.ipldPutBase + int64(dataSize)*pl.ipldPutPerByte
WithExtra(dataSize).WithVirtual(88970, 0)
} }
// OnCreateActor returns the gas used for creating an actor // OnCreateActor returns the gas used for creating an actor
func (pl *pricelistV0) OnCreateActor() GasCharge { func (pl *pricelistV0) OnCreateActor() int64 {
return newGasCharge("OnCreateActor", pl.createActorBase, pl.createActorExtra).WithVirtual(65636, 0) return pl.createActorBase + pl.createActorExtra
} }
// OnDeleteActor returns the gas used for deleting an actor // OnDeleteActor returns the gas used for deleting an actor
func (pl *pricelistV0) OnDeleteActor() GasCharge { func (pl *pricelistV0) OnDeleteActor() int64 {
return newGasCharge("OnDeleteActor", 0, pl.deleteActor) return pl.deleteActor
} }
// OnVerifySignature // OnVerifySignature
func (pl *pricelistV0) OnVerifySignature(sigType crypto.SigType, planTextSize int) (int64, error) {
func (pl *pricelistV0) OnVerifySignature(sigType crypto.SigType, planTextSize int) (GasCharge, error) {
costFn, ok := pl.verifySignature[sigType] costFn, ok := pl.verifySignature[sigType]
if !ok { if !ok {
return GasCharge{}, fmt.Errorf("cost function for signature type %d not supported", sigType) return 0, fmt.Errorf("cost function for signature type %d not supported", sigType)
} }
sigName, _ := sigType.Name() return costFn(int64(planTextSize)), nil
virtGas := int64(0)
switch sigType {
case crypto.SigTypeBLS:
virtGas = 220138570
case crypto.SigTypeSecp256k1:
virtGas = 7053730
}
return newGasCharge("OnVerifySignature", costFn(int64(planTextSize)), 0).
WithExtra(map[string]interface{}{
"type": sigName,
"size": planTextSize,
}).WithVirtual(virtGas, 0), nil
} }
// OnHashing // OnHashing
func (pl *pricelistV0) OnHashing(dataSize int) GasCharge { func (pl *pricelistV0) OnHashing(dataSize int) int64 {
return newGasCharge("OnHashing", pl.hashingBase+int64(dataSize)*pl.hashingPerByte, 0).WithExtra(dataSize).WithVirtual(77300, 0) return pl.hashingBase + int64(dataSize)*pl.hashingPerByte
} }
// OnComputeUnsealedSectorCid // OnComputeUnsealedSectorCid
func (pl *pricelistV0) OnComputeUnsealedSectorCid(proofType abi.RegisteredSealProof, pieces []abi.PieceInfo) GasCharge { func (pl *pricelistV0) OnComputeUnsealedSectorCid(proofType abi.RegisteredProof, pieces []abi.PieceInfo) int64 {
// TODO: this needs more cost tunning, check with @lotus // TODO: this needs more cost tunning, check with @lotus
return newGasCharge("OnComputeUnsealedSectorCid", pl.computeUnsealedSectorCidBase, 0).WithVirtual(382370, 0) return pl.computeUnsealedSectorCidBase
} }
// OnVerifySeal // OnVerifySeal
func (pl *pricelistV0) OnVerifySeal(info abi.SealVerifyInfo) GasCharge { func (pl *pricelistV0) OnVerifySeal(info abi.SealVerifyInfo) int64 {
// TODO: this needs more cost tunning, check with @lotus // TODO: this needs more cost tunning, check with @lotus
return newGasCharge("OnVerifySeal", pl.verifySealBase, 0).WithVirtual(199954003, 0) return pl.verifySealBase
} }
// OnVerifyPost // OnVerifyPost
func (pl *pricelistV0) OnVerifyPost(info abi.WindowPoStVerifyInfo) GasCharge { func (pl *pricelistV0) OnVerifyPost(info abi.WindowPoStVerifyInfo) int64 {
// TODO: this needs more cost tunning, check with @lotus // TODO: this needs more cost tunning, check with @lotus
return newGasCharge("OnVerifyPost", pl.verifyPostBase, 0).WithVirtual(2629471704, 0).WithExtra(len(info.ChallengedSectors)) return pl.verifyPostBase
} }
// OnVerifyConsensusFault // OnVerifyConsensusFault
func (pl *pricelistV0) OnVerifyConsensusFault() GasCharge { func (pl *pricelistV0) OnVerifyConsensusFault() int64 {
return newGasCharge("OnVerifyConsensusFault", pl.verifyConsensusFault, 0).WithVirtual(551935, 0) return pl.verifyConsensusFault
} }
+8 -6
View File
@@ -32,7 +32,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors/aerrors" "github.com/filecoin-project/lotus/chain/actors/aerrors"
) )
type Invoker struct { type invoker struct {
builtInCode map[cid.Cid]nativeCode builtInCode map[cid.Cid]nativeCode
builtInState map[cid.Cid]reflect.Type builtInState map[cid.Cid]reflect.Type
} }
@@ -40,8 +40,8 @@ type Invoker struct {
type invokeFunc func(rt runtime.Runtime, params []byte) ([]byte, aerrors.ActorError) type invokeFunc func(rt runtime.Runtime, params []byte) ([]byte, aerrors.ActorError)
type nativeCode []invokeFunc type nativeCode []invokeFunc
func NewInvoker() *Invoker { func NewInvoker() *invoker {
inv := &Invoker{ inv := &invoker{
builtInCode: make(map[cid.Cid]nativeCode), builtInCode: make(map[cid.Cid]nativeCode),
builtInState: make(map[cid.Cid]reflect.Type), builtInState: make(map[cid.Cid]reflect.Type),
} }
@@ -62,7 +62,7 @@ func NewInvoker() *Invoker {
return inv return inv
} }
func (inv *Invoker) Invoke(codeCid cid.Cid, rt runtime.Runtime, method abi.MethodNum, params []byte) ([]byte, aerrors.ActorError) { func (inv *invoker) Invoke(codeCid cid.Cid, rt runtime.Runtime, method abi.MethodNum, params []byte) ([]byte, aerrors.ActorError) {
code, ok := inv.builtInCode[codeCid] code, ok := inv.builtInCode[codeCid]
if !ok { if !ok {
@@ -76,7 +76,7 @@ func (inv *Invoker) Invoke(codeCid cid.Cid, rt runtime.Runtime, method abi.Metho
} }
func (inv *Invoker) Register(c cid.Cid, instance Invokee, state interface{}) { func (inv *invoker) Register(c cid.Cid, instance Invokee, state interface{}) {
code, err := inv.transform(instance) code, err := inv.transform(instance)
if err != nil { if err != nil {
panic(xerrors.Errorf("%s: %w", string(c.Hash()), err)) panic(xerrors.Errorf("%s: %w", string(c.Hash()), err))
@@ -89,7 +89,9 @@ type Invokee interface {
Exports() []interface{} Exports() []interface{}
} }
func (*Invoker) transform(instance Invokee) (nativeCode, error) { var tAError = reflect.TypeOf((*aerrors.ActorError)(nil)).Elem()
func (*invoker) transform(instance Invokee) (nativeCode, error) {
itype := reflect.TypeOf(instance) itype := reflect.TypeOf(instance)
exports := instance.Exports() exports := instance.Exports()
for i, m := range exports { for i, m := range exports {
+1 -1
View File
@@ -76,7 +76,7 @@ func (basicContract) InvokeSomething10(rt runtime.Runtime, params *basicParams)
} }
func TestInvokerBasic(t *testing.T) { func TestInvokerBasic(t *testing.T) {
inv := Invoker{} inv := invoker{}
code, err := inv.transform(basicContract{}) code, err := inv.transform(basicContract{})
assert.NoError(t, err) assert.NoError(t, err)
+1 -2
View File
@@ -2,7 +2,6 @@ package vm
import ( import (
"context" "context"
"github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/specs-actors/actors/abi/big" "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"
@@ -28,7 +27,7 @@ func init() {
var EmptyObjectCid cid.Cid var EmptyObjectCid cid.Cid
// TryCreateAccountActor creates account actors from only BLS/SECP256K1 addresses. // Creates account actors from only BLS/SECP256K1 addresses.
func TryCreateAccountActor(rt *Runtime, addr address.Address) (*types.Actor, aerrors.ActorError) { func TryCreateAccountActor(rt *Runtime, addr address.Address) (*types.Actor, aerrors.ActorError) {
addrID, err := rt.state.RegisterNewAddress(addr) addrID, err := rt.state.RegisterNewAddress(addr)
if err != nil { if err != nil {
+81 -129
View File
@@ -5,8 +5,6 @@ import (
"context" "context"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
gruntime "runtime"
"time"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
@@ -52,12 +50,10 @@ type Runtime struct {
origin address.Address origin address.Address
originNonce uint64 originNonce uint64
executionTrace types.ExecutionTrace internalExecutions []*types.ExecutionResult
numActorsCreated uint64 numActorsCreated uint64
allowInternal bool allowInternal bool
callerValidated bool callerValidated bool
lastGasChargeTime time.Time
lastGasCharge *types.GasTrace
} }
func (rt *Runtime) TotalFilCircSupply() abi.TokenAmount { func (rt *Runtime) TotalFilCircSupply() abi.TokenAmount {
@@ -110,8 +106,8 @@ type notFoundErr interface {
IsNotFound() bool IsNotFound() bool
} }
func (rt *Runtime) Get(c cid.Cid, o vmr.CBORUnmarshaler) bool { func (rs *Runtime) Get(c cid.Cid, o vmr.CBORUnmarshaler) bool {
if err := rt.cst.Get(context.TODO(), c, o); err != nil { if err := rs.cst.Get(context.TODO(), c, o); err != nil {
var nfe notFoundErr var nfe notFoundErr
if xerrors.As(err, &nfe) && nfe.IsNotFound() { if xerrors.As(err, &nfe) && nfe.IsNotFound() {
if xerrors.As(err, new(cbor.SerializationError)) { if xerrors.As(err, new(cbor.SerializationError)) {
@@ -125,8 +121,8 @@ func (rt *Runtime) Get(c cid.Cid, o vmr.CBORUnmarshaler) bool {
return true return true
} }
func (rt *Runtime) Put(x vmr.CBORMarshaler) cid.Cid { func (rs *Runtime) Put(x vmr.CBORMarshaler) cid.Cid {
c, err := rt.cst.Put(context.TODO(), x) c, err := rs.cst.Put(context.TODO(), x)
if err != nil { if err != nil {
if xerrors.As(err, new(cbor.SerializationError)) { if xerrors.As(err, new(cbor.SerializationError)) {
panic(aerrors.Newf(exitcode.ErrSerialization, "failed to marshal cbor object %s", err)) panic(aerrors.Newf(exitcode.ErrSerialization, "failed to marshal cbor object %s", err))
@@ -138,11 +134,11 @@ func (rt *Runtime) Put(x vmr.CBORMarshaler) cid.Cid {
var _ vmr.Runtime = (*Runtime)(nil) var _ vmr.Runtime = (*Runtime)(nil)
func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.ActorError) { func (rs *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.ActorError) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
if ar, ok := r.(aerrors.ActorError); ok { if ar, ok := r.(aerrors.ActorError); ok {
log.Warnf("VM.Call failure: %+v", ar) log.Errorf("VM.Call failure: %+v", ar)
aerr = ar aerr = ar
return return
} }
@@ -153,8 +149,8 @@ func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act
ret := f() ret := f()
if !rt.callerValidated { if !rs.callerValidated {
rt.Abortf(exitcode.SysErrorIllegalActor, "Caller MUST be validated during method execution") rs.Abortf(exitcode.SysErrorIllegalActor, "Caller MUST be validated during method execution")
} }
switch ret := ret.(type) { switch ret := ret.(type) {
@@ -175,25 +171,25 @@ func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act
} }
} }
func (rt *Runtime) Message() vmr.Message { func (rs *Runtime) Message() vmr.Message {
return rt.vmsg return rs.vmsg
} }
func (rt *Runtime) ValidateImmediateCallerAcceptAny() { func (rs *Runtime) ValidateImmediateCallerAcceptAny() {
rt.abortIfAlreadyValidated() rs.abortIfAlreadyValidated()
return return
} }
func (rt *Runtime) CurrentBalance() abi.TokenAmount { func (rs *Runtime) CurrentBalance() abi.TokenAmount {
b, err := rt.GetBalance(rt.Message().Receiver()) b, err := rs.GetBalance(rs.Message().Receiver())
if err != nil { if err != nil {
rt.Abortf(err.RetCode(), "get current balance: %v", err) rs.Abortf(err.RetCode(), "get current balance: %v", err)
} }
return b return b
} }
func (rt *Runtime) GetActorCodeCID(addr address.Address) (ret cid.Cid, ok bool) { func (rs *Runtime) GetActorCodeCID(addr address.Address) (ret cid.Cid, ok bool) {
act, err := rt.state.GetActor(addr) act, err := rs.state.GetActor(addr)
if err != nil { if err != nil {
if xerrors.Is(err, types.ErrActorNotFound) { if xerrors.Is(err, types.ErrActorNotFound) {
return cid.Undef, false return cid.Undef, false
@@ -213,8 +209,8 @@ func (rt *Runtime) GetRandomness(personalization crypto.DomainSeparationTag, ran
return res return res
} }
func (rt *Runtime) Store() vmr.Store { func (rs *Runtime) Store() vmr.Store {
return rt return rs
} }
func (rt *Runtime) NewActorAddress() address.Address { func (rt *Runtime) NewActorAddress() address.Address {
@@ -239,12 +235,12 @@ func (rt *Runtime) NewActorAddress() address.Address {
return addr return addr
} }
func (rt *Runtime) CreateActor(codeID cid.Cid, address address.Address) { func (rt *Runtime) CreateActor(codeId cid.Cid, address address.Address) {
if !builtin.IsBuiltinActor(codeID) { if !builtin.IsBuiltinActor(codeId) {
rt.Abortf(exitcode.SysErrorIllegalArgument, "Can only create built-in actors.") rt.Abortf(exitcode.SysErrorIllegalArgument, "Can only create built-in actors.")
} }
if builtin.IsSingletonActor(codeID) { if builtin.IsSingletonActor(codeId) {
rt.Abortf(exitcode.SysErrorIllegalArgument, "Can only have one instance of singleton actors.") rt.Abortf(exitcode.SysErrorIllegalArgument, "Can only have one instance of singleton actors.")
} }
@@ -253,10 +249,10 @@ func (rt *Runtime) CreateActor(codeID cid.Cid, address address.Address) {
rt.Abortf(exitcode.SysErrorIllegalArgument, "Actor address already exists") rt.Abortf(exitcode.SysErrorIllegalArgument, "Actor address already exists")
} }
rt.chargeGas(rt.Pricelist().OnCreateActor()) rt.ChargeGas(rt.Pricelist().OnCreateActor())
err = rt.state.SetActor(address, &types.Actor{ err = rt.state.SetActor(address, &types.Actor{
Code: codeID, Code: codeId,
Head: EmptyObjectCid, Head: EmptyObjectCid,
Nonce: 0, Nonce: 0,
Balance: big.Zero(), Balance: big.Zero(),
@@ -264,11 +260,10 @@ func (rt *Runtime) CreateActor(codeID cid.Cid, address address.Address) {
if err != nil { if err != nil {
panic(aerrors.Fatalf("creating actor entry: %v", err)) panic(aerrors.Fatalf("creating actor entry: %v", err))
} }
_ = rt.chargeGasSafe(gasOnActorExec)
} }
func (rt *Runtime) DeleteActor(addr address.Address) { func (rt *Runtime) DeleteActor(addr address.Address) {
rt.chargeGas(rt.Pricelist().OnDeleteActor()) rt.ChargeGas(rt.Pricelist().OnDeleteActor())
act, err := rt.state.GetActor(rt.Message().Receiver()) act, err := rt.state.GetActor(rt.Message().Receiver())
if err != nil { if err != nil {
if xerrors.Is(err, types.ErrActorNotFound) { if xerrors.Is(err, types.ErrActorNotFound) {
@@ -285,14 +280,14 @@ func (rt *Runtime) DeleteActor(addr address.Address) {
if err := rt.state.DeleteActor(rt.Message().Receiver()); err != nil { if err := rt.state.DeleteActor(rt.Message().Receiver()); err != nil {
panic(aerrors.Fatalf("failed to delete actor: %s", err)) panic(aerrors.Fatalf("failed to delete actor: %s", err))
} }
_ = rt.chargeGasSafe(gasOnActorExec)
} }
func (rt *Runtime) Syscalls() vmr.Syscalls { func (rs *Runtime) Syscalls() vmr.Syscalls {
return rt.sys // TODO: Make sure this is wrapped in something that charges gas for each of the calls
return rs.sys
} }
func (rt *Runtime) StartSpan(name string) vmr.TraceSpan { func (rs *Runtime) StartSpan(name string) vmr.TraceSpan {
panic("implement me") panic("implement me")
} }
@@ -312,12 +307,12 @@ func (rt *Runtime) Context() context.Context {
return rt.ctx return rt.ctx
} }
func (rt *Runtime) Abortf(code exitcode.ExitCode, msg string, args ...interface{}) { func (rs *Runtime) Abortf(code exitcode.ExitCode, msg string, args ...interface{}) {
log.Warnf("Abortf: " + fmt.Sprintf(msg, args...)) log.Error("Abortf: ", fmt.Sprintf(msg, args...))
panic(aerrors.NewfSkip(2, code, msg, args...)) panic(aerrors.NewfSkip(2, code, msg, args...))
} }
func (rt *Runtime) AbortStateMsg(msg string) { func (rs *Runtime) AbortStateMsg(msg string) {
panic(aerrors.NewfSkip(3, 101, msg)) panic(aerrors.NewfSkip(3, 101, msg))
} }
@@ -335,8 +330,8 @@ func (rt *Runtime) ValidateImmediateCallerType(ts ...cid.Cid) {
rt.Abortf(exitcode.SysErrForbidden, "caller cid type %q was not one of %v", callerCid, ts) rt.Abortf(exitcode.SysErrForbidden, "caller cid type %q was not one of %v", callerCid, ts)
} }
func (rt *Runtime) CurrEpoch() abi.ChainEpoch { func (rs *Runtime) CurrEpoch() abi.ChainEpoch {
return rt.height return rs.height
} }
type dumbWrapperType struct { type dumbWrapperType struct {
@@ -347,20 +342,20 @@ func (dwt *dumbWrapperType) Into(um vmr.CBORUnmarshaler) error {
return um.UnmarshalCBOR(bytes.NewReader(dwt.val)) return um.UnmarshalCBOR(bytes.NewReader(dwt.val))
} }
func (rt *Runtime) Send(to address.Address, method abi.MethodNum, m vmr.CBORMarshaler, value abi.TokenAmount) (vmr.SendReturn, exitcode.ExitCode) { func (rs *Runtime) Send(to address.Address, method abi.MethodNum, m vmr.CBORMarshaler, value abi.TokenAmount) (vmr.SendReturn, exitcode.ExitCode) {
if !rt.allowInternal { if !rs.allowInternal {
rt.Abortf(exitcode.SysErrorIllegalActor, "runtime.Send() is currently disallowed") rs.Abortf(exitcode.SysErrorIllegalActor, "runtime.Send() is currently disallowed")
} }
var params []byte var params []byte
if m != nil { if m != nil {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
if err := m.MarshalCBOR(buf); err != nil { if err := m.MarshalCBOR(buf); err != nil {
rt.Abortf(exitcode.SysErrInvalidParameters, "failed to marshal input parameters: %s", err) rs.Abortf(exitcode.SysErrInvalidParameters, "failed to marshal input parameters: %s", err)
} }
params = buf.Bytes() params = buf.Bytes()
} }
ret, err := rt.internalSend(rt.Message().Receiver(), to, method, value, params) ret, err := rs.internalSend(rs.Message().Receiver(), to, method, value, params)
if err != nil { if err != nil {
if err.IsFatal() { if err.IsFatal() {
panic(err) panic(err)
@@ -368,13 +363,10 @@ func (rt *Runtime) Send(to address.Address, method abi.MethodNum, m vmr.CBORMars
log.Warnf("vmctx send failed: to: %s, method: %d: ret: %d, err: %s", to, method, ret, err) log.Warnf("vmctx send failed: to: %s, method: %d: ret: %d, err: %s", to, method, ret, err)
return nil, err.RetCode() return nil, err.RetCode()
} }
_ = rt.chargeGasSafe(gasOnActorExec)
return &dumbWrapperType{ret}, 0 return &dumbWrapperType{ret}, 0
} }
func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum, value types.BigInt, params []byte) ([]byte, aerrors.ActorError) { func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum, value types.BigInt, params []byte) ([]byte, aerrors.ActorError) {
start := time.Now()
ctx, span := trace.StartSpan(rt.ctx, "vmc.Send") ctx, span := trace.StartSpan(rt.ctx, "vmc.Send")
defer span.End() defer span.End()
if span.IsRecordingEvents() { if span.IsRecordingEvents() {
@@ -400,62 +392,78 @@ func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum,
} }
defer st.ClearSnapshot() defer st.ClearSnapshot()
ret, errSend, subrt := rt.vm.send(ctx, msg, rt, nil, start) ret, errSend, subrt := rt.vm.send(ctx, msg, rt, 0)
if errSend != nil { if errSend != nil {
if errRevert := st.Revert(); errRevert != nil { if errRevert := st.Revert(); errRevert != nil {
return nil, aerrors.Escalate(errRevert, "failed to revert state tree after failed subcall") return nil, aerrors.Escalate(errRevert, "failed to revert state tree after failed subcall")
} }
} }
mr := types.MessageReceipt{
ExitCode: aerrors.RetCode(errSend),
Return: ret,
GasUsed: 0,
}
er := types.ExecutionResult{
Msg: msg,
MsgRct: &mr,
}
if errSend != nil {
er.Error = errSend.Error()
}
if subrt != nil { if subrt != nil {
er.Subcalls = subrt.internalExecutions
rt.numActorsCreated = subrt.numActorsCreated rt.numActorsCreated = subrt.numActorsCreated
} }
rt.executionTrace.Subcalls = append(rt.executionTrace.Subcalls, subrt.executionTrace) rt.internalExecutions = append(rt.internalExecutions, &er)
return ret, errSend return ret, errSend
} }
func (rt *Runtime) State() vmr.StateHandle { func (rs *Runtime) State() vmr.StateHandle {
return &shimStateHandle{rt: rt} return &shimStateHandle{rs: rs}
} }
type shimStateHandle struct { type shimStateHandle struct {
rt *Runtime rs *Runtime
} }
func (ssh *shimStateHandle) Create(obj vmr.CBORMarshaler) { func (ssh *shimStateHandle) Create(obj vmr.CBORMarshaler) {
c := ssh.rt.Put(obj) c := ssh.rs.Put(obj)
// TODO: handle error below // TODO: handle error below
ssh.rt.stateCommit(EmptyObjectCid, c) ssh.rs.stateCommit(EmptyObjectCid, c)
} }
func (ssh *shimStateHandle) Readonly(obj vmr.CBORUnmarshaler) { func (ssh *shimStateHandle) Readonly(obj vmr.CBORUnmarshaler) {
act, err := ssh.rt.state.GetActor(ssh.rt.Message().Receiver()) act, err := ssh.rs.state.GetActor(ssh.rs.Message().Receiver())
if err != nil { if err != nil {
ssh.rt.Abortf(exitcode.SysErrorIllegalArgument, "failed to get actor for Readonly state: %s", err) ssh.rs.Abortf(exitcode.SysErrorIllegalArgument, "failed to get actor for Readonly state: %s", err)
} }
ssh.rt.Get(act.Head, obj) ssh.rs.Get(act.Head, obj)
} }
func (ssh *shimStateHandle) Transaction(obj vmr.CBORer, f func() interface{}) interface{} { func (ssh *shimStateHandle) Transaction(obj vmr.CBORer, f func() interface{}) interface{} {
if obj == nil { if obj == nil {
ssh.rt.Abortf(exitcode.SysErrorIllegalActor, "Must not pass nil to Transaction()") ssh.rs.Abortf(exitcode.SysErrorIllegalActor, "Must not pass nil to Transaction()")
} }
act, err := ssh.rt.state.GetActor(ssh.rt.Message().Receiver()) act, err := ssh.rs.state.GetActor(ssh.rs.Message().Receiver())
if err != nil { if err != nil {
ssh.rt.Abortf(exitcode.SysErrorIllegalActor, "failed to get actor for Transaction: %s", err) ssh.rs.Abortf(exitcode.SysErrorIllegalActor, "failed to get actor for Transaction: %s", err)
} }
baseState := act.Head baseState := act.Head
ssh.rt.Get(baseState, obj) ssh.rs.Get(baseState, obj)
ssh.rt.allowInternal = false ssh.rs.allowInternal = false
out := f() out := f()
ssh.rt.allowInternal = true ssh.rs.allowInternal = true
c := ssh.rt.Put(obj) c := ssh.rs.Put(obj)
// TODO: handle error below // TODO: handle error below
ssh.rt.stateCommit(baseState, c) ssh.rs.stateCommit(baseState, c)
return out return out
} }
@@ -492,78 +500,22 @@ func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
return nil return nil
} }
func (rt *Runtime) finilizeGasTracing() { func (rt *Runtime) ChargeGas(toUse int64) {
if rt.lastGasCharge != nil { err := rt.chargeGasSafe(toUse)
rt.lastGasCharge.TimeTaken = time.Since(rt.lastGasChargeTime)
}
}
// ChargeGas is spec actors function
func (rt *Runtime) ChargeGas(name string, compute int64, virtual int64) {
err := rt.chargeGasInternal(newGasCharge(name, compute, 0).WithVirtual(virtual, 0), 1)
if err != nil { if err != nil {
panic(err) panic(err)
} }
} }
func (rt *Runtime) chargeGas(gas GasCharge) { func (rt *Runtime) chargeGasSafe(toUse int64) aerrors.ActorError {
err := rt.chargeGasInternal(gas, 1)
if err != nil {
panic(err)
}
}
func (rt *Runtime) chargeGasFunc(skip int) func(GasCharge) {
return func(gas GasCharge) {
err := rt.chargeGasInternal(gas, 1+skip)
if err != nil {
panic(err)
}
}
}
func (rt *Runtime) chargeGasInternal(gas GasCharge, skip int) aerrors.ActorError {
toUse := gas.Total()
var callers [10]uintptr
cout := gruntime.Callers(2+skip, callers[:])
now := time.Now()
if rt.lastGasCharge != nil {
rt.lastGasCharge.TimeTaken = now.Sub(rt.lastGasChargeTime)
}
gasTrace := types.GasTrace{
Name: gas.Name,
Extra: gas.Extra,
TotalGas: toUse,
ComputeGas: gas.ComputeGas,
StorageGas: gas.StorageGas,
TotalVirtualGas: gas.VirtualCompute*GasComputeMulti + gas.VirtualStorage*GasStorageMulti,
VirtualComputeGas: gas.VirtualCompute,
VirtualStorageGas: gas.VirtualStorage,
Callers: callers[:cout],
}
rt.executionTrace.GasCharges = append(rt.executionTrace.GasCharges, &gasTrace)
rt.lastGasChargeTime = now
rt.lastGasCharge = &gasTrace
if rt.gasUsed+toUse > rt.gasAvailable { if rt.gasUsed+toUse > rt.gasAvailable {
rt.gasUsed = rt.gasAvailable rt.gasUsed = rt.gasAvailable
return aerrors.Newf(exitcode.SysErrOutOfGas, "not enough gas: used=%d, available=%d", return aerrors.Newf(exitcode.SysErrOutOfGas, "not enough gas: used=%d, available=%d", rt.gasUsed, rt.gasAvailable)
rt.gasUsed, rt.gasAvailable)
} }
rt.gasUsed += toUse rt.gasUsed += toUse
return nil return nil
} }
func (rt *Runtime) chargeGasSafe(gas GasCharge) aerrors.ActorError {
return rt.chargeGasInternal(gas, 1)
}
func (rt *Runtime) Pricelist() Pricelist { func (rt *Runtime) Pricelist() Pricelist {
return rt.pricelist return rt.pricelist
} }
+18 -13
View File
@@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
goruntime "runtime"
"sync" "sync"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
@@ -43,7 +42,7 @@ type syscallShim struct {
verifier ffiwrapper.Verifier verifier ffiwrapper.Verifier
} }
func (ss *syscallShim) ComputeUnsealedSectorCID(st abi.RegisteredSealProof, pieces []abi.PieceInfo) (cid.Cid, error) { func (ss *syscallShim) ComputeUnsealedSectorCID(st abi.RegisteredProof, pieces []abi.PieceInfo) (cid.Cid, error) {
var sum abi.PaddedPieceSize var sum abi.PaddedPieceSize
for _, p := range pieces { for _, p := range pieces {
sum += p.Size sum += p.Size
@@ -115,7 +114,7 @@ func (ss *syscallShim) VerifyConsensusFault(a, b, extra []byte) (*runtime.Consen
// (b) time-offset mining fault // (b) time-offset mining fault
// strictly speaking no need to compare heights based on double fork mining check above, // strictly speaking no need to compare heights based on double fork mining check above,
// but at same height this would be a different fault. // but at same height this would be a different fault.
if types.CidArrsEqual(blockA.Parents, blockB.Parents) && blockA.Height != blockB.Height { if !types.CidArrsEqual(blockA.Parents, blockB.Parents) && blockA.Height != blockB.Height {
consensusFault = &runtime.ConsensusFault{ consensusFault = &runtime.ConsensusFault{
Target: blockA.Miner, Target: blockA.Miner,
Epoch: blockB.Height, Epoch: blockB.Height,
@@ -159,7 +158,7 @@ func (ss *syscallShim) VerifyConsensusFault(a, b, extra []byte) (*runtime.Consen
} }
if sigErr := ss.VerifyBlockSig(&blockB); sigErr != nil { if sigErr := ss.VerifyBlockSig(&blockB); sigErr != nil {
return nil, xerrors.Errorf("cannot verify second block sig: %w", sigErr) return nil, xerrors.Errorf("cannot verify first block sig: %w", sigErr)
} }
return consensusFault, nil return consensusFault, nil
@@ -185,7 +184,7 @@ func (ss *syscallShim) VerifyBlockSig(blk *types.BlockHeader) error {
return err return err
} }
if err := sigs.CheckBlockSignature(ss.ctx, blk, waddr); err != nil { if err := sigs.CheckBlockSignature(blk, ss.ctx, waddr); err != nil {
return err return err
} }
@@ -203,6 +202,20 @@ func (ss *syscallShim) VerifyPoSt(proof abi.WindowPoStVerifyInfo) error {
return nil return nil
} }
func cidToCommD(c cid.Cid) [32]byte {
b := c.Bytes()
var out [32]byte
copy(out[:], b[len(b)-32:])
return out
}
func cidToCommR(c cid.Cid) [32]byte {
b := c.Bytes()
var out [32]byte
copy(out[:], b[len(b)-32:])
return out
}
func (ss *syscallShim) VerifySeal(info abi.SealVerifyInfo) error { func (ss *syscallShim) VerifySeal(info abi.SealVerifyInfo) error {
//_, span := trace.StartSpan(ctx, "ValidatePoRep") //_, span := trace.StartSpan(ctx, "ValidatePoRep")
//defer span.End() //defer span.End()
@@ -241,13 +254,9 @@ func (ss *syscallShim) VerifySignature(sig crypto.Signature, addr address.Addres
return sigs.Verify(&sig, kaddr, input) return sigs.Verify(&sig, kaddr, input)
} }
var BatchSealVerifyParallelism = goruntime.NumCPU()
func (ss *syscallShim) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) { func (ss *syscallShim) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) {
out := make(map[address.Address][]bool) out := make(map[address.Address][]bool)
sema := make(chan struct{}, BatchSealVerifyParallelism)
var wg sync.WaitGroup var wg sync.WaitGroup
for addr, seals := range inp { for addr, seals := range inp {
results := make([]bool, len(seals)) results := make([]bool, len(seals))
@@ -257,16 +266,12 @@ func (ss *syscallShim) BatchVerifySeals(inp map[address.Address][]abi.SealVerify
wg.Add(1) wg.Add(1)
go func(ma address.Address, ix int, svi abi.SealVerifyInfo, res []bool) { go func(ma address.Address, ix int, svi abi.SealVerifyInfo, res []bool) {
defer wg.Done() defer wg.Done()
sema <- struct{}{}
if err := ss.VerifySeal(svi); err != nil { if err := ss.VerifySeal(svi); err != nil {
log.Warnw("seal verify in batch failed", "miner", ma, "index", ix, "err", err) log.Warnw("seal verify in batch failed", "miner", ma, "index", ix, "err", err)
res[ix] = false res[ix] = false
} else { } else {
res[ix] = true res[ix] = true
} }
<-sema
}(addr, i, s, results) }(addr, i, s, results)
} }
} }
+55 -94
View File
@@ -35,7 +35,6 @@ import (
) )
var log = logging.Logger("vm") var log = logging.Logger("vm")
var gasOnActorExec = newGasCharge("OnActorExec", 0, 0)
// ResolveToKeyAddr returns the public key type of address (`BLS`/`SECP256K1`) of an account actor identified by `addr`. // ResolveToKeyAddr returns the public key type of address (`BLS`/`SECP256K1`) of an account actor identified by `addr`.
func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Address) (address.Address, aerrors.ActorError) { func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Address) (address.Address, aerrors.ActorError) {
@@ -63,19 +62,17 @@ func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Ad
var _ cbor.IpldBlockstore = (*gasChargingBlocks)(nil) var _ cbor.IpldBlockstore = (*gasChargingBlocks)(nil)
type gasChargingBlocks struct { type gasChargingBlocks struct {
chargeGas func(GasCharge) chargeGas func(int64)
pricelist Pricelist pricelist Pricelist
under cbor.IpldBlockstore under cbor.IpldBlockstore
} }
func (bs *gasChargingBlocks) Get(c cid.Cid) (block.Block, error) { func (bs *gasChargingBlocks) Get(c cid.Cid) (block.Block, error) {
bs.chargeGas(newGasCharge("OnIpldGetStart", 0, 0))
blk, err := bs.under.Get(c) blk, err := bs.under.Get(c)
if err != nil { if err != nil {
return nil, aerrors.Escalate(err, "failed to get block from blockstore") return nil, aerrors.Escalate(err, "failed to get block from blockstore")
} }
bs.chargeGas(bs.pricelist.OnIpldGet(len(blk.RawData()))) bs.chargeGas(bs.pricelist.OnIpldGet(len(blk.RawData())))
bs.chargeGas(gasOnActorExec)
return blk, nil return blk, nil
} }
@@ -86,7 +83,6 @@ func (bs *gasChargingBlocks) Put(blk block.Block) error {
if err := bs.under.Put(blk); err != nil { if err := bs.under.Put(blk); err != nil {
return aerrors.Escalate(err, "failed to write data to disk") return aerrors.Escalate(err, "failed to write data to disk")
} }
bs.chargeGas(gasOnActorExec)
return nil return nil
} }
@@ -106,16 +102,15 @@ func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, origin addres
pricelist: PricelistByEpoch(vm.blockHeight), pricelist: PricelistByEpoch(vm.blockHeight),
allowInternal: true, allowInternal: true,
callerValidated: false, callerValidated: false,
executionTrace: types.ExecutionTrace{Msg: msg},
} }
rt.cst = &cbor.BasicIpldStore{ rt.cst = &cbor.BasicIpldStore{
Blocks: &gasChargingBlocks{rt.chargeGasFunc(2), rt.pricelist, vm.cst.Blocks}, Blocks: &gasChargingBlocks{rt.ChargeGas, rt.pricelist, vm.cst.Blocks},
Atlas: vm.cst.Atlas, Atlas: vm.cst.Atlas,
} }
rt.sys = pricedSyscalls{ rt.sys = pricedSyscalls{
under: vm.Syscalls, under: vm.Syscalls,
chargeGas: rt.chargeGasFunc(1), chargeGas: rt.ChargeGas,
pl: rt.pricelist, pl: rt.pricelist,
} }
@@ -136,7 +131,7 @@ type VM struct {
cst *cbor.BasicIpldStore cst *cbor.BasicIpldStore
buf *bufbstore.BufferedBS buf *bufbstore.BufferedBS
blockHeight abi.ChainEpoch blockHeight abi.ChainEpoch
inv *Invoker inv *invoker
rand Rand rand Rand
Syscalls runtime.Syscalls Syscalls runtime.Syscalls
@@ -168,93 +163,63 @@ type Rand interface {
type ApplyRet struct { type ApplyRet struct {
types.MessageReceipt types.MessageReceipt
ActorErr aerrors.ActorError ActorErr aerrors.ActorError
Penalty types.BigInt Penalty types.BigInt
ExecutionTrace types.ExecutionTrace InternalExecutions []*types.ExecutionResult
Duration time.Duration Duration time.Duration
} }
func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime, func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
gasCharge *GasCharge, start time.Time) ([]byte, aerrors.ActorError, *Runtime) { gasCharge int64) ([]byte, aerrors.ActorError, *Runtime) {
st := vm.cstate st := vm.cstate
gasUsed := gasCharge
origin := msg.From origin := msg.From
on := msg.Nonce on := msg.Nonce
var nac uint64 = 0 var nac uint64 = 0
var gasUsed int64
if parent != nil { if parent != nil {
gasUsed = parent.gasUsed gasUsed = parent.gasUsed + gasUsed
origin = parent.origin origin = parent.origin
on = parent.originNonce on = parent.originNonce
nac = parent.numActorsCreated nac = parent.numActorsCreated
} }
rt := vm.makeRuntime(ctx, msg, origin, on, gasUsed, nac) rt := vm.makeRuntime(ctx, msg, origin, on, gasUsed, nac)
rt.lastGasChargeTime = start
if parent != nil { if parent != nil {
rt.lastGasChargeTime = parent.lastGasChargeTime
rt.lastGasCharge = parent.lastGasCharge
defer func() { defer func() {
parent.gasUsed = rt.gasUsed parent.gasUsed = rt.gasUsed
parent.lastGasChargeTime = rt.lastGasChargeTime
parent.lastGasCharge = rt.lastGasCharge
}() }()
} }
if gasCharge != nil { if aerr := rt.chargeGasSafe(rt.Pricelist().OnMethodInvocation(msg.Value, msg.Method)); aerr != nil {
if err := rt.chargeGasSafe(*gasCharge); err != nil { return nil, aerrors.Wrap(aerr, "not enough gas for method invocation"), rt
// this should never happen
return nil, aerrors.Wrap(err, "not enough gas for initial message charge, this should not happen"), rt
}
} }
ret, err := func() ([]byte, aerrors.ActorError) { toActor, err := st.GetActor(msg.To)
if aerr := rt.chargeGasSafe(rt.Pricelist().OnMethodInvocation(msg.Value, msg.Method)); aerr != nil {
return nil, aerrors.Wrap(aerr, "not enough gas for method invocation")
}
toActor, err := st.GetActor(msg.To)
if err != nil {
if xerrors.Is(err, init_.ErrAddressNotFound) {
a, err := TryCreateAccountActor(rt, msg.To)
if err != nil {
return nil, aerrors.Wrapf(err, "could not create account")
}
toActor = a
} else {
return nil, aerrors.Escalate(err, "getting actor")
}
}
if types.BigCmp(msg.Value, types.NewInt(0)) != 0 {
if err := vm.transfer(msg.From, msg.To, msg.Value); err != nil {
return nil, aerrors.Wrap(err, "failed to transfer funds")
}
}
if msg.Method != 0 {
var ret []byte
_ = rt.chargeGasSafe(gasOnActorExec)
ret, err := vm.Invoke(toActor, rt, msg.Method, msg.Params)
_ = rt.chargeGasSafe(newGasCharge("OnActorExecDone", 0, 0))
return ret, err
}
return nil, nil
}()
mr := types.MessageReceipt{
ExitCode: aerrors.RetCode(err),
Return: ret,
GasUsed: rt.gasUsed,
}
rt.executionTrace.MsgRct = &mr
rt.executionTrace.Duration = time.Since(start)
if err != nil { if err != nil {
rt.executionTrace.Error = err.Error() if xerrors.Is(err, init_.ErrAddressNotFound) {
a, err := TryCreateAccountActor(rt, msg.To)
if err != nil {
return nil, aerrors.Wrapf(err, "could not create account"), rt
}
toActor = a
} else {
return nil, aerrors.Escalate(err, "getting actor"), rt
}
} }
return ret, err, rt if types.BigCmp(msg.Value, types.NewInt(0)) != 0 {
if err := vm.transfer(msg.From, msg.To, msg.Value); err != nil {
return nil, aerrors.Wrap(err, "failed to transfer funds"), nil
}
}
if msg.Method != 0 {
ret, err := vm.Invoke(toActor, rt, msg.Method, msg.Params)
return ret, err, rt
}
return nil, nil, rt
} }
func checkMessage(msg *types.Message) error { func checkMessage(msg *types.Message) error {
@@ -278,18 +243,17 @@ func checkMessage(msg *types.Message) error {
func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*ApplyRet, error) { func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*ApplyRet, error) {
start := time.Now() start := time.Now()
ret, actorErr, rt := vm.send(ctx, msg, nil, nil, start) ret, actorErr, rt := vm.send(ctx, msg, nil, 0)
rt.finilizeGasTracing()
return &ApplyRet{ return &ApplyRet{
MessageReceipt: types.MessageReceipt{ MessageReceipt: types.MessageReceipt{
ExitCode: aerrors.RetCode(actorErr), ExitCode: aerrors.RetCode(actorErr),
Return: ret, Return: ret,
GasUsed: 0, GasUsed: 0,
}, },
ActorErr: actorErr, ActorErr: actorErr,
ExecutionTrace: rt.executionTrace, InternalExecutions: rt.internalExecutions,
Penalty: types.NewInt(0), Penalty: types.NewInt(0),
Duration: time.Since(start), Duration: time.Since(start),
}, actorErr }, actorErr
} }
@@ -312,8 +276,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
pl := PricelistByEpoch(vm.blockHeight) pl := PricelistByEpoch(vm.blockHeight)
msgGas := pl.OnChainMessage(cmsg.ChainLength()) msgGasCost := pl.OnChainMessage(cmsg.ChainLength())
msgGasCost := msgGas.Total()
// this should never happen, but is currently still exercised by some tests // this should never happen, but is currently still exercised by some tests
if msgGasCost > msg.GasLimit { if msgGasCost > msg.GasLimit {
return &ApplyRet{ return &ApplyRet{
@@ -396,7 +359,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
} }
defer st.ClearSnapshot() defer st.ClearSnapshot()
ret, actorErr, rt := vm.send(ctx, msg, nil, &msgGas, start) ret, actorErr, rt := vm.send(ctx, msg, nil, msgGasCost)
if aerrors.IsFatal(actorErr) { if aerrors.IsFatal(actorErr) {
return nil, xerrors.Errorf("[from=%s,to=%s,n=%d,m=%d,h=%d] fatal error: %w", msg.From, msg.To, msg.Nonce, msg.Method, vm.blockHeight, actorErr) return nil, xerrors.Errorf("[from=%s,to=%s,n=%d,m=%d,h=%d] fatal error: %w", msg.From, msg.To, msg.Nonce, msg.Method, vm.blockHeight, actorErr)
} }
@@ -450,18 +413,16 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
return nil, xerrors.Errorf("gas handling math is wrong") return nil, xerrors.Errorf("gas handling math is wrong")
} }
rt.finilizeGasTracing()
return &ApplyRet{ return &ApplyRet{
MessageReceipt: types.MessageReceipt{ MessageReceipt: types.MessageReceipt{
ExitCode: errcode, ExitCode: errcode,
Return: ret, Return: ret,
GasUsed: gasUsed, GasUsed: gasUsed,
}, },
ActorErr: actorErr, ActorErr: actorErr,
ExecutionTrace: rt.executionTrace, InternalExecutions: rt.internalExecutions,
Penalty: types.NewInt(0), Penalty: types.NewInt(0),
Duration: time.Since(start), Duration: time.Since(start),
}, nil }, nil
} }
@@ -493,7 +454,7 @@ func (vm *VM) Flush(ctx context.Context) (cid.Cid, error) {
return root, nil return root, nil
} }
// MutateState usage: MutateState(ctx, idAddr, func(cst cbor.IpldStore, st *ActorStateType) error {...}) // vm.MutateState(idAddr, func(cst cbor.IpldStore, st *ActorStateType) error {...})
func (vm *VM) MutateState(ctx context.Context, addr address.Address, fn interface{}) error { func (vm *VM) MutateState(ctx context.Context, addr address.Address, fn interface{}) error {
act, err := vm.cstate.GetActor(addr) act, err := vm.cstate.GetActor(addr)
if err != nil { if err != nil {
@@ -630,7 +591,7 @@ func (vm *VM) Invoke(act *types.Actor, rt *Runtime, method abi.MethodNum, params
return ret, nil return ret, nil
} }
func (vm *VM) SetInvoker(i *Invoker) { func (vm *VM) SetInvoker(i *invoker) {
vm.inv = i vm.inv = i
} }
@@ -646,17 +607,17 @@ func (vm *VM) transfer(from, to address.Address, amt types.BigInt) aerrors.Actor
return nil return nil
} }
fromID, err := vm.cstate.LookupID(from) fromId, err := vm.cstate.LookupID(from)
if err != nil { if err != nil {
return aerrors.Fatalf("transfer failed when resolving sender address: %s", err) return aerrors.Fatalf("transfer failed when resolving sender address: %s", err)
} }
toID, err := vm.cstate.LookupID(to) toId, err := vm.cstate.LookupID(to)
if err != nil { if err != nil {
return aerrors.Fatalf("transfer failed when resolving receiver address: %s", err) return aerrors.Fatalf("transfer failed when resolving receiver address: %s", err)
} }
if fromID == toID { if fromId == toId {
return nil return nil
} }
@@ -664,12 +625,12 @@ func (vm *VM) transfer(from, to address.Address, amt types.BigInt) aerrors.Actor
return aerrors.Newf(exitcode.SysErrForbidden, "attempted to transfer negative value: %s", amt) return aerrors.Newf(exitcode.SysErrForbidden, "attempted to transfer negative value: %s", amt)
} }
f, err := vm.cstate.GetActor(fromID) f, err := vm.cstate.GetActor(fromId)
if err != nil { if err != nil {
return aerrors.Fatalf("transfer failed when retrieving sender actor: %s", err) return aerrors.Fatalf("transfer failed when retrieving sender actor: %s", err)
} }
t, err := vm.cstate.GetActor(toID) t, err := vm.cstate.GetActor(toId)
if err != nil { if err != nil {
return aerrors.Fatalf("transfer failed when retrieving receiver actor: %s", err) return aerrors.Fatalf("transfer failed when retrieving receiver actor: %s", err)
} }
@@ -679,11 +640,11 @@ func (vm *VM) transfer(from, to address.Address, amt types.BigInt) aerrors.Actor
} }
depositFunds(t, amt) depositFunds(t, amt)
if err := vm.cstate.SetActor(fromID, f); err != nil { if err := vm.cstate.SetActor(fromId, f); err != nil {
return aerrors.Fatalf("transfer failed when setting receiver actor: %s", err) return aerrors.Fatalf("transfer failed when setting receiver actor: %s", err)
} }
if err := vm.cstate.SetActor(toID, t); err != nil { if err := vm.cstate.SetActor(toId, t); err != nil {
return aerrors.Fatalf("transfer failed when setting sender actor: %s", err) return aerrors.Fatalf("transfer failed when setting sender actor: %s", err)
} }
+4 -22
View File
@@ -22,11 +22,10 @@ import (
var log = logging.Logger("wallet") var log = logging.Logger("wallet")
const ( const (
KNamePrefix = "wallet-" KNamePrefix = "wallet-"
KTrashPrefix = "trash-" KDefault = "default"
KDefault = "default" KTBLS = "bls"
KTBLS = "bls" KTSecp256k1 = "secp256k1"
KTSecp256k1 = "secp256k1"
) )
type Wallet struct { type Wallet struct {
@@ -231,23 +230,6 @@ func (w *Wallet) HasKey(addr address.Address) (bool, error) {
return k != nil, nil return k != nil, nil
} }
func (w *Wallet) DeleteKey(addr address.Address) error {
k, err := w.findKey(addr)
if err != nil {
return xerrors.Errorf("failed to delete key %s : %w", addr, err)
}
if err := w.keystore.Put(KTrashPrefix+k.Address.String(), k.KeyInfo); err != nil {
return xerrors.Errorf("failed to mark key %s as trashed: %w", addr, err)
}
if err := w.keystore.Delete(KNamePrefix + k.Address.String()); err != nil {
return xerrors.Errorf("failed to delete key %s: %w", addr, err)
}
return nil
}
type Key struct { type Key struct {
types.KeyInfo types.KeyInfo
+1 -1
View File
@@ -3,8 +3,8 @@ package cli
import ( import (
"fmt" "fmt"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"gopkg.in/urfave/cli.v2"
"github.com/filecoin-project/go-jsonrpc/auth" "github.com/filecoin-project/go-jsonrpc/auth"
+7 -38
View File
@@ -12,6 +12,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/docker/go-units"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
cborutil "github.com/filecoin-project/go-cbor-util" cborutil "github.com/filecoin-project/go-cbor-util"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
@@ -22,9 +23,9 @@ import (
"github.com/filecoin-project/specs-actors/actors/builtin/power" "github.com/filecoin-project/specs-actors/actors/builtin/power"
"github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/specs-actors/actors/util/adt"
cid "github.com/ipfs/go-cid" cid "github.com/ipfs/go-cid"
"github.com/urfave/cli/v2"
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"gopkg.in/urfave/cli.v2"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors"
@@ -221,9 +222,6 @@ var chainStatObjCmd = &cli.Command{
base := cid.Undef base := cid.Undef
if cctx.IsSet("base") { if cctx.IsSet("base") {
base, err = cid.Decode(cctx.String("base")) base, err = cid.Decode(cctx.String("base"))
if err != nil {
return err
}
} }
stats, err := api.ChainStatObj(ctx, obj, base) stats, err := api.ChainStatObj(ctx, obj, base)
@@ -232,7 +230,7 @@ var chainStatObjCmd = &cli.Command{
} }
fmt.Printf("Links: %d\n", stats.Links) fmt.Printf("Links: %d\n", stats.Links)
fmt.Printf("Size: %s (%d)\n", types.SizeStr(types.NewInt(stats.Size)), stats.Size) fmt.Printf("Size: %s (%d)\n", units.BytesSize(float64(stats.Size)), stats.Size)
return nil return nil
}, },
} }
@@ -444,8 +442,7 @@ var chainGetCmd = &cli.Command{
- /ipfs/[cid]/@Hi:123 - get varint elem 123 from hamt - /ipfs/[cid]/@Hi:123 - get varint elem 123 from hamt
- /ipfs/[cid]/@Hu:123 - get uvarint elem 123 from hamt - /ipfs/[cid]/@Hu:123 - get uvarint elem 123 from hamt
- /ipfs/[cid]/@Ha:t01 - get element under Addr(t01).Bytes - /ipfs/[cid]/@Ha:t01 - get element under Addr(t01).Bytes
- /ipfs/[cid]/@A:10 - get 10th amt element - /ipfs/[cid]/@A:10 - get 10th amt element
- .../@Ha:t01/@state - get pretty map-based actor state
List of --as-type types: List of --as-type types:
- raw - raw
@@ -844,10 +841,6 @@ var slashConsensusFault = &cli.Command{
Name: "miner", Name: "miner",
Usage: "Miner address", Usage: "Miner address",
}, },
&cli.StringFlag{
Name: "extra",
Usage: "Extra block cid",
},
}, },
Action: func(cctx *cli.Context) error { Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx) api, closer, err := GetFullNodeAPI(cctx)
@@ -892,34 +885,10 @@ var slashConsensusFault = &cli.Command{
return err return err
} }
params := miner.ReportConsensusFaultParams{ params, err := actors.SerializeParams(&miner.ReportConsensusFaultParams{
BlockHeader1: bh1, BlockHeader1: bh1,
BlockHeader2: bh2, BlockHeader2: bh2,
} })
if cctx.String("extra") != "" {
cExtra, err := cid.Parse(cctx.String("extra"))
if err != nil {
return xerrors.Errorf("parsing cid extra: %w", err)
}
bExtra, err := api.ChainGetBlock(ctx, cExtra)
if err != nil {
return xerrors.Errorf("getting block extra: %w", err)
}
be, err := cborutil.Dump(bExtra)
if err != nil {
return err
}
params.BlockHeaderExtra = be
}
enc, err := actors.SerializeParams(&params)
if err != nil {
return err
}
if cctx.String("miner") == "" { if cctx.String("miner") == "" {
return xerrors.Errorf("--miner flag is required") return xerrors.Errorf("--miner flag is required")
@@ -937,7 +906,7 @@ var slashConsensusFault = &cli.Command{
GasPrice: types.NewInt(1), GasPrice: types.NewInt(1),
GasLimit: 10000000, GasLimit: 10000000,
Method: builtin.MethodsMiner.ReportConsensusFault, Method: builtin.MethodsMiner.ReportConsensusFault,
Params: enc, Params: params,
} }
smsg, err := api.MpoolPushMessage(ctx, msg) smsg, err := api.MpoolPushMessage(ctx, msg)
+29 -115
View File
@@ -8,48 +8,19 @@ import (
"text/tabwriter" "text/tabwriter"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"github.com/ipfs/go-cidutil/cidenc"
"github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/peer"
"github.com/multiformats/go-multibase"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"gopkg.in/urfave/cli.v2"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-fil-markets/storagemarket"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/specs-actors/actors/builtin/market"
"github.com/filecoin-project/lotus/api"
lapi "github.com/filecoin-project/lotus/api" lapi "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
) )
var CidBaseFlag = cli.StringFlag{
Name: "cid-base",
Hidden: true,
Value: "base32",
Usage: "Multibase encoding used for version 1 CIDs in output.",
DefaultText: "base32",
}
// GetCidEncoder returns an encoder using the `cid-base` flag if provided, or
// the default (Base32) encoder if not.
func GetCidEncoder(cctx *cli.Context) (cidenc.Encoder, error) {
val := cctx.String("cid-base")
e := cidenc.Encoder{Base: multibase.MustNewEncoder(multibase.Base32)}
if val != "" {
var err error
e.Base, err = multibase.EncoderByName(val)
if err != nil {
return e, err
}
}
return e, nil
}
var clientCmd = &cli.Command{ var clientCmd = &cli.Command{
Name: "client", Name: "client",
Usage: "Make deals, store data, retrieve data", Usage: "Make deals, store data, retrieve data",
@@ -75,7 +46,6 @@ var clientImportCmd = &cli.Command{
Name: "car", Name: "car",
Usage: "import from a car file instead of a regular file", Usage: "import from a car file instead of a regular file",
}, },
&CidBaseFlag,
}, },
Action: func(cctx *cli.Context) error { Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx) api, closer, err := GetFullNodeAPI(cctx)
@@ -84,11 +54,6 @@ var clientImportCmd = &cli.Command{
} }
defer closer() defer closer()
ctx := ReqContext(cctx) ctx := ReqContext(cctx)
if cctx.NArg() != 1 {
return xerrors.New("expected input path as the only arg")
}
absPath, err := filepath.Abs(cctx.Args().First()) absPath, err := filepath.Abs(cctx.Args().First())
if err != nil { if err != nil {
return err return err
@@ -102,14 +67,7 @@ var clientImportCmd = &cli.Command{
if err != nil { if err != nil {
return err return err
} }
fmt.Println(c.String())
encoder, err := GetCidEncoder(cctx)
if err != nil {
return err
}
fmt.Println(encoder.Encode(c))
return nil return nil
}, },
} }
@@ -118,9 +76,6 @@ var clientCommPCmd = &cli.Command{
Name: "commP", Name: "commP",
Usage: "calculate the piece-cid (commP) of a CAR file", Usage: "calculate the piece-cid (commP) of a CAR file",
ArgsUsage: "[inputFile minerAddress]", ArgsUsage: "[inputFile minerAddress]",
Flags: []cli.Flag{
&CidBaseFlag,
},
Action: func(cctx *cli.Context) error { Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx) api, closer, err := GetFullNodeAPI(cctx)
if err != nil { if err != nil {
@@ -139,17 +94,12 @@ var clientCommPCmd = &cli.Command{
} }
ret, err := api.ClientCalcCommP(ctx, cctx.Args().Get(0), miner) ret, err := api.ClientCalcCommP(ctx, cctx.Args().Get(0), miner)
if err != nil { if err != nil {
return err return err
} }
fmt.Println("CID: ", ret.Root)
encoder, err := GetCidEncoder(cctx) fmt.Println("Piece size: ", ret.Size)
if err != nil {
return err
}
fmt.Println("CID: ", encoder.Encode(ret.Root))
fmt.Println("Piece size: ", types.SizeStr(types.NewInt(uint64(ret.Size))))
return nil return nil
}, },
} }
@@ -187,9 +137,6 @@ var clientCarGenCmd = &cli.Command{
var clientLocalCmd = &cli.Command{ var clientLocalCmd = &cli.Command{
Name: "local", Name: "local",
Usage: "List locally imported data", Usage: "List locally imported data",
Flags: []cli.Flag{
&CidBaseFlag,
},
Action: func(cctx *cli.Context) error { Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx) api, closer, err := GetFullNodeAPI(cctx)
if err != nil { if err != nil {
@@ -202,14 +149,8 @@ var clientLocalCmd = &cli.Command{
if err != nil { if err != nil {
return err return err
} }
encoder, err := GetCidEncoder(cctx)
if err != nil {
return err
}
for _, v := range list { for _, v := range list {
fmt.Printf("%s %s %s %s\n", encoder.Encode(v.Key), v.FilePath, types.SizeStr(types.NewInt(v.Size)), v.Status) fmt.Printf("%s %s %d %s\n", v.Key, v.FilePath, v.Size, v.Status)
} }
return nil return nil
}, },
@@ -237,7 +178,6 @@ var clientDealCmd = &cli.Command{
Usage: "specify the epoch that the deal should start at", Usage: "specify the epoch that the deal should start at",
Value: -1, Value: -1,
}, },
&CidBaseFlag,
}, },
Action: func(cctx *cli.Context) error { Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx) api, closer, err := GetFullNodeAPI(cctx)
@@ -323,13 +263,7 @@ var clientDealCmd = &cli.Command{
return err return err
} }
encoder, err := GetCidEncoder(cctx) fmt.Println(proposal)
if err != nil {
return err
}
fmt.Println(encoder.Encode(*proposal))
return nil return nil
}, },
} }
@@ -377,7 +311,7 @@ var clientFindCmd = &cli.Command{
fmt.Printf("ERR %s@%s: %s\n", offer.Miner, offer.MinerPeerID, offer.Err) fmt.Printf("ERR %s@%s: %s\n", offer.Miner, offer.MinerPeerID, offer.Err)
continue continue
} }
fmt.Printf("RETRIEVAL %s@%s-%sfil-%s\n", offer.Miner, offer.MinerPeerID, types.FIL(offer.MinPrice), types.SizeStr(types.NewInt(offer.Size))) fmt.Printf("RETRIEVAL %s@%s-%sfil-%db\n", offer.Miner, offer.MinerPeerID, types.FIL(offer.MinPrice), offer.Size)
} }
return nil return nil
@@ -390,17 +324,13 @@ var clientRetrieveCmd = &cli.Command{
ArgsUsage: "[dataCid outputPath]", ArgsUsage: "[dataCid outputPath]",
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "from", Name: "address",
Usage: "address to send transactions from", Usage: "address to use for transactions",
}, },
&cli.BoolFlag{ &cli.BoolFlag{
Name: "car", Name: "car",
Usage: "export to a car file instead of a regular file", Usage: "export to a car file instead of a regular file",
}, },
&cli.StringFlag{
Name: "miner",
Usage: "miner address for retrieval, if not present it'll use local discovery",
},
}, },
Action: func(cctx *cli.Context) error { Action: func(cctx *cli.Context) error {
if cctx.NArg() != 2 { if cctx.NArg() != 2 {
@@ -408,7 +338,7 @@ var clientRetrieveCmd = &cli.Command{
return nil return nil
} }
fapi, closer, err := GetFullNodeAPI(cctx) api, closer, err := GetFullNodeAPI(cctx)
if err != nil { if err != nil {
return err return err
} }
@@ -416,10 +346,10 @@ var clientRetrieveCmd = &cli.Command{
ctx := ReqContext(cctx) ctx := ReqContext(cctx)
var payer address.Address var payer address.Address
if cctx.String("from") != "" { if cctx.String("address") != "" {
payer, err = address.NewFromString(cctx.String("from")) payer, err = address.NewFromString(cctx.String("address"))
} else { } else {
payer, err = fapi.WalletDefaultAddress(ctx) payer, err = api.WalletDefaultAddress(ctx)
} }
if err != nil { if err != nil {
return err return err
@@ -442,39 +372,23 @@ var clientRetrieveCmd = &cli.Command{
return nil return nil
}*/ // TODO: fix }*/ // TODO: fix
var offer api.QueryOffer offers, err := api.ClientFindData(ctx, file)
minerStrAddr := cctx.String("miner") if err != nil {
if minerStrAddr == "" { // Local discovery return err
offers, err := fapi.ClientFindData(ctx, file)
if err != nil {
return err
}
// TODO: parse offer strings from `client find`, make this smarter
if len(offers) < 1 {
fmt.Println("Failed to find file")
return nil
}
offer = offers[0]
} else { // Directed retrieval
minerAddr, err := address.NewFromString(minerStrAddr)
if err != nil {
return err
}
offer, err = fapi.ClientMinerQueryOffer(ctx, file, minerAddr)
if err != nil {
return err
}
} }
if offer.Err != "" {
return fmt.Errorf("The received offer errored: %s", offer.Err) // TODO: parse offer strings from `client find`, make this smarter
if len(offers) < 1 {
fmt.Println("Failed to find file")
return nil
} }
ref := &lapi.FileRef{ ref := &lapi.FileRef{
Path: cctx.Args().Get(1), Path: cctx.Args().Get(1),
IsCAR: cctx.Bool("car"), IsCAR: cctx.Bool("car"),
} }
if err := fapi.ClientRetrieve(ctx, offer.Order(payer), ref); err != nil { if err := api.ClientRetrieve(ctx, offers[0].Order(payer), ref); err != nil {
return xerrors.Errorf("Retrieval Failed: %w", err) return xerrors.Errorf("Retrieval Failed: %w", err)
} }
@@ -503,7 +417,7 @@ var clientQueryAskCmd = &cli.Command{
}, },
Action: func(cctx *cli.Context) error { Action: func(cctx *cli.Context) error {
if cctx.NArg() != 1 { if cctx.NArg() != 1 {
fmt.Println("Usage: query-ask [minerAddress]") fmt.Println("Usage: query-ask [address]")
return nil return nil
} }
@@ -532,11 +446,11 @@ var clientQueryAskCmd = &cli.Command{
return xerrors.Errorf("failed to get peerID for miner: %w", err) return xerrors.Errorf("failed to get peerID for miner: %w", err)
} }
if peer.ID(mi.PeerId) == peer.ID("SETME") { if mi.PeerId == peer.ID("SETME") {
return fmt.Errorf("the miner hasn't initialized yet") return fmt.Errorf("the miner hasn't initialized yet")
} }
pid = peer.ID(mi.PeerId) pid = mi.PeerId
} }
ask, err := api.ClientQueryAsk(ctx, pid, maddr) ask, err := api.ClientQueryAsk(ctx, pid, maddr)
@@ -546,7 +460,7 @@ var clientQueryAskCmd = &cli.Command{
fmt.Printf("Ask: %s\n", maddr) fmt.Printf("Ask: %s\n", maddr)
fmt.Printf("Price per GiB: %s\n", types.FIL(ask.Ask.Price)) fmt.Printf("Price per GiB: %s\n", types.FIL(ask.Ask.Price))
fmt.Printf("Max Piece size: %s\n", types.SizeStr(types.NewInt(uint64(ask.Ask.MaxPieceSize)))) fmt.Printf("Max Piece size: %d\n", ask.Ask.MaxPieceSize)
size := cctx.Int64("size") size := cctx.Int64("size")
if size == 0 { if size == 0 {
@@ -623,7 +537,7 @@ var clientListDeals = &cli.Command{
slashed = fmt.Sprintf("Y (epoch %d)", d.OnChainDealState.SlashEpoch) slashed = fmt.Sprintf("Y (epoch %d)", d.OnChainDealState.SlashEpoch)
} }
fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%d\t%s\n", d.LocalDeal.ProposalCid, d.LocalDeal.DealID, d.LocalDeal.Provider, storagemarket.DealStates[d.LocalDeal.State], onChain, slashed, d.LocalDeal.PieceCID, types.SizeStr(types.NewInt(d.LocalDeal.Size)), d.LocalDeal.PricePerEpoch, d.LocalDeal.Duration, d.LocalDeal.Message) fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\t%s\t%s\t%d\t%s\t%d\t%s\n", d.LocalDeal.ProposalCid, d.LocalDeal.DealID, d.LocalDeal.Provider, storagemarket.DealStates[d.LocalDeal.State], onChain, slashed, d.LocalDeal.PieceCID, d.LocalDeal.Size, d.LocalDeal.PricePerEpoch, d.LocalDeal.Duration, d.LocalDeal.Message)
} }
return w.Flush() return w.Flush()
}, },
+1 -1
View File
@@ -13,8 +13,8 @@ import (
"github.com/mitchellh/go-homedir" "github.com/mitchellh/go-homedir"
"github.com/multiformats/go-multiaddr" "github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr-net" manet "github.com/multiformats/go-multiaddr-net"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"gopkg.in/urfave/cli.v2"
"github.com/filecoin-project/go-jsonrpc" "github.com/filecoin-project/go-jsonrpc"
+1 -1
View File
@@ -3,8 +3,8 @@ package cli
import ( import (
"fmt" "fmt"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"gopkg.in/urfave/cli.v2"
) )
var logCmd = &cli.Command{ var logCmd = &cli.Command{
+1 -1
View File
@@ -5,8 +5,8 @@ import (
"fmt" "fmt"
"sort" "sort"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"gopkg.in/urfave/cli.v2"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
+20 -262
View File
@@ -6,7 +6,6 @@ import (
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"github.com/filecoin-project/specs-actors/actors/abi"
"os" "os"
"sort" "sort"
"strconv" "strconv"
@@ -18,27 +17,29 @@ import (
cid "github.com/ipfs/go-cid" cid "github.com/ipfs/go-cid"
"github.com/ipfs/go-hamt-ipld" "github.com/ipfs/go-hamt-ipld"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
"github.com/urfave/cli/v2"
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"gopkg.in/urfave/cli.v2"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/apibstore" "github.com/filecoin-project/lotus/api/apibstore"
"github.com/filecoin-project/lotus/build"
types "github.com/filecoin-project/lotus/chain/types" types "github.com/filecoin-project/lotus/chain/types"
) )
var multisigCmd = &cli.Command{ var multisigCmd = &cli.Command{
Name: "msig", Name: "msig",
Usage: "Interact with a multisig wallet", Usage: "Interact with a multisig wallet",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "source",
Usage: "specify the account to send propose from",
},
},
Subcommands: []*cli.Command{ Subcommands: []*cli.Command{
msigCreateCmd, msigCreateCmd,
msigInspectCmd, msigInspectCmd,
msigProposeCmd, msigProposeCmd,
msigApproveCmd, msigApproveCmd,
msigSwapProposeCmd,
msigSwapApproveCmd,
msigSwapCancelCmd,
}, },
} }
@@ -48,8 +49,7 @@ var msigCreateCmd = &cli.Command{
ArgsUsage: "[address1 address2 ...]", ArgsUsage: "[address1 address2 ...]",
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.Int64Flag{ &cli.Int64Flag{
Name: "required", Name: "required",
Usage: "number of required approvals (uses number of signers provided if omitted)",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "value", Name: "value",
@@ -57,12 +57,7 @@ var msigCreateCmd = &cli.Command{
Value: "0", Value: "0",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "duration", Name: "sender",
Usage: "length of the period over which funds unlock",
Value: "0",
},
&cli.StringFlag{
Name: "from",
Usage: "account to send the create message from", Usage: "account to send the create message from",
}, },
}, },
@@ -74,10 +69,6 @@ var msigCreateCmd = &cli.Command{
defer closer() defer closer()
ctx := ReqContext(cctx) ctx := ReqContext(cctx)
if cctx.Args().Len() < 1 {
return fmt.Errorf("multisigs must have at least one signer")
}
var addrs []address.Address var addrs []address.Address
for _, a := range cctx.Args().Slice() { for _, a := range cctx.Args().Slice() {
addr, err := address.NewFromString(a) addr, err := address.NewFromString(a)
@@ -89,7 +80,7 @@ var msigCreateCmd = &cli.Command{
// get the address we're going to use to create the multisig (can be one of the above, as long as they have funds) // get the address we're going to use to create the multisig (can be one of the above, as long as they have funds)
var sendAddr address.Address var sendAddr address.Address
if send := cctx.String("from"); send == "" { if send := cctx.String("sender"); send == "" {
defaddr, err := api.WalletDefaultAddress(ctx) defaddr, err := api.WalletDefaultAddress(ctx)
if err != nil { if err != nil {
return err return err
@@ -118,17 +109,15 @@ var msigCreateCmd = &cli.Command{
required = int64(len(addrs)) required = int64(len(addrs))
} }
d := abi.ChainEpoch(cctx.Uint64("duration"))
gp := types.NewInt(1) gp := types.NewInt(1)
msgCid, err := api.MsigCreate(ctx, required, addrs, d, intVal, sendAddr, gp) msgCid, err := api.MsigCreate(ctx, required, addrs, intVal, sendAddr, gp)
if err != nil { if err != nil {
return err return err
} }
// wait for it to get mined into a block // wait for it to get mined into a block
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence) wait, err := api.StateWaitMsg(ctx, msgCid)
if err != nil { if err != nil {
return err return err
} }
@@ -274,7 +263,7 @@ var msigProposeCmd = &cli.Command{
ArgsUsage: "[multisigAddress destinationAddress value <methodId methodParams> (optional)]", ArgsUsage: "[multisigAddress destinationAddress value <methodId methodParams> (optional)]",
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "from", Name: "source",
Usage: "account to send the propose message from", Usage: "account to send the propose message from",
}, },
}, },
@@ -326,8 +315,8 @@ var msigProposeCmd = &cli.Command{
} }
var from address.Address var from address.Address
if cctx.IsSet("from") { if cctx.IsSet("source") {
f, err := address.NewFromString(cctx.String("from")) f, err := address.NewFromString(cctx.String("source"))
if err != nil { if err != nil {
return err return err
} }
@@ -347,7 +336,7 @@ var msigProposeCmd = &cli.Command{
fmt.Println("send proposal in message: ", msgCid) fmt.Println("send proposal in message: ", msgCid)
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence) wait, err := api.StateWaitMsg(ctx, msgCid)
if err != nil { if err != nil {
return err return err
} }
@@ -373,7 +362,7 @@ var msigApproveCmd = &cli.Command{
ArgsUsage: "[multisigAddress messageId proposerAddress destination value <methodId methodParams> (optional)]", ArgsUsage: "[multisigAddress messageId proposerAddress destination value <methodId methodParams> (optional)]",
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "from", Name: "source",
Usage: "account to send the approve message from", Usage: "account to send the approve message from",
}, },
}, },
@@ -442,8 +431,8 @@ var msigApproveCmd = &cli.Command{
} }
var from address.Address var from address.Address
if cctx.IsSet("from") { if cctx.IsSet("source") {
f, err := address.NewFromString(cctx.String("from")) f, err := address.NewFromString(cctx.String("source"))
if err != nil { if err != nil {
return err return err
} }
@@ -463,7 +452,7 @@ var msigApproveCmd = &cli.Command{
fmt.Println("sent approval in message: ", msgCid) fmt.Println("sent approval in message: ", msgCid)
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence) wait, err := api.StateWaitMsg(ctx, msgCid)
if err != nil { if err != nil {
return err return err
} }
@@ -475,234 +464,3 @@ var msigApproveCmd = &cli.Command{
return nil return nil
}, },
} }
var msigSwapProposeCmd = &cli.Command{
Name: "swap-propose",
Usage: "Propose to swap signers",
ArgsUsage: "[multisigAddress oldAddress newAddress]",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "from",
Usage: "account to send the approve message from",
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
if cctx.Args().Len() != 3 {
return fmt.Errorf("must pass multisig address, old signer address, new signer address")
}
msig, err := address.NewFromString(cctx.Args().Get(0))
if err != nil {
return err
}
oldAdd, err := address.NewFromString(cctx.Args().Get(1))
if err != nil {
return err
}
newAdd, err := address.NewFromString(cctx.Args().Get(2))
if err != nil {
return err
}
var from address.Address
if cctx.IsSet("from") {
f, err := address.NewFromString(cctx.String("from"))
if err != nil {
return err
}
from = f
} else {
defaddr, err := api.WalletDefaultAddress(ctx)
if err != nil {
return err
}
from = defaddr
}
msgCid, err := api.MsigSwapPropose(ctx, msig, from, oldAdd, newAdd)
if err != nil {
return err
}
fmt.Println("sent swap proposal in message: ", msgCid)
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
if err != nil {
return err
}
if wait.Receipt.ExitCode != 0 {
return fmt.Errorf("swap proposal returned exit %d", wait.Receipt.ExitCode)
}
return nil
},
}
var msigSwapApproveCmd = &cli.Command{
Name: "swap-approve",
Usage: "Approve a message to swap signers",
ArgsUsage: "[multisigAddress proposerAddress txId oldAddress newAddress]",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "from",
Usage: "account to send the approve message from",
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
if cctx.Args().Len() != 5 {
return fmt.Errorf("must pass multisig address, proposer address, transaction id, old signer address, new signer address")
}
msig, err := address.NewFromString(cctx.Args().Get(0))
if err != nil {
return err
}
prop, err := address.NewFromString(cctx.Args().Get(1))
if err != nil {
return err
}
txid, err := strconv.ParseUint(cctx.Args().Get(2), 10, 64)
if err != nil {
return err
}
oldAdd, err := address.NewFromString(cctx.Args().Get(3))
if err != nil {
return err
}
newAdd, err := address.NewFromString(cctx.Args().Get(4))
if err != nil {
return err
}
var from address.Address
if cctx.IsSet("from") {
f, err := address.NewFromString(cctx.String("from"))
if err != nil {
return err
}
from = f
} else {
defaddr, err := api.WalletDefaultAddress(ctx)
if err != nil {
return err
}
from = defaddr
}
msgCid, err := api.MsigSwapApprove(ctx, msig, from, txid, prop, oldAdd, newAdd)
if err != nil {
return err
}
fmt.Println("sent swap approval in message: ", msgCid)
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
if err != nil {
return err
}
if wait.Receipt.ExitCode != 0 {
return fmt.Errorf("swap approval returned exit %d", wait.Receipt.ExitCode)
}
return nil
},
}
var msigSwapCancelCmd = &cli.Command{
Name: "swap-cancel",
Usage: "Cancel a message to swap signers",
ArgsUsage: "[multisigAddress txId oldAddress newAddress]",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "from",
Usage: "account to send the approve message from",
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
if cctx.Args().Len() != 4 {
return fmt.Errorf("must pass multisig address, transaction id, old signer address, new signer address")
}
msig, err := address.NewFromString(cctx.Args().Get(0))
if err != nil {
return err
}
txid, err := strconv.ParseUint(cctx.Args().Get(1), 10, 64)
if err != nil {
return err
}
oldAdd, err := address.NewFromString(cctx.Args().Get(2))
if err != nil {
return err
}
newAdd, err := address.NewFromString(cctx.Args().Get(3))
if err != nil {
return err
}
var from address.Address
if cctx.IsSet("from") {
f, err := address.NewFromString(cctx.String("from"))
if err != nil {
return err
}
from = f
} else {
defaddr, err := api.WalletDefaultAddress(ctx)
if err != nil {
return err
}
from = defaddr
}
msgCid, err := api.MsigSwapCancel(ctx, msig, from, txid, oldAdd, newAdd)
if err != nil {
return err
}
fmt.Println("sent swap approval in message: ", msgCid)
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
if err != nil {
return err
}
if wait.Receipt.ExitCode != 0 {
return fmt.Errorf("swap approval returned exit %d", wait.Receipt.ExitCode)
}
return nil
},
}
+2 -26
View File
@@ -7,7 +7,7 @@ import (
"github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/peer"
"github.com/urfave/cli/v2" "gopkg.in/urfave/cli.v2"
"github.com/filecoin-project/lotus/lib/addrutil" "github.com/filecoin-project/lotus/lib/addrutil"
) )
@@ -21,7 +21,6 @@ var netCmd = &cli.Command{
netListen, netListen,
netId, netId,
netFindPeer, netFindPeer,
netScores,
}, },
} }
@@ -45,30 +44,7 @@ var netPeers = &cli.Command{
}) })
for _, peer := range peers { for _, peer := range peers {
fmt.Printf("%s, %s\n", peer.ID, peer.Addrs) fmt.Println(peer)
}
return nil
},
}
var netScores = &cli.Command{
Name: "scores",
Usage: "Print peers' pubsub scores",
Action: func(cctx *cli.Context) error {
api, closer, err := GetAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
scores, err := api.NetPubsubScores(ctx)
if err != nil {
return err
}
for _, peer := range scores {
fmt.Printf("%s, %f\n", peer.ID, peer.Score)
} }
return nil return nil
+12 -11
View File
@@ -3,27 +3,28 @@ package cli
import ( import (
"github.com/docker/go-units" "github.com/docker/go-units"
paramfetch "github.com/filecoin-project/go-paramfetch" paramfetch "github.com/filecoin-project/go-paramfetch"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"gopkg.in/urfave/cli.v2"
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
) )
var fetchParamCmd = &cli.Command{ var fetchParamCmd = &cli.Command{
Name: "fetch-params", Name: "fetch-params",
Usage: "Fetch proving parameters", Usage: "Fetch proving parameters",
ArgsUsage: "[sectorSize]", Flags: []cli.Flag{
&cli.StringFlag{
Name: "proving-params",
Usage: "download params used creating proofs for given size, i.e. 32GiB",
},
},
Action: func(cctx *cli.Context) error { Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() { sectorSizeInt, err := units.RAMInBytes(cctx.String("proving-params"))
return xerrors.Errorf("must pass sector size to fetch params for (specify as \"32GiB\", for instance)")
}
sectorSizeInt, err := units.RAMInBytes(cctx.Args().First())
if err != nil { if err != nil {
return xerrors.Errorf("error parsing sector size (specify as \"32GiB\", for instance): %w", err) return err
} }
sectorSize := uint64(sectorSizeInt) sectorSize := uint64(sectorSizeInt)
err = paramfetch.GetParams(build.ParametersJSON(), sectorSize)
err = paramfetch.GetParams(ReqContext(cctx), build.ParametersJSON(), sectorSize)
if err != nil { if err != nil {
return xerrors.Errorf("fetching proof parameters: %w", err) return xerrors.Errorf("fetching proof parameters: %w", err)
} }
+6 -7
View File
@@ -4,11 +4,10 @@ import (
"bytes" "bytes"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/filecoin-project/specs-actors/actors/builtin/paych"
"github.com/urfave/cli/v2" "gopkg.in/urfave/cli.v2"
types "github.com/filecoin-project/lotus/chain/types" types "github.com/filecoin-project/lotus/chain/types"
) )
@@ -29,7 +28,7 @@ var paychGetCmd = &cli.Command{
ArgsUsage: "[fromAddress toAddress amount]", ArgsUsage: "[fromAddress toAddress amount]",
Action: func(cctx *cli.Context) error { Action: func(cctx *cli.Context) error {
if cctx.Args().Len() != 3 { if cctx.Args().Len() != 3 {
return fmt.Errorf("must pass three arguments: <from> <to> <available funds in FIL>") return fmt.Errorf("must pass three arguments: <from> <to> <available funds>")
} }
from, err := address.NewFromString(cctx.Args().Get(0)) from, err := address.NewFromString(cctx.Args().Get(0))
@@ -42,9 +41,9 @@ var paychGetCmd = &cli.Command{
return fmt.Errorf("failed to parse to address: %s", err) return fmt.Errorf("failed to parse to address: %s", err)
} }
amt, err := types.ParseFIL(cctx.Args().Get(2)) amt, err := types.BigFromString(cctx.Args().Get(2))
if err != nil { if err != nil {
return fmt.Errorf("parsing amount as whole FIL failed: %s", err) return fmt.Errorf("parsing amount failed: %s", err)
} }
api, closer, err := GetFullNodeAPI(cctx) api, closer, err := GetFullNodeAPI(cctx)
@@ -55,7 +54,7 @@ var paychGetCmd = &cli.Command{
ctx := ReqContext(cctx) ctx := ReqContext(cctx)
info, err := api.PaychGet(ctx, from, to, types.BigInt(amt)) info, err := api.PaychGet(ctx, from, to, amt)
if err != nil { if err != nil {
return err return err
} }
@@ -362,7 +361,7 @@ var paychVoucherSubmitCmd = &cli.Command{
return err return err
} }
mwait, err := api.StateWaitMsg(ctx, mcid, build.MessageConfidence) mwait, err := api.StateWaitMsg(ctx, mcid)
if err != nil { if err != nil {
return err return err
} }
+3 -3
View File
@@ -5,7 +5,7 @@ import (
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/urfave/cli/v2" "gopkg.in/urfave/cli.v2"
) )
var sendCmd = &cli.Command{ var sendCmd = &cli.Command{
@@ -14,7 +14,7 @@ var sendCmd = &cli.Command{
ArgsUsage: "[targetAddress] [amount]", ArgsUsage: "[targetAddress] [amount]",
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "from", Name: "source",
Usage: "optionally specify the account to send funds from", Usage: "optionally specify the account to send funds from",
}, },
&cli.StringFlag{ &cli.StringFlag{
@@ -52,7 +52,7 @@ var sendCmd = &cli.Command{
} }
var fromAddr address.Address var fromAddr address.Address
if from := cctx.String("from"); from == "" { if from := cctx.String("source"); from == "" {
defaddr, err := api.WalletDefaultAddress(ctx) defaddr, err := api.WalletDefaultAddress(ctx)
if err != nil { if err != nil {
return err return err
+190 -260
View File
@@ -5,38 +5,87 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"html/template"
"os"
"reflect" "reflect"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/docker/go-units"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/peer"
"github.com/multiformats/go-multihash" "github.com/multiformats/go-multihash"
"github.com/urfave/cli/v2"
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"gopkg.in/urfave/cli.v2"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin" "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/market"
miner2 "github.com/filecoin-project/specs-actors/actors/builtin/miner" miner2 "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/multisig"
"github.com/filecoin-project/specs-actors/actors/builtin/paych" "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/power"
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "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/util/adt"
"github.com/filecoin-project/lotus/api" "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/chain/types"
"github.com/filecoin-project/lotus/miner" "github.com/filecoin-project/lotus/miner"
) )
type methodMeta struct {
name string
params reflect.Type
ret reflect.Type
}
var methods = 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, miner2.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()
methods[c] = append(methods[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])
methods[c] = append(methods[c], methodMeta{
name: rt.Field(i).Name,
params: export.In(1),
ret: export.Out(0),
})
}
}
}
var stateCmd = &cli.Command{ var stateCmd = &cli.Command{
Name: "state", Name: "state",
Usage: "Interact with and query filecoin chain state", Usage: "Interact with and query filecoin chain state",
@@ -95,15 +144,27 @@ var stateMinerInfo = &cli.Command{
return err return err
} }
mi, err := api.StateMinerInfo(ctx, addr, ts.Key()) act, err := api.StateGetActor(ctx, addr, ts.Key())
if err != nil { if err != nil {
return err return err
} }
aso, err := api.ChainReadObj(ctx, act.Head)
if err != nil {
return err
}
var mst miner2.State
if err := mst.UnmarshalCBOR(bytes.NewReader(aso)); err != nil {
return err
}
mi := mst.Info
fmt.Printf("Owner:\t%s\n", mi.Owner) fmt.Printf("Owner:\t%s\n", mi.Owner)
fmt.Printf("Worker:\t%s\n", mi.Worker) fmt.Printf("Worker:\t%s\n", mi.Worker)
fmt.Printf("PeerID:\t%s\n", mi.PeerId) fmt.Printf("PeerID:\t%s\n", mi.PeerId)
fmt.Printf("SectorSize:\t%s (%d)\n", types.SizeStr(types.NewInt(uint64(mi.SectorSize))), mi.SectorSize) fmt.Printf("SectorSize:\t%s (%d)\n", units.BytesSize(float64(mi.SectorSize)), mi.SectorSize)
return nil return nil
}, },
@@ -299,7 +360,7 @@ var stateReplaySetCmd = &cli.Command{
return fmt.Errorf("message cid was invalid: %s", err) return fmt.Errorf("message cid was invalid: %s", err)
} }
fapi, closer, err := GetFullNodeAPI(cctx) api, closer, err := GetFullNodeAPI(cctx)
if err != nil { if err != nil {
return err return err
} }
@@ -321,7 +382,7 @@ var stateReplaySetCmd = &cli.Command{
if len(tscids) > 0 { if len(tscids) > 0 {
var headers []*types.BlockHeader var headers []*types.BlockHeader
for _, c := range tscids { for _, c := range tscids {
h, err := fapi.ChainGetBlock(ctx, c) h, err := api.ChainGetBlock(ctx, c)
if err != nil { if err != nil {
return err return err
} }
@@ -331,17 +392,12 @@ var stateReplaySetCmd = &cli.Command{
ts, err = types.NewTipSet(headers) ts, err = types.NewTipSet(headers)
} else { } else {
var r *api.MsgLookup r, err := api.StateWaitMsg(ctx, mcid)
r, err = fapi.StateWaitMsg(ctx, mcid, build.MessageConfidence)
if err != nil { if err != nil {
return xerrors.Errorf("finding message in chain: %w", err) return xerrors.Errorf("finding message in chain: %w", err)
} }
childTs, err := fapi.ChainGetTipSet(ctx, r.TipSet) ts, err = api.ChainGetTipSet(ctx, r.TipSet.Parents())
if err != nil {
return xerrors.Errorf("loading tipset: %w", err)
}
ts, err = fapi.ChainGetTipSet(ctx, childTs.Parents())
} }
if err != nil { if err != nil {
return err return err
@@ -349,7 +405,7 @@ var stateReplaySetCmd = &cli.Command{
} }
res, err := fapi.StateReplay(ctx, ts.Key(), mcid) res, err := api.StateReplay(ctx, ts.Key(), mcid)
if err != nil { if err != nil {
return xerrors.Errorf("replay call failed: %w", err) return xerrors.Errorf("replay call failed: %w", err)
} }
@@ -662,7 +718,7 @@ var stateSectorSizeCmd = &cli.Command{
return err return err
} }
fmt.Printf("%s (%d)\n", types.SizeStr(types.NewInt(uint64(mi.SectorSize))), mi.SectorSize) fmt.Printf("%d\n", mi.SectorSize)
return nil return nil
}, },
} }
@@ -694,7 +750,12 @@ var stateReadStateCmd = &cli.Command{
return err return err
} }
as, err := api.StateReadState(ctx, addr, ts.Key()) act, err := api.StateGetActor(ctx, addr, ts.Key())
if err != nil {
return err
}
as, err := api.StateReadState(ctx, act, ts.Key())
if err != nil { if err != nil {
return err return err
} }
@@ -794,8 +855,8 @@ var stateComputeStateCmd = &cli.Command{
Usage: "Perform state computations", Usage: "Perform state computations",
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.Uint64Flag{ &cli.Uint64Flag{
Name: "vm-height", Name: "height",
Usage: "set the height that the vm will see", Usage: "set the height to compute state at",
}, },
&cli.BoolFlag{ &cli.BoolFlag{
Name: "apply-mpool-messages", Name: "apply-mpool-messages",
@@ -824,7 +885,7 @@ var stateComputeStateCmd = &cli.Command{
return err return err
} }
h := abi.ChainEpoch(cctx.Uint64("vm-height")) h := abi.ChainEpoch(cctx.Uint64("height"))
if h == 0 { if h == 0 {
if ts == nil { if ts == nil {
head, err := api.ChainHead(ctx) head, err := api.ChainHead(ctx)
@@ -874,29 +935,37 @@ var stateComputeStateCmd = &cli.Command{
return c.Code, nil return c.Code, nil
} }
return computeStateHTMLTempl(ts, stout, getCode) return computeStateHtml(ts, stout, getCode)
} }
fmt.Println("computed state cid: ", stout.Root) fmt.Println("computed state cid: ", stout.Root)
if cctx.Bool("show-trace") { if cctx.Bool("show-trace") {
for _, ir := range stout.Trace { for _, ir := range stout.Trace {
fmt.Printf("%s\t%s\t%s\t%d\t%x\t%d\t%x\n", ir.Msg.From, ir.Msg.To, ir.Msg.Value, ir.Msg.Method, ir.Msg.Params, ir.MsgRct.ExitCode, ir.MsgRct.Return) fmt.Printf("%s\t%s\t%s\t%d\t%x\t%d\t%x\n", ir.Msg.From, ir.Msg.To, ir.Msg.Value, ir.Msg.Method, ir.Msg.Params, ir.MsgRct.ExitCode, ir.MsgRct.Return)
printInternalExecutions("\t", ir.ExecutionTrace.Subcalls) printInternalExecutions("\t", ir.InternalExecutions)
} }
} }
return nil return nil
}, },
} }
func printInternalExecutions(prefix string, trace []types.ExecutionTrace) { func printInternalExecutions(prefix string, trace []*types.ExecutionResult) {
for _, im := range trace { for _, im := range trace {
fmt.Printf("%s%s\t%s\t%s\t%d\t%x\t%d\t%x\n", prefix, im.Msg.From, im.Msg.To, im.Msg.Value, im.Msg.Method, im.Msg.Params, im.MsgRct.ExitCode, im.MsgRct.Return) fmt.Printf("%s%s\t%s\t%s\t%d\t%x\t%d\t%x\n", prefix, im.Msg.From, im.Msg.To, im.Msg.Value, im.Msg.Method, im.Msg.Params, im.MsgRct.ExitCode, im.MsgRct.Return)
printInternalExecutions(prefix+"\t", im.Subcalls) printInternalExecutions(prefix+"\t", im.Subcalls)
} }
} }
var compStateTemplate = ` func codeStr(c cid.Cid) string {
<html> cmh, err := multihash.Decode(c.Hash())
if err != nil {
panic(err)
}
return string(cmh.Digest)
}
func computeStateHtml(ts *types.TipSet, o *api.ComputeStateOutput, getCode func(addr address.Address) (cid.Cid, error)) error {
fmt.Printf(`<html>
<head> <head>
<style> <style>
html, body { font-family: monospace; } html, body { font-family: monospace; }
@@ -918,263 +987,124 @@ var compStateTemplate = `
} }
.slow-true-false { color: #660; } .slow-true-false { color: #660; }
.slow-true-true { color: #f80; } .slow-true-true { color: #f80; }
.deemp { color: #444; }
table {
font-size: 12px;
border-collapse: collapse;
}
tr {
border-top: 1px solid black;
border-bottom: 1px solid black;
}
tr.sum { border-top: 2px solid black; }
tr:first-child { border-top: none; }
tr:last-child { border-bottom: none; }
.ellipsis-content,
.ellipsis-toggle input {
display: none;
}
.ellipsis-toggle {
cursor: pointer;
}
/**
Checked State
**/
.ellipsis-toggle input:checked + .ellipsis {
display: none;
}
.ellipsis-toggle input:checked ~ .ellipsis-content {
display: inline;
background-color: #ddd;
}
hr {
border: none;
height: 1px;
background-color: black;
margin: 0;
}
</style> </style>
</head> </head>
<body> <body>
<div>Tipset: <b>{{.TipSet.Key}}</b></div> <div>Tipset: <b>%s</b></div>
<div>Epoch: {{.TipSet.Height}}</div> <div>Height: %d</div>
<div>State CID: <b>{{.Comp.Root}}</b></div> <div>State CID: <b>%s</b></div>
<div>Calls</div> <div>Calls</div>`, ts.Key(), ts.Height(), o.Root)
{{range .Comp.Trace}}
{{template "message" (Call .ExecutionTrace false .Msg.Cid.String)}}
{{end}}
</body>
</html>
`
var compStateMsg = ` for _, ir := range o.Trace {
<div class="exec" id="{{.Hash}}"> toCode, err := getCode(ir.Msg.To)
{{$code := GetCode .Msg.To}} if err != nil {
<div> return xerrors.Errorf("getting code for %s: %w", toCode, err)
<a href="#{{.Hash}}"> }
{{if not .Subcall}}
<h2 class="call">
{{else}}
<h4 class="call">
{{end}}
{{- CodeStr $code}}:{{GetMethod ($code) (.Msg.Method)}}
{{if not .Subcall}}
</h2>
{{else}}
</h4>
{{end}}
</a>
</div>
<div><b>{{.Msg.From}}</b> -&gt; <b>{{.Msg.To}}</b> ({{ToFil .Msg.Value}} FIL), M{{.Msg.Method}}</div> params, err := jsonParams(toCode, ir.Msg.Method, ir.Msg.Params)
{{if not .Subcall}}<div><small>Msg CID: {{.Msg.Cid}}</small></div>{{end}} if err != nil {
{{if gt (len .Msg.Params) 0}} return xerrors.Errorf("decoding params: %w", err)
<div><pre class="params">{{JsonParams ($code) (.Msg.Method) (.Msg.Params) | html}}</pre></div> }
{{end}}
<div><span class="slow-{{IsSlow .Duration}}-{{IsVerySlow .Duration}}">Took {{.Duration}}</span>, <span class="exit{{IntExit .MsgRct.ExitCode}}">Exit: <b>{{.MsgRct.ExitCode}}</b></span>{{if gt (len .MsgRct.Return) 0}}, Return{{end}}</div>
{{if gt (len .MsgRct.Return) 0}}
<div><pre class="ret">{{JsonReturn ($code) (.Msg.Method) (.MsgRct.Return) | html}}</pre></div>
{{end}}
{{if ne .MsgRct.ExitCode 0}} if len(ir.Msg.Params) != 0 {
<div class="error">Error: <pre>{{.Error}}</pre></div> params = `<div><pre class="params">` + params + `</pre></div>`
{{end}} } else {
params = ""
}
<details> ret, err := jsonReturn(toCode, ir.Msg.Method, ir.MsgRct.Return)
<summary>Gas Trace</summary> if err != nil {
<table> return xerrors.Errorf("decoding return value: %w", err)
<tr><th>Name</th><th>Total/Compute/Storage</th><th>Time Taken</th><th>Location</th></tr> }
{{define "virt" -}}
{{- if . -}}
<span class="deemp">+({{.}})</span>
{{- end -}}
{{- end}}
{{define "gasC" -}} if len(ir.MsgRct.Return) == 0 {
<td>{{.TotalGas}}{{template "virt" .TotalVirtualGas }}/{{.ComputeGas}}{{template "virt" .VirtualComputeGas}}/{{.StorageGas}}{{template "virt" .VirtualStorageGas}}</td> ret = "</div>"
{{- end}} } else {
ret = `, Return</div><div><pre class="ret">` + ret + `</pre></div>`
}
{{range .GasCharges}} slow := ir.Duration > 10*time.Millisecond
<tr><td>{{.Name}}{{if .Extra}}:{{.Extra}}{{end}}</td> veryslow := ir.Duration > 50*time.Millisecond
{{template "gasC" .}}
<td>{{.TimeTaken}}</td>
<td>
{{ $fImp := FirstImportant .Location }}
{{ if $fImp }}
<details>
<summary>{{ $fImp }}</summary><hr />
{{ $elipOn := false }}
{{ range $index, $ele := .Location -}}
{{- if $index }}<br />{{end -}}
{{- if .Show -}}
{{ if $elipOn }}
{{ $elipOn = false }}
</span></label>
{{end}}
{{- if .Important }}<b>{{end -}} cid := ir.Msg.Cid()
{{- . -}}
{{if .Important }}</b>{{end}}
{{else}}
{{ if not $elipOn }}
{{ $elipOn = true }}
<label class="ellipsis-toggle"><input type="checkbox" /><span class="ellipsis">[]<br /></span>
<span class="ellipsis-content">
{{end}}
{{- "" -}}
{{- . -}}
{{end}}
{{end}}
{{ if $elipOn }}
{{ $elipOn = false }}
</span></label>
{{end}}
</details>
{{end}}
</td></tr>
{{end}}
{{with SumGas .GasCharges}}
<tr class="sum"><td><b>Sum</b></td>
{{template "gasC" .}}
<td>{{.TimeTaken}}</td>
<td></td></tr>
{{end}}
</table>
</details>
fmt.Printf(`<div class="exec" id="%s">
<div><a href="#%s"><h2 class="call">%s:%s</h2></a></div>
<div><b>%s</b> -&gt; <b>%s</b> (%s FIL), M%d</div>
<div><small>Msg CID: %s</small></div>
%s
<div><span class="slow-%t-%t">Took %s</span>, <span class="exit%d">Exit: <b>%d</b></span>%s
`, cid, cid, codeStr(toCode), methods[toCode][ir.Msg.Method].name, ir.Msg.From, ir.Msg.To, types.FIL(ir.Msg.Value), ir.Msg.Method, cid, params, slow, veryslow, ir.Duration, ir.MsgRct.ExitCode, ir.MsgRct.ExitCode, ret)
if ir.MsgRct.ExitCode != 0 {
fmt.Printf(`<div class="error">Error: <pre>%s</pre></div>`, ir.Error)
}
{{if gt (len .Subcalls) 0}} if len(ir.InternalExecutions) > 0 {
<div>Subcalls:</div> fmt.Println("<div>Internal executions:</div>")
{{$hash := .Hash}} if err := printInternalExecutionsHtml(ir.InternalExecutions, getCode); err != nil {
{{range .Subcalls}} return err
{{template "message" (Call . true (printf "%s-%s" $hash .Msg.Cid.String))}}
{{end}}
{{end}}
</div>`
type compStateHTMLIn struct {
TipSet *types.TipSet
Comp *api.ComputeStateOutput
}
func computeStateHTMLTempl(ts *types.TipSet, o *api.ComputeStateOutput, getCode func(addr address.Address) (cid.Cid, error)) error {
t, err := template.New("compute_state").Funcs(map[string]interface{}{
"GetCode": getCode,
"GetMethod": getMethod,
"ToFil": toFil,
"JsonParams": jsonParams,
"JsonReturn": jsonReturn,
"IsSlow": isSlow,
"IsVerySlow": isVerySlow,
"IntExit": func(i exitcode.ExitCode) int64 { return int64(i) },
"SumGas": sumGas,
"CodeStr": codeStr,
"Call": call,
"FirstImportant": func(locs []types.Loc) *types.Loc {
if len(locs) != 0 {
for _, l := range locs {
if l.Important() {
return &l
}
}
return &locs[0]
} }
return nil }
}, fmt.Println("</div>")
}).Parse(compStateTemplate)
if err != nil {
return err
}
t, err = t.New("message").Parse(compStateMsg)
if err != nil {
return err
} }
return t.ExecuteTemplate(os.Stdout, "compute_state", &compStateHTMLIn{ fmt.Printf(`</body>
TipSet: ts, </html>`)
Comp: o, return nil
})
} }
type callMeta struct { func printInternalExecutionsHtml(trace []*types.ExecutionResult, getCode func(addr address.Address) (cid.Cid, error)) error {
types.ExecutionTrace for _, im := range trace {
Subcall bool toCode, err := getCode(im.Msg.To)
Hash string if err != nil {
} return xerrors.Errorf("getting code for %s: %w", toCode, err)
}
func call(e types.ExecutionTrace, subcall bool, hash string) callMeta { params, err := jsonParams(toCode, im.Msg.Method, im.Msg.Params)
return callMeta{ if err != nil {
ExecutionTrace: e, return xerrors.Errorf("decoding params: %w", err)
Subcall: subcall, }
Hash: hash,
}
}
func codeStr(c cid.Cid) string { if len(im.Msg.Params) != 0 {
cmh, err := multihash.Decode(c.Hash()) params = `<div><pre class="params">` + params + `</pre></div>`
if err != nil { } else {
panic(err) params = ""
} }
return string(cmh.Digest)
}
func getMethod(code cid.Cid, method abi.MethodNum) string { ret, err := jsonReturn(toCode, im.Msg.Method, im.MsgRct.Return)
return stmgr.MethodsMap[code][method].Name if err != nil {
} return xerrors.Errorf("decoding return value: %w", err)
}
func toFil(f types.BigInt) types.FIL { if len(im.MsgRct.Return) == 0 {
return types.FIL(f) ret = "</div>"
} } else {
ret = `, Return</div><div><pre class="ret">` + ret + `</pre></div>`
}
func isSlow(t time.Duration) bool { fmt.Printf(`<div class="exec">
return t > 10*time.Millisecond <div><h4 class="call">%s:%s</h4></div>
} <div><b>%s</b> -&gt; <b>%s</b> (%s FIL), M%d</div>
%s
func isVerySlow(t time.Duration) bool { <div><span class="exit%d">Exit: <b>%d</b></span>%s
return t > 50*time.Millisecond `, codeStr(toCode), methods[toCode][im.Msg.Method].name, im.Msg.From, im.Msg.To, types.FIL(im.Msg.Value), im.Msg.Method, params, im.MsgRct.ExitCode, im.MsgRct.ExitCode, ret)
} if im.MsgRct.ExitCode != 0 {
fmt.Printf(`<div class="error">Error: <pre>%s</pre></div>`, im.Error)
func sumGas(changes []*types.GasTrace) types.GasTrace { }
var out types.GasTrace if len(im.Subcalls) > 0 {
for _, gc := range changes { fmt.Println("<div>Subcalls:</div>")
out.TotalGas += gc.TotalGas if err := printInternalExecutionsHtml(im.Subcalls, getCode); err != nil {
out.ComputeGas += gc.ComputeGas return err
out.StorageGas += gc.StorageGas }
}
out.TotalVirtualGas += gc.TotalVirtualGas fmt.Println("</div>")
out.VirtualComputeGas += gc.VirtualComputeGas
out.VirtualStorageGas += gc.VirtualStorageGas
} }
return out return nil
} }
func jsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, error) { func jsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, error) {
re := reflect.New(stmgr.MethodsMap[code][method].Params.Elem()) re := reflect.New(methods[code][method].params.Elem())
p := re.Interface().(cbg.CBORUnmarshaler) p := re.Interface().(cbg.CBORUnmarshaler)
if err := p.UnmarshalCBOR(bytes.NewReader(params)); err != nil { if err := p.UnmarshalCBOR(bytes.NewReader(params)); err != nil {
return "", err return "", err
@@ -1185,7 +1115,7 @@ func jsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, erro
} }
func jsonReturn(code cid.Cid, method abi.MethodNum, ret []byte) (string, error) { func jsonReturn(code cid.Cid, method abi.MethodNum, ret []byte) (string, error) {
re := reflect.New(stmgr.MethodsMap[code][method].Ret.Elem()) re := reflect.New(methods[code][method].ret.Elem())
p := re.Interface().(cbg.CBORUnmarshaler) p := re.Interface().(cbg.CBORUnmarshaler)
if err := p.UnmarshalCBOR(bytes.NewReader(ret)); err != nil { if err := p.UnmarshalCBOR(bytes.NewReader(ret)); err != nil {
return "", err return "", err
@@ -1223,7 +1153,7 @@ var stateWaitMsgCmd = &cli.Command{
return err return err
} }
mw, err := api.StateWaitMsg(ctx, msg, build.MessageConfidence) mw, err := api.StateWaitMsg(ctx, msg)
if err != nil { if err != nil {
return err return err
} }
+2 -2
View File
@@ -7,7 +7,7 @@ import (
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
cid "github.com/ipfs/go-cid" cid "github.com/ipfs/go-cid"
"github.com/urfave/cli/v2" "gopkg.in/urfave/cli.v2"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
@@ -186,7 +186,7 @@ func SyncWait(ctx context.Context, napi api.FullNode) error {
fmt.Printf("\r\x1b[2KWorker %d: Target: %s\tState: %s\tHeight: %d", working, target, chain.SyncStageString(ss.Stage), ss.Height) fmt.Printf("\r\x1b[2KWorker %d: Target: %s\tState: %s\tHeight: %d", working, target, chain.SyncStageString(ss.Stage), ss.Height)
if time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs) { if time.Now().Unix()-int64(head.MinTimestamp()) < build.BlockDelay {
fmt.Println("\nDone!") fmt.Println("\nDone!")
return nil return nil
} }
+1 -1
View File
@@ -3,7 +3,7 @@ package cli
import ( import (
"fmt" "fmt"
"github.com/urfave/cli/v2" "gopkg.in/urfave/cli.v2"
) )
var versionCmd = &cli.Command{ var versionCmd = &cli.Command{
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/urfave/cli/v2" "gopkg.in/urfave/cli.v2"
) )
var waitApiCmd = &cli.Command{ var waitApiCmd = &cli.Command{

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