Compare commits

..
2 Commits
280 changed files with 5921 additions and 12362 deletions
+33 -18
View File
@@ -1,6 +1,6 @@
version: 2.1
orbs:
go: gotest/tools@0.0.13
go: gotest/tools@0.0.9
executors:
golang:
@@ -45,7 +45,7 @@ commands:
- 'v25-2k-lotus-params'
paths:
- /var/tmp/filecoin-proof-parameters/
- run: ./lotus fetch-params 2048
- run: ./lotus fetch-params --proving-params 2048
- save_cache:
name: Save parameters cache
key: 'v25-2k-lotus-params'
@@ -79,6 +79,7 @@ jobs:
steps:
- install-deps
- prepare
- go/mod-download
- go/mod-tidy-check
build-all:
@@ -86,8 +87,12 @@ jobs:
steps:
- install-deps
- prepare
- go/mod-download
- run: sudo apt-get update
- 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:
command: make buildall
- store_artifacts:
@@ -107,6 +112,10 @@ jobs:
steps:
- install-deps
- prepare
- go/mod-download
- restore_cache:
name: restore go mod cache
key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }}
- run:
command: make debug
@@ -125,9 +134,6 @@ jobs:
type: string
default: "./..."
description: Import paths of packages to be tested.
winpost-test:
type: string
default: "0"
test-suite-name:
type: string
default: unit
@@ -150,6 +156,10 @@ jobs:
steps:
- install-deps
- prepare
- go/mod-download
- restore_cache:
name: restore go mod cache
key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }}
- run:
command: make deps lotus
no_output_timeout: 30m
@@ -161,7 +171,6 @@ jobs:
environment:
GOTESTSUM_JUNITFILE: /tmp/test-reports/<< parameters.test-suite-name >>/junit.xml
GOTESTSUM_FORMAT: << parameters.gotestsum-format >>
LOTUS_TEST_WINDOW_POST: << parameters.winpost-test >>
command: |
mkdir -p /tmp/test-reports/<< parameters.test-suite-name >>
gotestsum -- \
@@ -180,11 +189,16 @@ jobs:
shell: /bin/bash -eo pipefail
command: |
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
test-window-post:
<<: *test
build-macos:
description: build darwin lotus binary
@@ -211,12 +225,14 @@ jobs:
- run:
name: Install jq
command: |
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
mkdir $HOME/.bin
curl --location https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64 --output $HOME/.bin/jq
chmod +x $HOME/.bin/jq
- 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" }}
- install-deps
- go/mod-download
- run:
command: make build
no_output_timeout: 30m
@@ -243,6 +259,7 @@ jobs:
steps:
- install-deps
- prepare
- go/mod-download
- run:
command: "! go fmt ./... 2>&1 | read"
@@ -255,7 +272,7 @@ jobs:
default: golang
golangci-lint-version:
type: string
default: 1.27.0
default: 1.23.8
concurrency:
type: string
default: '2'
@@ -271,6 +288,7 @@ jobs:
steps:
- install-deps
- prepare
- go/mod-download
- run:
command: make deps
no_output_timeout: 30m
@@ -280,7 +298,7 @@ jobs:
- run:
name: Lint
command: |
$HOME/.local/bin/golangci-lint run -v --timeout 2m \
$HOME/.local/bin/golangci-lint run -v \
--concurrency << parameters.concurrency >> << parameters.args >>
lint-changes:
<<: *lint
@@ -315,13 +333,10 @@ workflows:
jobs:
- lint-changes:
args: "--new-from-rev origin/master"
- mod-tidy-check
- gofmt
- test:
codecov-upload: true
- test-window-post:
go-test-flags: "-run=TestWindowedPost"
winpost-test: "1"
- mod-tidy-check
- gofmt
- test-short:
go-test-flags: "--timeout 10m --short"
filters:
-34
View File
@@ -1,34 +0,0 @@
---
name: Sealing Issues
about: Create a report for help with sealing (commit) failures.
title: ''
labels: 'sealing'
assignees: ''
---
Please provide all the information requested here to help us troubleshoot "commit failed" issues.
If the information requested is missing, we will probably have to just ask you to provide it anyway,
before we can help debug.
**Describe the problem**
A brief description of the problem you encountered while proving (sealing) a sector.
Including what commands you ran, and a description of your setup, is very helpful.
**Sectors list**
The output of `./lotus-storage-miner sectors list`.
**Sectors status**
The output of `./lotus-storage-miner sectors status --log <sectorId>` for the failed sector(s).
**Lotus storage miner logs**
Please go through the logs of your storage miner, and include screenshots of any error-like messages you find.
**Version**
The output of `./lotus --version`.
-1
View File
@@ -35,4 +35,3 @@ build/paramfetch.sh
bin/ipget
bin/tmp/*
.idea
scratchpad
+1 -15
View File
@@ -22,27 +22,13 @@ issues:
- "func name will be used as test\\.Test.* by other packages, and that stutters; consider calling this"
- "Potential file inclusion via variable"
- "should have( a package)? comment"
- "Error return value of `logging.SetLogLevel` is not checked"
exclude-use-default: false
exclude-rules:
- path: lotuspond
linters:
- errcheck
- path: node/modules/lp2p
linters:
- golint
- path: build/params_.*\.go
linters:
- golint
- path: api/apistruct/struct.go
linters:
- golint
- path: .*_test.go
- path: ".*_test.go"
linters:
- gosec
+3 -31
View File
@@ -6,7 +6,7 @@ all: build
unexport GOFLAGS
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))
$(error Update Golang to version $(shell grep '^go' go.mod))
endif
@@ -17,7 +17,7 @@ MODULES:=
CLEAN:=
BINS:=
ldflags=-X=github.com/filecoin-project/lotus/build.CurrentCommit=+git.$(subst -,.,$(shell git describe --always --match=NeVeRmAtCh --dirty 2>/dev/null || git rev-parse --short HEAD 2>/dev/null))
ldflags=-X=github.com/filecoin-project/lotus/build.CurrentCommit='+git$(subst -,.,$(shell git describe --always --match=NeVeRmAtCh --dirty 2>/dev/null || git rev-parse --short HEAD 2>/dev/null))'
ifneq ($(strip $(LDFLAGS)),)
ldflags+=-extldflags=$(LDFLAGS)
endif
@@ -103,21 +103,6 @@ install:
install -C ./lotus-storage-miner /usr/local/bin/lotus-storage-miner
install -C ./lotus-seal-worker /usr/local/bin/lotus-seal-worker
install-services: install
mkdir -p /usr/local/lib/systemd/system
mkdir -p /var/log/lotus
install -C -m 0644 ./scripts/lotus-daemon.service /usr/local/lib/systemd/system/lotus-daemon.service
install -C -m 0644 ./scripts/lotus-miner.service /usr/local/lib/systemd/system/lotus-miner.service
systemctl daemon-reload
@echo
@echo "lotus-daemon and lotus-miner services installed. Don't forget to 'systemctl enable lotus-daemon|lotus-miner' for it to be enabled on startup."
clean-services:
rm -f /usr/local/lib/systemd/system/lotus-daemon.service
rm -f /usr/local/lib/systemd/system/lotus-miner.service
rm -f /usr/local/lib/systemd/system/chainwatch.service
systemctl daemon-reload
# TOOLS
lotus-seed: $(BUILD_DEPS)
@@ -134,7 +119,7 @@ benchmarks:
@curl -X POST 'http://benchmark.kittyhawk.wtf/benchmark' -d '@bench.json' -u "${benchmark_http_cred}"
.PHONY: benchmarks
pond: 2k
pond: build
go build -o pond ./lotuspond
(cd lotuspond/front && npm i && CI=false npm run build)
.PHONY: pond
@@ -162,13 +147,6 @@ chainwatch:
.PHONY: 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:
rm -f bench
go build -o bench ./cmd/lotus-bench
@@ -191,12 +169,6 @@ health:
.PHONY: health
BINS+=health
testground:
go build -tags testground -o /dev/null ./cmd/lotus
.PHONY: testground
BINS+=testground
# MISC
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).
## Building & Documentation
For instructions on how to build lotus from source, please visit [https://docs.lotu.sh](https://docs.lotu.sh) or read the source [here](https://github.com/filecoin-project/lotus/tree/master/documentation).
## Reporting a Vulnerability
Please send an email to security@filecoin.org. See our [security policy](SECURITY.md) for more details.
## Development
All work is tracked via issues. An attempt at keeping an up-to-date view on remaining work is in the [lotus testnet github project board](https://github.com/filecoin-project/lotus/projects/1).
The main branches under development at the moment are:
* [`master`](https://github.com/filecoin-project/lotus): current testnet.
* [`next`](https://github.com/filecoin-project/lotus/tree/next): working branch with chain-breaking changes.
* [`interopnet`](https://github.com/filecoin-project/lotus/tree/interopnet): devnet running one of `next` commits.
## 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).
## 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: |
+7 -18
View File
@@ -4,22 +4,19 @@ import (
"context"
"fmt"
"github.com/filecoin-project/lotus/build"
"github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/filecoin-project/go-jsonrpc/auth"
"github.com/filecoin-project/lotus/build"
)
type Permission = string
type Common interface {
// Auth
AuthVerify(ctx context.Context, token string) ([]Permission, error)
AuthNew(ctx context.Context, perms []Permission) ([]byte, error)
// MethodGroup: Auth
AuthVerify(ctx context.Context, token string) ([]auth.Permission, error)
AuthNew(ctx context.Context, perms []auth.Permission) ([]byte, error)
// MethodGroup: Net
// network
NetConnectedness(context.Context, peer.ID) (network.Connectedness, error)
NetPeers(context.Context) ([]peer.AddrInfo, error)
@@ -27,9 +24,6 @@ type Common interface {
NetAddrsListen(context.Context) (peer.AddrInfo, error)
NetDisconnect(context.Context, peer.ID) 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(context.Context) (peer.ID, error)
@@ -39,11 +33,6 @@ type Common interface {
LogList(context.Context) ([]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
+21 -127
View File
@@ -28,134 +28,55 @@ type FullNode interface {
// TODO: TipSetKeys
// MethodGroup: Chain
// The Chain method group contains methods for interacting with the
// blockchain, but that do not require any form of state computation
// chain
// ChainNotify returns channel with chain head updates
// First message is guaranteed to be of len == 1, and type == 'current'
ChainNotify(context.Context) (<-chan []*HeadChange, error)
// ChainHead returns the current head of the chain
ChainHead(context.Context) (*types.TipSet, error)
// ChainGetRandomness is used to sample the chain for randomness
ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
// ChainGetBlock returns the block specified by the given CID
ChainGetBlock(context.Context, cid.Cid) (*types.BlockHeader, error)
ChainGetTipSet(context.Context, types.TipSetKey) (*types.TipSet, error)
// ChainGetBlockMessages returns messages stored in the specified block
ChainGetBlockMessages(ctx context.Context, blockCid cid.Cid) (*BlockMessages, error)
// ChainGetParentReceipts returns receipts for messages in parent tipset of
// the specified block
ChainGetParentReceipts(ctx context.Context, blockCid cid.Cid) ([]*types.MessageReceipt, error)
// ChainGetParentReceipts returns messages stored in parent tipset of the
// specified block
ChainGetParentMessages(ctx context.Context, blockCid cid.Cid) ([]Message, error)
// ChainGetTipSetByHeight looks back for a tipset at the specified epoch.
// If there are no blocks at the specified epoch, a tipset at higher epoch
// will be returned
ChainGetBlockMessages(context.Context, cid.Cid) (*BlockMessages, error)
ChainGetParentReceipts(context.Context, cid.Cid) ([]*types.MessageReceipt, error)
ChainGetParentMessages(context.Context, cid.Cid) ([]Message, 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)
// ChainHasObj checks if a given CID exists in the chain blockstore
ChainHasObj(context.Context, cid.Cid) (bool, error)
ChainStatObj(context.Context, cid.Cid, cid.Cid) (ObjStat, error)
// ChainSetHead forcefully sets current chain head. Use with caution
ChainSetHead(context.Context, types.TipSetKey) error
// ChainGetGenesis returns the genesis tipset
ChainGetGenesis(context.Context) (*types.TipSet, error)
// ChainTipSetWeight computes weight for the specified tipset
ChainTipSetWeight(context.Context, types.TipSetKey) (types.BigInt, error)
ChainGetNode(ctx context.Context, p string) (*IpldObject, error)
// ChainGetMessage reads a message referenced by the specified CID from the
// chain blockstore
ChainGetMessage(context.Context, cid.Cid) (*types.Message, error)
// ChainGetPath returns a set of revert/apply operations needed to get from
// one tipset to another, for example:
//```
// to
// ^
// from tAA
// ^ ^
// tBA tAB
// ^---*--^
// ^
// tRR
//```
// Would return `[revert(tBA), apply(tAB), apply(tAA)]`
ChainGetPath(ctx context.Context, from types.TipSetKey, to types.TipSetKey) ([]*HeadChange, error)
// ChainExport returns a stream of bytes with CAR dump of chain data
ChainExport(context.Context, types.TipSetKey) (<-chan []byte, error)
// MethodGroup: Sync
// The Sync method group contains methods for interacting with and
// observing the lotus sync service
// SyncState returns the current status of the lotus sync system
// syncer
SyncState(context.Context) (*SyncState, error)
// SyncSubmitBlock can be used to submit a newly created block to the
// network through this node
SyncSubmitBlock(ctx context.Context, blk *types.BlockMsg) error
// SyncIncomingBlocks returns a channel streaming incoming, potentially not
// yet synced block headers.
SyncIncomingBlocks(ctx context.Context) (<-chan *types.BlockHeader, error)
// SyncMarkBad marks a blocks as bad, meaning that it won't ever by synced.
// Use with extreme caution
SyncMarkBad(ctx context.Context, bcid cid.Cid) error
// SyncCheckBad checks if a block was marked as bad, and if it was, returns
// the reason
SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error)
// MethodGroup: Mpool
// The Mpool methods are for interacting with the message pool. The message pool
// manages all incoming and outgoing 'messages' going over the network.
// MpoolPending returns pending mempool messages
// messages
MpoolPending(context.Context, types.TipSetKey) ([]*types.SignedMessage, error)
// MpoolPush pushes a signed message to mempool
MpoolPush(context.Context, *types.SignedMessage) (cid.Cid, error)
// MpoolPushMessage 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
MpoolPushMessage(context.Context, *types.Message) (*types.SignedMessage, error) // get nonce, sign, push
MpoolGetNonce(context.Context, address.Address) (uint64, error)
MpoolSub(context.Context) (<-chan MpoolUpdate, error)
MpoolEstimateGasPrice(context.Context, uint64, address.Address, int64, types.TipSetKey) (types.BigInt, error)
// MpoolEstimateGasPrice 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)
// FullNodeStruct
// MethodGroup: Miner
// miner
MinerGetBaseInfo(context.Context, address.Address, abi.ChainEpoch, types.TipSetKey) (*MiningBaseInfo, error)
MinerCreateBlock(context.Context, *BlockTemplate) (*types.BlockMsg, error)
// // UX ?
// MethodGroup: Wallet
// wallet
WalletNew(context.Context, crypto.SigType) (address.Address, error)
WalletHas(context.Context, address.Address) (bool, error)
@@ -168,25 +89,17 @@ type FullNode interface {
WalletSetDefault(context.Context, address.Address) error
WalletExport(context.Context, address.Address) (*types.KeyInfo, error)
WalletImport(context.Context, *types.KeyInfo) (address.Address, error)
WalletDelete(context.Context, address.Address) error
// Other
// MethodGroup: Client
// The Client methods all have to do with interacting with the storage and
// retrieval markets as a client
// ClientImport imports file under the specified path into filestore
ClientImport(ctx context.Context, ref FileRef) (cid.Cid, error)
// ClientStartDeal proposes a deal with a miner
ClientStartDeal(ctx context.Context, params *StartDealParams) (*cid.Cid, error)
// ClientGetDeal info returns the latest information about a given deal
ClientGetDealInfo(context.Context, cid.Cid) (*DealInfo, error)
ClientListDeals(ctx context.Context) ([]DealInfo, error)
ClientHasLocal(ctx context.Context, root cid.Cid) (bool, error)
ClientFindData(ctx context.Context, root cid.Cid) ([]QueryOffer, error)
ClientMinerQueryOffer(ctx context.Context, root cid.Cid, miner address.Address) (QueryOffer, error)
ClientRetrieve(ctx context.Context, order RetrievalOrder, ref *FileRef) error
ClientRetrieve(ctx context.Context, order RetrievalOrder, ref FileRef) error
ClientQueryAsk(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error)
ClientCalcCommP(ctx context.Context, inpath string, miner address.Address) (*CommPRet, error)
ClientGenCar(ctx context.Context, ref FileRef, outpath string) error
@@ -199,14 +112,11 @@ type FullNode interface {
//ClientListAsks() []Ask
// MethodGroup: State
// The State methods are used to query, inspect, and interact with chain state
// if tipset is nil, we'll use heaviest
StateCall(context.Context, *types.Message, types.TipSetKey) (*InvocResult, error)
StateReplay(context.Context, types.TipSetKey, cid.Cid) (*InvocResult, error)
StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error)
StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*ActorState, error)
StateReadState(ctx context.Context, act *types.Actor, tsk types.TipSetKey) (*ActorState, error)
StateListMessages(ctx context.Context, match *types.Message, tsk types.TipSetKey, toht abi.ChainEpoch) ([]cid.Cid, error)
StateNetworkName(context.Context) (dtypes.NetworkName, error)
@@ -214,18 +124,14 @@ type FullNode interface {
StateMinerProvingSet(context.Context, address.Address, types.TipSetKey) ([]*ChainSectorInfo, error)
StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error)
StateMinerPower(context.Context, address.Address, types.TipSetKey) (*MinerPower, error)
StateMinerInfo(context.Context, address.Address, types.TipSetKey) (MinerInfo, error)
StateMinerInfo(context.Context, address.Address, types.TipSetKey) (miner.MinerInfo, error)
StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) (*miner.Deadlines, error)
StateMinerFaults(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error)
// Returns all non-expired Faults that occur within lookback epochs of the given tipset
StateAllMinerFaults(ctx context.Context, lookback abi.ChainEpoch, ts types.TipSetKey) ([]*Fault, error)
StateMinerRecoveries(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error)
StateMinerFaults(context.Context, address.Address, types.TipSetKey) ([]abi.SectorNumber, error)
StateMinerInitialPledgeCollateral(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (types.BigInt, error)
StateMinerAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error)
StateSectorGetInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error)
StatePledgeCollateral(context.Context, types.TipSetKey) (types.BigInt, error)
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*MsgLookup, error)
StateWaitMsg(context.Context, cid.Cid) (*MsgLookup, error)
StateSearchMsg(context.Context, cid.Cid) (*MsgLookup, error)
StateListMiners(context.Context, types.TipSetKey) ([]address.Address, error)
StateListActors(context.Context, types.TipSetKey) ([]address.Address, error)
@@ -240,10 +146,6 @@ type FullNode interface {
StateMinerSectorCount(context.Context, address.Address, types.TipSetKey) (MinerSectors, error)
StateCompute(context.Context, abi.ChainEpoch, []*types.Message, types.TipSetKey) (*ComputeStateOutput, error)
// MethodGroup: Msig
// The Msig methods are used to interact with multisig wallets on the
// filecoin network
MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
MsigCreate(context.Context, int64, []address.Address, types.BigInt, address.Address, types.BigInt) (cid.Cid, error)
MsigPropose(context.Context, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
@@ -253,9 +155,6 @@ type FullNode interface {
MarketEnsureAvailable(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error)
// MarketFreeBalance
// MethodGroup: Paych
// The Paych methods are for interacting with and managing payment channels
PaychGet(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*ChannelInfo, error)
PaychList(context.Context) ([]address.Address, error)
PaychStatus(context.Context, address.Address) (*PaychStatus, error)
@@ -418,11 +317,11 @@ type RetrievalOrder struct {
}
type InvocResult struct {
Msg *types.Message
MsgRct *types.MessageReceipt
ExecutionTrace types.ExecutionTrace
Error string
Duration time.Duration
Msg *types.Message
MsgRct *types.MessageReceipt
InternalExecutions []*types.ExecutionResult
Error string
Duration time.Duration
}
type MethodCall struct {
@@ -525,8 +424,3 @@ const (
MsigApprove MsigProposeResponse = iota
MsigCancel
)
type Fault struct {
Miner address.Address
Epoch abi.ChainEpoch
}
+3 -14
View File
@@ -8,10 +8,11 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-fil-markets/storagemarket"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/sector-storage/stores"
"github.com/filecoin-project/sector-storage/storiface"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/lotus/chain/types"
)
// StorageMiner is a low-level interface to the Filecoin network storage miner node
@@ -36,7 +37,6 @@ type StorageMiner interface {
SectorsRefs(context.Context) (map[string][]SealedRef, error)
SectorsUpdate(context.Context, abi.SectorNumber, SectorState) error
SectorRemove(context.Context, abi.SectorNumber) error
StorageList(ctx context.Context) (map[stores.ID][]stores.Decl, error)
StorageLocal(ctx context.Context) (map[stores.ID]string, error)
@@ -51,21 +51,10 @@ type StorageMiner interface {
MarketImportDealData(ctx context.Context, propcid cid.Cid, path string) error
MarketListDeals(ctx context.Context) ([]storagemarket.StorageDeal, error)
MarketListIncompleteDeals(ctx context.Context) ([]storagemarket.MinerDeal, error)
MarketSetAsk(ctx context.Context, price types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error
MarketGetAsk(ctx context.Context) (*storagemarket.SignedStorageAsk, error)
MarketSetPrice(context.Context, types.BigInt) error
DealsImportData(ctx context.Context, dealPropCid cid.Cid, file string) error
DealsList(ctx context.Context) ([]storagemarket.StorageDeal, error)
DealsConsiderOnlineStorageDeals(context.Context) (bool, error)
DealsSetConsiderOnlineStorageDeals(context.Context, bool) error
DealsConsiderOnlineRetrievalDeals(context.Context) (bool, error)
DealsSetConsiderOnlineRetrievalDeals(context.Context, bool) error
DealsPieceCidBlocklist(context.Context) ([]cid.Cid, error)
DealsSetPieceCidBlocklist(context.Context, []cid.Cid) error
DealsConsiderOfflineStorageDeals(context.Context) (bool, error)
DealsSetConsiderOfflineStorageDeals(context.Context, bool) error
DealsConsiderOfflineRetrievalDeals(context.Context) (bool, error)
DealsSetConsiderOfflineRetrievalDeals(context.Context, bool) error
StorageAddLocal(ctx context.Context, path string) error
}
+2 -11
View File
@@ -2,9 +2,6 @@ package api
import (
"context"
"io"
"github.com/ipfs/go-cid"
"github.com/filecoin-project/sector-storage/sealtasks"
"github.com/filecoin-project/sector-storage/stores"
@@ -15,7 +12,7 @@ import (
"github.com/filecoin-project/lotus/build"
)
type WorkerAPI interface {
type WorkerApi interface {
Version(context.Context) (build.Version, error)
// TODO: Info() (name, ...) ?
@@ -24,13 +21,7 @@ type WorkerAPI interface {
Info(context.Context) (storiface.WorkerInfo, error)
storage.Sealer
MoveStorage(ctx context.Context, sector abi.SectorID) 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
Fetch(context.Context, abi.SectorID, stores.SectorFileType, stores.PathType, stores.AcquireMode) error
Fetch(context.Context, abi.SectorID, stores.SectorFileType, bool) error
Closing(context.Context) (<-chan struct{}, error)
}
+86 -13
View File
@@ -1,38 +1,111 @@
package apistruct
import (
"github.com/filecoin-project/go-jsonrpc/auth"
"context"
"reflect"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/api"
)
type permKey int
var permCtxKey permKey
const (
// When changing these, update docs/API.md too
PermRead auth.Permission = "read" // default
PermWrite auth.Permission = "write"
PermSign auth.Permission = "sign" // Use wallet keys for signing
PermAdmin auth.Permission = "admin" // Manage permissions
PermRead api.Permission = "read" // default
PermWrite api.Permission = "write"
PermSign api.Permission = "sign" // Use wallet keys for signing
PermAdmin api.Permission = "admin" // Manage permissions
)
var AllPermissions = []auth.Permission{PermRead, PermWrite, PermSign, PermAdmin}
var DefaultPerms = []auth.Permission{PermRead}
var AllPermissions = []api.Permission{PermRead, PermWrite, PermSign, PermAdmin}
var defaultPerms = []api.Permission{PermRead}
func WithPerm(ctx context.Context, perms []api.Permission) context.Context {
return context.WithValue(ctx, permCtxKey, perms)
}
func PermissionedStorMinerAPI(a api.StorageMiner) api.StorageMiner {
var out StorageMinerStruct
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal)
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.CommonStruct.Internal)
permissionedAny(a, &out.Internal)
permissionedAny(a, &out.CommonStruct.Internal)
return &out
}
func PermissionedFullAPI(a api.FullNode) api.FullNode {
var out FullNodeStruct
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal)
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.CommonStruct.Internal)
permissionedAny(a, &out.Internal)
permissionedAny(a, &out.CommonStruct.Internal)
return &out
}
func PermissionedWorkerAPI(a api.WorkerAPI) api.WorkerAPI {
func PermissionedWorkerAPI(a api.WorkerApi) api.WorkerApi {
var out WorkerStruct
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal)
permissionedAny(a, &out.Internal)
return &out
}
func HasPerm(ctx context.Context, perm api.Permission) bool {
callerPerms, ok := ctx.Value(permCtxKey).([]api.Permission)
if !ok {
callerPerms = defaultPerms
}
for _, callerPerm := range callerPerms {
if callerPerm == perm {
return true
}
}
return false
}
func permissionedAny(in interface{}, out interface{}) {
rint := reflect.ValueOf(out).Elem()
ra := reflect.ValueOf(in)
for f := 0; f < rint.NumField(); f++ {
field := rint.Type().Field(f)
requiredPerm := api.Permission(field.Tag.Get("perm"))
if requiredPerm == "" {
panic("missing 'perm' tag on " + field.Name) // ok
}
// Validate perm tag
ok := false
for _, perm := range AllPermissions {
if requiredPerm == perm {
ok = true
break
}
}
if !ok {
panic("unknown 'perm' tag on " + field.Name) // ok
}
fn := ra.MethodByName(field.Name)
rint.Field(f).Set(reflect.MakeFunc(field.Type, func(args []reflect.Value) (results []reflect.Value) {
ctx := args[0].Interface().(context.Context)
if HasPerm(ctx, requiredPerm) {
return fn.Call(args)
}
err := xerrors.Errorf("missing permission to invoke '%s' (need '%s')", field.Name, requiredPerm)
rerr := reflect.ValueOf(&err).Elem()
if field.Type.NumOut() == 2 {
return []reflect.Value{
reflect.Zero(field.Type.Out(0)),
rerr,
}
} else {
return []reflect.Value{rerr}
}
}))
}
}
+60 -199
View File
@@ -2,7 +2,6 @@ package apistruct
import (
"context"
"io"
"github.com/ipfs/go-cid"
"github.com/libp2p/go-libp2p-core/network"
@@ -10,8 +9,6 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-fil-markets/storagemarket"
"github.com/filecoin-project/go-jsonrpc/auth"
"github.com/filecoin-project/sector-storage/sealtasks"
"github.com/filecoin-project/sector-storage/stores"
"github.com/filecoin-project/sector-storage/storiface"
@@ -33,8 +30,8 @@ var _ = AllPermissions
type CommonStruct struct {
Internal struct {
AuthVerify func(ctx context.Context, token string) ([]auth.Permission, error) `perm:"read"`
AuthNew func(ctx context.Context, perms []auth.Permission) ([]byte, error) `perm:"admin"`
AuthVerify func(ctx context.Context, token string) ([]api.Permission, error) `perm:"read"`
AuthNew func(ctx context.Context, perms []api.Permission) ([]byte, error) `perm:"admin"`
NetConnectedness func(context.Context, peer.ID) (network.Connectedness, error) `perm:"read"`
NetPeers func(context.Context) ([]peer.AddrInfo, error) `perm:"read"`
@@ -42,16 +39,12 @@ type CommonStruct struct {
NetAddrsListen func(context.Context) (peer.AddrInfo, error) `perm:"read"`
NetDisconnect func(context.Context, peer.ID) error `perm:"write"`
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"`
Version func(context.Context) (api.Version, error) `perm:"read"`
LogList func(context.Context) ([]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,41 +100,36 @@ type FullNodeStruct struct {
WalletSetDefault func(context.Context, address.Address) 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"`
WalletDelete func(context.Context, address.Address) error `perm:"write"`
ClientImport func(ctx context.Context, ref api.FileRef) (cid.Cid, error) `perm:"admin"`
ClientListImports func(ctx context.Context) ([]api.Import, error) `perm:"write"`
ClientHasLocal func(ctx context.Context, root cid.Cid) (bool, error) `perm:"write"`
ClientFindData func(ctx context.Context, root cid.Cid) ([]api.QueryOffer, error) `perm:"read"`
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"`
ClientGetDealInfo func(context.Context, cid.Cid) (*api.DealInfo, error) `perm:"read"`
ClientListDeals func(ctx context.Context) ([]api.DealInfo, error) `perm:"write"`
ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error `perm:"admin"`
ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
ClientCalcCommP func(ctx context.Context, inpath string, miner address.Address) (*api.CommPRet, error) `perm:"read"`
ClientGenCar func(ctx context.Context, ref api.FileRef, outpath string) error `perm:"write"`
ClientImport func(ctx context.Context, ref api.FileRef) (cid.Cid, error) `perm:"admin"`
ClientListImports func(ctx context.Context) ([]api.Import, error) `perm:"write"`
ClientHasLocal func(ctx context.Context, root cid.Cid) (bool, error) `perm:"write"`
ClientFindData func(ctx context.Context, root cid.Cid) ([]api.QueryOffer, error) `perm:"read"`
ClientStartDeal func(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) `perm:"admin"`
ClientGetDealInfo func(context.Context, cid.Cid) (*api.DealInfo, error) `perm:"read"`
ClientListDeals func(ctx context.Context) ([]api.DealInfo, error) `perm:"write"`
ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, ref api.FileRef) error `perm:"admin"`
ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
ClientCalcCommP func(ctx context.Context, inpath string, miner address.Address) (*api.CommPRet, error) `perm:"read"`
ClientGenCar func(ctx context.Context, ref api.FileRef, outpath string) error `perm:"write"`
StateNetworkName func(context.Context) (dtypes.NetworkName, error) `perm:"read"`
StateMinerSectors func(context.Context, address.Address, *abi.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"`
StateMinerProvingSet func(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"`
StateMinerProvingDeadline func(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error) `perm:"read"`
StateMinerPower func(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error) `perm:"read"`
StateMinerInfo func(context.Context, address.Address, types.TipSetKey) (api.MinerInfo, error) `perm:"read"`
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"`
StateMinerFaults func(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error) `perm:"read"`
StateAllMinerFaults func(context.Context, abi.ChainEpoch, types.TipSetKey) ([]*api.Fault, error) `perm:"read"`
StateMinerRecoveries func(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error) `perm:"read"`
StateMinerFaults func(context.Context, address.Address, types.TipSetKey) ([]abi.SectorNumber, error) `perm:"read"`
StateMinerInitialPledgeCollateral func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (types.BigInt, error) `perm:"read"`
StateMinerAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
StateSectorPreCommitInfo func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) `perm:"read"`
StateSectorGetInfo func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error) `perm:"read"`
StateCall func(context.Context, *types.Message, types.TipSetKey) (*api.InvocResult, error) `perm:"read"`
StateReplay func(context.Context, types.TipSetKey, cid.Cid) (*api.InvocResult, error) `perm:"read"`
StateGetActor func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) `perm:"read"`
StateReadState func(context.Context, 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"`
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"`
StateListMiners func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
StateListActors func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
@@ -194,11 +182,10 @@ type StorageMinerStruct struct {
MiningBase func(context.Context) (*types.TipSet, error) `perm:"read"`
MarketImportDealData func(context.Context, cid.Cid, string) error `perm:"write"`
MarketListDeals func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"`
MarketListIncompleteDeals func(ctx context.Context) ([]storagemarket.MinerDeal, error) `perm:"read"`
MarketSetAsk func(ctx context.Context, price types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error `perm:"admin"`
MarketGetAsk func(ctx context.Context) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
MarketImportDealData func(context.Context, cid.Cid, string) error `perm:"write"`
MarketListDeals func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"`
MarketListIncompleteDeals func(ctx context.Context) ([]storagemarket.MinerDeal, error) `perm:"read"`
MarketSetPrice func(context.Context, types.BigInt) error `perm:"admin"`
PledgeSector func(context.Context) error `perm:"write"`
@@ -206,36 +193,23 @@ type StorageMinerStruct struct {
SectorsList func(context.Context) ([]abi.SectorNumber, error) `perm:"read"`
SectorsRefs func(context.Context) (map[string][]api.SealedRef, error) `perm:"read"`
SectorsUpdate func(context.Context, abi.SectorNumber, api.SectorState) error `perm:"write"`
SectorRemove func(context.Context, abi.SectorNumber) error `perm:"admin"`
WorkerConnect func(context.Context, string) error `perm:"admin"` // TODO: worker perm
WorkerStats func(context.Context) (map[uint64]storiface.WorkerStats, error) `perm:"admin"`
StorageList func(context.Context) (map[stores.ID][]stores.Decl, error) `perm:"admin"`
StorageLocal func(context.Context) (map[stores.ID]string, error) `perm:"admin"`
StorageStat func(context.Context, stores.ID) (stores.FsStat, error) `perm:"admin"`
StorageAttach func(context.Context, stores.StorageInfo, stores.FsStat) error `perm:"admin"`
StorageDeclareSector func(context.Context, stores.ID, abi.SectorID, stores.SectorFileType, bool) error `perm:"admin"`
StorageDropSector func(context.Context, stores.ID, abi.SectorID, stores.SectorFileType) error `perm:"admin"`
StorageFindSector func(context.Context, abi.SectorID, stores.SectorFileType, bool) ([]stores.SectorStorageInfo, error) `perm:"admin"`
StorageInfo func(context.Context, stores.ID) (stores.StorageInfo, error) `perm:"admin"`
StorageBestAlloc func(ctx context.Context, allocate stores.SectorFileType, spt abi.RegisteredSealProof, sealing stores.PathType) ([]stores.StorageInfo, error) `perm:"admin"`
StorageReportHealth func(ctx context.Context, id stores.ID, report stores.HealthReport) error `perm:"admin"`
StorageLock func(ctx context.Context, sector abi.SectorID, read stores.SectorFileType, write stores.SectorFileType) error `perm:"admin"`
StorageTryLock func(ctx context.Context, sector abi.SectorID, read stores.SectorFileType, write stores.SectorFileType) (bool, error) `perm:"admin"`
StorageList func(context.Context) (map[stores.ID][]stores.Decl, error) `perm:"admin"`
StorageLocal func(context.Context) (map[stores.ID]string, error) `perm:"admin"`
StorageStat func(context.Context, stores.ID) (stores.FsStat, error) `perm:"admin"`
StorageAttach func(context.Context, stores.StorageInfo, stores.FsStat) error `perm:"admin"`
StorageDeclareSector func(context.Context, stores.ID, abi.SectorID, stores.SectorFileType) 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.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.RegisteredProof, sealing bool) ([]stores.StorageInfo, error) `perm:"admin"`
StorageReportHealth func(ctx context.Context, id stores.ID, report stores.HealthReport) error `perm:"admin"`
DealsImportData func(ctx context.Context, dealPropCid cid.Cid, file string) error `perm:"write"`
DealsList func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"`
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"`
DealsImportData func(ctx context.Context, dealPropCid cid.Cid, file string) error `perm:"write"`
DealsList func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"`
StorageAddLocal func(ctx context.Context, path string) error `perm:"admin"`
}
@@ -251,19 +225,13 @@ type WorkerStruct struct {
Paths func(context.Context) ([]stores.StoragePath, error) `perm:"admin"`
Info func(context.Context) (storiface.WorkerInfo, error) `perm:"admin"`
SealPreCommit1 func(ctx context.Context, sector abi.SectorID, ticket abi.SealRandomness, pieces []abi.PieceInfo) (storage.PreCommit1Out, error) `perm:"admin"`
SealPreCommit2 func(context.Context, abi.SectorID, storage.PreCommit1Out) (cids storage.SectorCids, err error) `perm:"admin"`
SealCommit1 func(ctx context.Context, sector abi.SectorID, ticket abi.SealRandomness, seed abi.InteractiveSealRandomness, pieces []abi.PieceInfo, cids storage.SectorCids) (storage.Commit1Out, error) `perm:"admin"`
SealCommit2 func(context.Context, abi.SectorID, storage.Commit1Out) (storage.Proof, error) `perm:"admin"`
FinalizeSector func(context.Context, abi.SectorID, []storage.Range) error `perm:"admin"`
ReleaseUnsealed func(ctx context.Context, sector abi.SectorID, safeToFree []storage.Range) error `perm:"admin"`
Remove func(ctx context.Context, sector abi.SectorID) error `perm:"admin"`
MoveStorage func(ctx context.Context, sector abi.SectorID) error `perm:"admin"`
SealPreCommit1 func(ctx context.Context, sector abi.SectorID, ticket abi.SealRandomness, pieces []abi.PieceInfo) (storage.PreCommit1Out, error) `perm:"admin"`
SealPreCommit2 func(context.Context, abi.SectorID, storage.PreCommit1Out) (cids storage.SectorCids, err error) `perm:"admin"`
SealCommit1 func(ctx context.Context, sector abi.SectorID, ticket abi.SealRandomness, seed abi.InteractiveSealRandomness, pieces []abi.PieceInfo, cids storage.SectorCids) (storage.Commit1Out, error) `perm:"admin"`
SealCommit2 func(context.Context, abi.SectorID, storage.Commit1Out) (storage.Proof, error) `perm:"admin"`
FinalizeSector func(context.Context, abi.SectorID) error `perm:"admin"`
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"`
Fetch func(context.Context, abi.SectorID, stores.SectorFileType, stores.PathType, stores.AcquireMode) error `perm:"admin"`
Fetch func(context.Context, abi.SectorID, stores.SectorFileType, bool) error `perm:"admin"`
Closing func(context.Context) (<-chan struct{}, error) `perm:"admin"`
}
@@ -271,17 +239,14 @@ type WorkerStruct struct {
// CommonStruct
func (c *CommonStruct) AuthVerify(ctx context.Context, token string) ([]auth.Permission, error) {
func (c *CommonStruct) AuthVerify(ctx context.Context, token string) ([]api.Permission, error) {
return c.Internal.AuthVerify(ctx, token)
}
func (c *CommonStruct) AuthNew(ctx context.Context, perms []auth.Permission) ([]byte, error) {
func (c *CommonStruct) AuthNew(ctx context.Context, perms []api.Permission) ([]byte, error) {
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) {
return c.Internal.NetConnectedness(ctx, pid)
}
@@ -324,14 +289,6 @@ func (c *CommonStruct) LogSetLevel(ctx context.Context, group, level string) err
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
func (c *FullNodeStruct) ClientListImports(ctx context.Context) ([]api.Import, error) {
@@ -350,10 +307,6 @@ func (c *FullNodeStruct) ClientFindData(ctx context.Context, root cid.Cid) ([]ap
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) {
return c.Internal.ClientStartDeal(ctx, params)
}
@@ -365,7 +318,7 @@ func (c *FullNodeStruct) ClientListDeals(ctx context.Context) ([]api.DealInfo, e
return c.Internal.ClientListDeals(ctx)
}
func (c *FullNodeStruct) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error {
func (c *FullNodeStruct) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref api.FileRef) error {
return c.Internal.ClientRetrieve(ctx, order, ref)
}
@@ -464,10 +417,6 @@ func (c *FullNodeStruct) WalletImport(ctx context.Context, ki *types.KeyInfo) (a
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) {
return c.Internal.MpoolGetNonce(ctx, addr)
}
@@ -576,7 +525,7 @@ func (c *FullNodeStruct) StateMinerPower(ctx context.Context, a address.Address,
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)
}
@@ -584,18 +533,10 @@ func (c *FullNodeStruct) StateMinerDeadlines(ctx context.Context, m address.Addr
return c.Internal.StateMinerDeadlines(ctx, m, tsk)
}
func (c *FullNodeStruct) StateMinerFaults(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*abi.BitField, error) {
func (c *FullNodeStruct) StateMinerFaults(ctx context.Context, actor address.Address, tsk types.TipSetKey) ([]abi.SectorNumber, error) {
return c.Internal.StateMinerFaults(ctx, actor, tsk)
}
func (c *FullNodeStruct) StateAllMinerFaults(ctx context.Context, cutoff abi.ChainEpoch, endTsk types.TipSetKey) ([]*api.Fault, error) {
return c.Internal.StateAllMinerFaults(ctx, cutoff, endTsk)
}
func (c *FullNodeStruct) StateMinerRecoveries(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*abi.BitField, error) {
return c.Internal.StateMinerRecoveries(ctx, actor, tsk)
}
func (c *FullNodeStruct) StateMinerInitialPledgeCollateral(ctx context.Context, maddr address.Address, snum abi.SectorNumber, tsk types.TipSetKey) (types.BigInt, error) {
return c.Internal.StateMinerInitialPledgeCollateral(ctx, maddr, snum, tsk)
}
@@ -608,10 +549,6 @@ func (c *FullNodeStruct) StateSectorPreCommitInfo(ctx context.Context, maddr add
return c.Internal.StateSectorPreCommitInfo(ctx, maddr, n, tsk)
}
func (c *FullNodeStruct) StateSectorGetInfo(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorOnChainInfo, error) {
return c.Internal.StateSectorGetInfo(ctx, maddr, n, tsk)
}
func (c *FullNodeStruct) StateCall(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (*api.InvocResult, error) {
return c.Internal.StateCall(ctx, msg, tsk)
}
@@ -624,16 +561,16 @@ func (c *FullNodeStruct) StateGetActor(ctx context.Context, actor address.Addres
return c.Internal.StateGetActor(ctx, actor, tsk)
}
func (c *FullNodeStruct) StateReadState(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*api.ActorState, error) {
return c.Internal.StateReadState(ctx, addr, tsk)
func (c *FullNodeStruct) StateReadState(ctx context.Context, act *types.Actor, tsk types.TipSetKey) (*api.ActorState, error) {
return c.Internal.StateReadState(ctx, act, tsk)
}
func (c *FullNodeStruct) StatePledgeCollateral(ctx context.Context, tsk types.TipSetKey) (types.BigInt, error) {
return c.Internal.StatePledgeCollateral(ctx, tsk)
}
func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid, confidence uint64) (*api.MsgLookup, error) {
return c.Internal.StateWaitMsg(ctx, msgc, confidence)
func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid) (*api.MsgLookup, error) {
return c.Internal.StateWaitMsg(ctx, msgc)
}
func (c *FullNodeStruct) StateSearchMsg(ctx context.Context, msgc cid.Cid) (*api.MsgLookup, error) {
@@ -796,10 +733,6 @@ func (c *StorageMinerStruct) SectorsUpdate(ctx context.Context, id abi.SectorNum
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 {
return c.Internal.WorkerConnect(ctx, url)
}
@@ -812,15 +745,15 @@ func (c *StorageMinerStruct) StorageAttach(ctx context.Context, si stores.Storag
return c.Internal.StorageAttach(ctx, si, st)
}
func (c *StorageMinerStruct) StorageDeclareSector(ctx context.Context, storageId stores.ID, s abi.SectorID, ft stores.SectorFileType, primary bool) error {
return c.Internal.StorageDeclareSector(ctx, storageId, s, ft, primary)
func (c *StorageMinerStruct) StorageDeclareSector(ctx context.Context, storageId stores.ID, s abi.SectorID, ft stores.SectorFileType) error {
return c.Internal.StorageDeclareSector(ctx, storageId, s, ft)
}
func (c *StorageMinerStruct) StorageDropSector(ctx context.Context, storageId stores.ID, s abi.SectorID, ft stores.SectorFileType) error {
return c.Internal.StorageDropSector(ctx, storageId, s, ft)
}
func (c *StorageMinerStruct) StorageFindSector(ctx context.Context, si abi.SectorID, types stores.SectorFileType, allowFetch bool) ([]stores.SectorStorageInfo, error) {
func (c *StorageMinerStruct) StorageFindSector(ctx context.Context, si abi.SectorID, types stores.SectorFileType, allowFetch bool) ([]stores.StorageInfo, error) {
return c.Internal.StorageFindSector(ctx, si, types, allowFetch)
}
@@ -840,22 +773,14 @@ func (c *StorageMinerStruct) StorageInfo(ctx context.Context, id stores.ID) (sto
return c.Internal.StorageInfo(ctx, id)
}
func (c *StorageMinerStruct) StorageBestAlloc(ctx context.Context, allocate stores.SectorFileType, spt abi.RegisteredSealProof, pt stores.PathType) ([]stores.StorageInfo, error) {
return c.Internal.StorageBestAlloc(ctx, allocate, spt, pt)
func (c *StorageMinerStruct) StorageBestAlloc(ctx context.Context, allocate stores.SectorFileType, spt abi.RegisteredProof, sealing bool) ([]stores.StorageInfo, error) {
return c.Internal.StorageBestAlloc(ctx, allocate, spt, sealing)
}
func (c *StorageMinerStruct) StorageReportHealth(ctx context.Context, id stores.ID, report stores.HealthReport) error {
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 {
return c.Internal.MarketImportDealData(ctx, propcid, path)
}
@@ -868,12 +793,8 @@ func (c *StorageMinerStruct) MarketListIncompleteDeals(ctx context.Context) ([]s
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 {
return c.Internal.MarketSetAsk(ctx, price, duration, minPieceSize, maxPieceSize)
}
func (c *StorageMinerStruct) MarketGetAsk(ctx context.Context) (*storagemarket.SignedStorageAsk, error) {
return c.Internal.MarketGetAsk(ctx)
func (c *StorageMinerStruct) MarketSetPrice(ctx context.Context, p types.BigInt) error {
return c.Internal.MarketSetPrice(ctx, p)
}
func (c *StorageMinerStruct) DealsImportData(ctx context.Context, dealPropCid cid.Cid, file string) error {
@@ -884,46 +805,6 @@ func (c *StorageMinerStruct) DealsList(ctx context.Context) ([]storagemarket.Sto
return c.Internal.DealsList(ctx)
}
func (c *StorageMinerStruct) DealsConsiderOnlineStorageDeals(ctx context.Context) (bool, error) {
return c.Internal.DealsConsiderOnlineStorageDeals(ctx)
}
func (c *StorageMinerStruct) DealsSetConsiderOnlineStorageDeals(ctx context.Context, b bool) error {
return c.Internal.DealsSetConsiderOnlineStorageDeals(ctx, b)
}
func (c *StorageMinerStruct) DealsConsiderOnlineRetrievalDeals(ctx context.Context) (bool, error) {
return c.Internal.DealsConsiderOnlineRetrievalDeals(ctx)
}
func (c *StorageMinerStruct) DealsSetConsiderOnlineRetrievalDeals(ctx context.Context, b bool) error {
return c.Internal.DealsSetConsiderOnlineRetrievalDeals(ctx, b)
}
func (c *StorageMinerStruct) DealsPieceCidBlocklist(ctx context.Context) ([]cid.Cid, error) {
return c.Internal.DealsPieceCidBlocklist(ctx)
}
func (c *StorageMinerStruct) DealsSetPieceCidBlocklist(ctx context.Context, cids []cid.Cid) error {
return c.Internal.DealsSetPieceCidBlocklist(ctx, cids)
}
func (c *StorageMinerStruct) DealsConsiderOfflineStorageDeals(ctx context.Context) (bool, error) {
return c.Internal.DealsConsiderOfflineStorageDeals(ctx)
}
func (c *StorageMinerStruct) DealsSetConsiderOfflineStorageDeals(ctx context.Context, b bool) error {
return c.Internal.DealsSetConsiderOfflineStorageDeals(ctx, b)
}
func (c *StorageMinerStruct) DealsConsiderOfflineRetrievalDeals(ctx context.Context) (bool, error) {
return c.Internal.DealsConsiderOfflineRetrievalDeals(ctx)
}
func (c *StorageMinerStruct) DealsSetConsiderOfflineRetrievalDeals(ctx context.Context, b bool) error {
return c.Internal.DealsSetConsiderOfflineRetrievalDeals(ctx, b)
}
func (c *StorageMinerStruct) StorageAddLocal(ctx context.Context, path string) error {
return c.Internal.StorageAddLocal(ctx, path)
}
@@ -962,32 +843,12 @@ func (w *WorkerStruct) SealCommit2(ctx context.Context, sector abi.SectorID, c1o
return w.Internal.SealCommit2(ctx, sector, c1o)
}
func (w *WorkerStruct) FinalizeSector(ctx context.Context, sector abi.SectorID, keepUnsealed []storage.Range) error {
return w.Internal.FinalizeSector(ctx, sector, keepUnsealed)
func (w *WorkerStruct) FinalizeSector(ctx context.Context, sector abi.SectorID) error {
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 {
return w.Internal.UnsealPiece(ctx, id, index, size, randomness, c)
}
func (w *WorkerStruct) ReadPiece(ctx context.Context, writer io.Writer, id abi.SectorID, index storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize) error {
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 {
return w.Internal.Fetch(ctx, id, fileType, ptype, am)
func (w *WorkerStruct) Fetch(ctx context.Context, id abi.SectorID, fileType stores.SectorFileType, b bool) error {
return w.Internal.Fetch(ctx, id, fileType, b)
}
func (w *WorkerStruct) Closing(ctx context.Context) (<-chan struct{}, error) {
@@ -997,4 +858,4 @@ func (w *WorkerStruct) Closing(ctx context.Context) (<-chan struct{}, error) {
var _ api.Common = &CommonStruct{}
var _ api.FullNode = &FullNodeStruct{}
var _ api.StorageMiner = &StorageMinerStruct{}
var _ api.WorkerAPI = &WorkerStruct{}
var _ api.WorkerApi = &WorkerStruct{}
+3 -4
View File
@@ -1,12 +1,11 @@
package client
import (
"github.com/filecoin-project/lotus/api/apistruct"
"net/http"
"github.com/filecoin-project/go-jsonrpc"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/apistruct"
"github.com/filecoin-project/lotus/lib/jsonrpc"
)
// NewCommonRPC creates a new http jsonrpc client.
@@ -48,7 +47,7 @@ func NewStorageMinerRPC(addr string, requestHeader http.Header) (api.StorageMine
return &res, closer, err
}
func NewWorkerRPC(addr string, requestHeader http.Header) (api.WorkerAPI, jsonrpc.ClientCloser, error) {
func NewWorkerRPC(addr string, requestHeader http.Header) (api.WorkerApi, jsonrpc.ClientCloser, error) {
var res apistruct.WorkerStruct
closer, err := jsonrpc.NewMergeClient(addr, "Filecoin",
[]interface{}{
-379
View File
@@ -1,379 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"go/ast"
"go/parser"
"go/token"
"reflect"
"sort"
"strings"
"time"
"unicode"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-bitfield"
"github.com/filecoin-project/go-jsonrpc/auth"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/apistruct"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-filestore"
"github.com/libp2p/go-libp2p-core/network"
peer "github.com/libp2p/go-libp2p-peer"
"github.com/multiformats/go-multiaddr"
)
var ExampleValues = map[reflect.Type]interface{}{
reflect.TypeOf(auth.Permission("")): auth.Permission("write"),
reflect.TypeOf(""): "string value",
reflect.TypeOf(uint64(42)): uint64(42),
reflect.TypeOf(byte(7)): byte(7),
reflect.TypeOf([]byte{}): []byte("byte array"),
}
func addExample(v interface{}) {
ExampleValues[reflect.TypeOf(v)] = v
}
func init() {
c, err := cid.Decode("bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4")
if err != nil {
panic(err)
}
ExampleValues[reflect.TypeOf(c)] = c
c2, err := cid.Decode("bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve")
if err != nil {
panic(err)
}
tsk := types.NewTipSetKey(c, c2)
ExampleValues[reflect.TypeOf(tsk)] = tsk
addr, err := address.NewIDAddress(1234)
if err != nil {
panic(err)
}
ExampleValues[reflect.TypeOf(addr)] = addr
pid, err := peer.IDB58Decode("12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf")
if err != nil {
panic(err)
}
addExample(pid)
addExample(bitfield.NewFromSet([]uint64{5}))
addExample(abi.RegisteredSealProof_StackedDrg32GiBV1)
addExample(abi.RegisteredPoStProof_StackedDrgWindow32GiBV1)
addExample(abi.ChainEpoch(10101))
addExample(crypto.SigTypeBLS)
addExample(int64(9))
addExample(12.3)
addExample(123)
addExample(uintptr(0))
addExample(abi.MethodNum(1))
addExample(exitcode.ExitCode(0))
addExample(crypto.DomainSeparationTag_ElectionProofProduction)
addExample(true)
addExample(abi.UnpaddedPieceSize(1024))
addExample(abi.UnpaddedPieceSize(1024).Padded())
addExample(abi.DealID(5432))
addExample(filestore.StatusFileChanged)
addExample(abi.SectorNumber(9))
addExample(abi.SectorSize(32 * 1024 * 1024 * 1024))
addExample(api.MpoolChange(0))
addExample(network.Connected)
addExample(dtypes.NetworkName("lotus"))
addExample(api.SyncStateStage(1))
addExample(build.APIVersion)
addExample(api.PCHInbound)
addExample(time.Minute)
addExample(&types.ExecutionTrace{
Msg: exampleValue(reflect.TypeOf(&types.Message{}), nil).(*types.Message),
MsgRct: exampleValue(reflect.TypeOf(&types.MessageReceipt{}), nil).(*types.MessageReceipt),
})
addExample(map[string]types.Actor{
"t01236": exampleValue(reflect.TypeOf(types.Actor{}), nil).(types.Actor),
})
addExample(map[string]api.MarketDeal{
"t026363": exampleValue(reflect.TypeOf(api.MarketDeal{}), nil).(api.MarketDeal),
})
addExample(map[string]api.MarketBalance{
"t026363": exampleValue(reflect.TypeOf(api.MarketBalance{}), nil).(api.MarketBalance),
})
maddr, err := multiaddr.NewMultiaddr("/ip4/52.36.61.156/tcp/1347/p2p/12D3KooWFETiESTf1v4PGUvtnxMAcEFMzLZbJGg4tjWfGEimYior")
if err != nil {
panic(err)
}
// because reflect.TypeOf(maddr) returns the concrete type...
ExampleValues[reflect.TypeOf(struct{ A multiaddr.Multiaddr }{}).Field(0).Type] = maddr
}
func exampleValue(t, parent reflect.Type) interface{} {
v, ok := ExampleValues[t]
if ok {
return v
}
switch t.Kind() {
case reflect.Slice:
out := reflect.New(t).Elem()
reflect.Append(out, reflect.ValueOf(exampleValue(t.Elem(), t)))
return out.Interface()
case reflect.Chan:
return exampleValue(t.Elem(), nil)
case reflect.Struct:
es := exampleStruct(t, parent)
v := reflect.ValueOf(es).Elem().Interface()
ExampleValues[t] = v
return v
case reflect.Array:
out := reflect.New(t).Elem()
for i := 0; i < t.Len(); i++ {
out.Index(i).Set(reflect.ValueOf(exampleValue(t.Elem(), t)))
}
return out.Interface()
case reflect.Ptr:
if t.Elem().Kind() == reflect.Struct {
es := exampleStruct(t.Elem(), t)
//ExampleValues[t] = es
return es
}
case reflect.Interface:
return struct{}{}
}
panic(fmt.Sprintf("No example value for type: %s", t))
}
func exampleStruct(t, parent reflect.Type) interface{} {
ns := reflect.New(t)
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
if f.Type == parent {
continue
}
if strings.Title(f.Name) == f.Name {
ns.Elem().Field(i).Set(reflect.ValueOf(exampleValue(f.Type, t)))
}
}
return ns.Interface()
}
type Visitor struct {
Methods map[string]ast.Node
}
func (v *Visitor) Visit(node ast.Node) ast.Visitor {
st, ok := node.(*ast.TypeSpec)
if !ok {
return v
}
if st.Name.Name != "FullNode" {
return nil
}
iface := st.Type.(*ast.InterfaceType)
for _, m := range iface.Methods.List {
if len(m.Names) > 0 {
v.Methods[m.Names[0].Name] = m
}
}
return v
}
const noComment = "There are not yet any comments for this method."
func parseApiASTInfo() (map[string]string, map[string]string) { //nolint:golint
fset := token.NewFileSet()
pkgs, err := parser.ParseDir(fset, "./api", nil, parser.AllErrors|parser.ParseComments)
if err != nil {
fmt.Println("parse error: ", err)
}
ap := pkgs["api"]
f := ap.Files["api/api_full.go"]
cmap := ast.NewCommentMap(fset, f, f.Comments)
v := &Visitor{make(map[string]ast.Node)}
ast.Walk(v, pkgs["api"])
groupDocs := make(map[string]string)
out := make(map[string]string)
for mn, node := range v.Methods {
cs := cmap.Filter(node).Comments()
if len(cs) == 0 {
out[mn] = noComment
} else {
for _, c := range cs {
if strings.HasPrefix(c.Text(), "MethodGroup:") {
parts := strings.Split(c.Text(), "\n")
groupName := strings.TrimSpace(parts[0][12:])
comment := strings.Join(parts[1:], "\n")
groupDocs[groupName] = comment
break
}
}
last := cs[len(cs)-1].Text()
if !strings.HasPrefix(last, "MethodGroup:") {
out[mn] = last
} else {
out[mn] = noComment
}
}
}
return out, groupDocs
}
type MethodGroup struct {
GroupName string
Header string
Methods []*Method
}
type Method struct {
Comment string
Name string
InputExample string
ResponseExample string
}
func methodGroupFromName(mn string) string {
i := strings.IndexFunc(mn[1:], func(r rune) bool {
return unicode.IsUpper(r)
})
if i < 0 {
return ""
}
return mn[:i+1]
}
func main() {
comments, groupComments := parseApiASTInfo()
groups := make(map[string]*MethodGroup)
var api struct{ api.FullNode }
t := reflect.TypeOf(api)
for i := 0; i < t.NumMethod(); i++ {
m := t.Method(i)
groupName := methodGroupFromName(m.Name)
g, ok := groups[groupName]
if !ok {
g = new(MethodGroup)
g.Header = groupComments[groupName]
g.GroupName = groupName
groups[groupName] = g
}
var args []interface{}
ft := m.Func.Type()
for j := 2; j < ft.NumIn(); j++ {
inp := ft.In(j)
args = append(args, exampleValue(inp, nil))
}
v, err := json.MarshalIndent(args, "", " ")
if err != nil {
panic(err)
}
outv := exampleValue(ft.Out(0), nil)
ov, err := json.MarshalIndent(outv, "", " ")
if err != nil {
panic(err)
}
g.Methods = append(g.Methods, &Method{
Name: m.Name,
Comment: comments[m.Name],
InputExample: string(v),
ResponseExample: string(ov),
})
}
var groupslice []*MethodGroup
for _, g := range groups {
groupslice = append(groupslice, g)
}
sort.Slice(groupslice, func(i, j int) bool {
return groupslice[i].GroupName < groupslice[j].GroupName
})
fmt.Printf("# Groups\n")
for _, g := range groupslice {
fmt.Printf("* [%s](#%s)\n", g.GroupName, g.GroupName)
for _, method := range g.Methods {
fmt.Printf(" * [%s](#%s)\n", method.Name, method.Name)
}
}
permStruct := reflect.TypeOf(apistruct.FullNodeStruct{}.Internal)
commonPermStruct := reflect.TypeOf(apistruct.CommonStruct{}.Internal)
for _, g := range groupslice {
g := g
fmt.Printf("## %s\n", g.GroupName)
fmt.Printf("%s\n\n", g.Header)
sort.Slice(g.Methods, func(i, j int) bool {
return g.Methods[i].Name < g.Methods[j].Name
})
for _, m := range g.Methods {
fmt.Printf("### %s\n", m.Name)
fmt.Printf("%s\n\n", m.Comment)
meth, ok := permStruct.FieldByName(m.Name)
if !ok {
meth, ok = commonPermStruct.FieldByName(m.Name)
if !ok {
panic("no perms for method: " + m.Name)
}
}
perms := meth.Tag.Get("perm")
fmt.Printf("Perms: %s\n\n", perms)
if strings.Count(m.InputExample, "\n") > 0 {
fmt.Printf("Inputs:\n```json\n%s\n```\n\n", m.InputExample)
} else {
fmt.Printf("Inputs: `%s`\n\n", m.InputExample)
}
if strings.Count(m.ResponseExample, "\n") > 0 {
fmt.Printf("Response:\n```json\n%s\n```\n\n", m.ResponseExample)
} else {
fmt.Printf("Response: `%s`\n\n", m.ResponseExample)
}
}
}
}
+10 -11
View File
@@ -8,7 +8,6 @@ import (
"math/rand"
"os"
"path/filepath"
"sync/atomic"
"testing"
"time"
@@ -36,7 +35,7 @@ func init() {
}
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()
n, sn := b(t, 1, oneMiner)
@@ -53,11 +52,11 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport
}
time.Sleep(time.Second)
mine := int64(1)
mine := true
done := make(chan struct{})
go func() {
defer close(done)
for atomic.LoadInt64(&mine) == 1 {
for mine {
time.Sleep(blocktime)
if err := sn[0].MineOne(ctx, func(bool) {}); err != nil {
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)
atomic.AddInt64(&mine, -1)
mine = false
fmt.Println("shutting down mining")
<-done
}
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()
n, sn := b(t, 1, oneMiner)
@@ -90,12 +89,12 @@ func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
}
time.Sleep(time.Second)
mine := int64(1)
mine := true
done := make(chan struct{})
go func() {
defer close(done)
for atomic.LoadInt64(&mine) == 1 {
for mine {
time.Sleep(blocktime)
if err := sn[0].MineOne(ctx, func(bool) {}); err != nil {
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, 7, client, miner, false)
atomic.AddInt64(&mine, -1)
mine = false
fmt.Println("shutting down mining")
<-done
}
@@ -194,14 +193,14 @@ func testRetrieval(t *testing.T, ctx context.Context, err error, client *impl.Fu
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(rpath) //nolint:errcheck
defer os.RemoveAll(rpath)
caddr, err := client.WalletDefaultAddress(ctx)
if err != nil {
t.Fatal(err)
}
ref := &api.FileRef{
ref := api.FileRef{
Path: filepath.Join(rpath, "ret"),
IsCAR: carExport,
}
+3 -4
View File
@@ -82,7 +82,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
}
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
@@ -126,7 +126,6 @@ func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExpo
minedTwo := make(chan struct{})
go func() {
doneMinedTwo := false
defer close(done)
prevExpect := 0
@@ -176,9 +175,9 @@ func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExpo
time.Sleep(blocktime)
}
if prevExpect == 2 && expect == 2 && !doneMinedTwo {
if prevExpect == 2 && expect == 2 && minedTwo != nil {
close(minedTwo)
doneMinedTwo = true
minedTwo = nil
}
prevExpect = expect
+4 -6
View File
@@ -4,11 +4,9 @@ import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/stretchr/testify/assert"
)
type TestNode struct {
@@ -23,8 +21,6 @@ type TestStorageNode struct {
var PresealGenesis = -1
const GenesisPreseals = 2
type StorageMiner struct {
Full int
Preseal int
@@ -64,7 +60,9 @@ func (ts *testSuite) testVersion(t *testing.T) {
if err != nil {
t.Fatal(err)
}
require.Equal(t, v.Version, build.BuildVersion)
if v.Version != build.BuildVersion {
t.Error("Version didn't work properly")
}
}
func (ts *testSuite) testID(t *testing.T) {
-169
View File
@@ -1,169 +0,0 @@
package test
import (
"context"
"fmt"
"github.com/filecoin-project/lotus/api"
"os"
"strings"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/filecoin-project/specs-actors/actors/abi"
miner2 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
sealing "github.com/filecoin-project/storage-fsm"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/node/impl"
)
func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) {
os.Setenv("BELLMAN_NO_GPU", "1")
ctx := context.Background()
n, sn := b(t, 1, oneMiner)
client := n[0].FullNode.(*impl.FullNodeAPI)
miner := sn[0]
addrinfo, err := client.NetAddrsListen(ctx)
if err != nil {
t.Fatal(err)
}
if err := miner.NetConnect(ctx, addrinfo); err != nil {
t.Fatal(err)
}
time.Sleep(time.Second)
mine := true
done := make(chan struct{})
go func() {
defer close(done)
for mine {
time.Sleep(blocktime)
if err := sn[0].MineOne(ctx, func(bool) {}); err != nil {
t.Error(err)
}
}
}()
pledgeSectors(t, ctx, miner, nSectors)
mine = false
<-done
}
func pledgeSectors(t *testing.T, ctx context.Context, miner TestStorageNode, n int) {
for i := 0; i < n; i++ {
err := miner.PledgeSector(ctx)
require.NoError(t, err)
}
for {
s, err := miner.SectorsList(ctx) // Note - the test builder doesn't import genesis sectors into FSM
require.NoError(t, err)
fmt.Printf("Sectors: %d\n", len(s))
if len(s) >= n {
break
}
time.Sleep(100 * time.Millisecond)
}
fmt.Printf("All sectors is fsm\n")
s, err := miner.SectorsList(ctx)
require.NoError(t, err)
toCheck := map[abi.SectorNumber]struct{}{}
for _, number := range s {
toCheck[number] = struct{}{}
}
for len(toCheck) > 0 {
for n := range toCheck {
st, err := miner.SectorsStatus(ctx, n)
require.NoError(t, err)
if st.State == api.SectorState(sealing.Proving) {
delete(toCheck, n)
}
if strings.Contains(string(st.State), "Fail") {
t.Fatal("sector in a failed state", st.State)
}
}
time.Sleep(100 * time.Millisecond)
fmt.Printf("WaitSeal: %d\n", len(s))
}
}
func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) {
os.Setenv("BELLMAN_NO_GPU", "1")
ctx := context.Background()
n, sn := b(t, 1, oneMiner)
client := n[0].FullNode.(*impl.FullNodeAPI)
miner := sn[0]
addrinfo, err := client.NetAddrsListen(ctx)
if err != nil {
t.Fatal(err)
}
if err := miner.NetConnect(ctx, addrinfo); err != nil {
t.Fatal(err)
}
time.Sleep(time.Second)
mine := true
done := make(chan struct{})
go func() {
defer close(done)
for mine {
time.Sleep(blocktime)
if err := sn[0].MineOne(ctx, func(bool) {}); err != nil {
t.Error(err)
}
}
}()
pledgeSectors(t, ctx, miner, nSectors)
maddr, err := miner.ActorAddress(ctx)
require.NoError(t, err)
di, err := client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK)
require.NoError(t, err)
fmt.Printf("Running one proving periods\n")
for {
head, err := client.ChainHead(ctx)
require.NoError(t, err)
if head.Height() > di.PeriodStart+(miner2.WPoStProvingPeriod)+2 {
break
}
if head.Height()%100 == 0 {
fmt.Printf("@%d\n", head.Height())
}
time.Sleep(blocktime)
}
p, err := client.StateMinerPower(ctx, maddr, types.EmptyTSK)
require.NoError(t, err)
ssz, err := miner.ActorSectorSize(ctx, maddr)
require.NoError(t, err)
require.Equal(t, p.MinerPower, p.TotalPower)
require.Equal(t, p.MinerPower.RawBytePower, types.NewInt(uint64(ssz)*uint64(nSectors+GenesisPreseals)))
// TODO: Inject faults here
mine = false
<-done
}
-43
View File
@@ -2,16 +2,11 @@ package api
import (
"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"
)
// TODO: check if this exists anywhere else
type MultiaddrSlice []ma.Multiaddr
func (m *MultiaddrSlice) UnmarshalJSON(raw []byte) (err error) {
@@ -37,41 +32,3 @@ type ObjStat struct {
Size 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) {
if DisableBuiltinAssets {
return nil, nil
}
var out []peer.AddrInfo
b := rice.MustFindBox("bootstrap")
@@ -38,12 +34,3 @@ func BuiltinBootstrap() ([]peer.AddrInfo, error) {
})
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
/ip4/86.109.15.57/tcp/1347/p2p/12D3KooWPdUquftaQvoQEtEdsRBAhwD6jopbF2oweVTzR59VbHEd
/dns4/bootstrap-0-dfw.fil-test.net/tcp/1347/p2p/12D3KooWQSCkHCzosEyrh8FgYfLejKgEPM5VB6qWzZE3yDAuXn8d
/ip4/139.178.84.45/tcp/1347/p2p/12D3KooWQSCkHCzosEyrh8FgYfLejKgEPM5VB6qWzZE3yDAuXn8d
/dns4/bootstrap-0-fra.fil-test.net/tcp/1347/p2p/12D3KooWEXN2eQmoyqnNjde9PBAQfQLHN67jcEdWU6JougWrgXJK
/ip4/136.144.49.17/tcp/1347/p2p/12D3KooWEXN2eQmoyqnNjde9PBAQfQLHN67jcEdWU6JougWrgXJK
/dns4/bootstrap-1-sin.fil-test.net/tcp/1347/p2p/12D3KooWLmJkZd33mJhjg5RrpJ6NFep9SNLXWc4uVngV4TXKwzYw
/ip4/86.109.15.123/tcp/1347/p2p/12D3KooWLmJkZd33mJhjg5RrpJ6NFep9SNLXWc4uVngV4TXKwzYw
/dns4/bootstrap-1-dfw.fil-test.net/tcp/1347/p2p/12D3KooWGXLHjiz6pTRu7x2pkgTVCoxcCiVxcNLpMnWcJ3JiNEy5
/ip4/139.178.86.3/tcp/1347/p2p/12D3KooWGXLHjiz6pTRu7x2pkgTVCoxcCiVxcNLpMnWcJ3JiNEy5
/dns4/bootstrap-1-fra.fil-test.net/tcp/1347/p2p/12D3KooW9szZmKttS9A1FafH3Zc2pxKwwmvCWCGKkRP4KmbhhC4R
/ip4/136.144.49.131/tcp/1347/p2p/12D3KooW9szZmKttS9A1FafH3Zc2pxKwwmvCWCGKkRP4KmbhhC4R
/dns4/t01000.miner.interopnet.kittyhawk.wtf/tcp/1347/p2p/12D3KooWQfrGdBE8N2RzcnuHfyWZ4MBKMYZ6z1oPdhEbFxSNo1du
/ip4/34.217.110.132/tcp/1347/p2p/12D3KooWQfrGdBE8N2RzcnuHfyWZ4MBKMYZ6z1oPdhEbFxSNo1du
/dns4/peer0.interopnet.kittyhawk.wtf/tcp/1347/p2p/12D3KooWKmHh5mQofRhFr6f6qsT4ksL7qUtd2BWC24wPHVFL9gej
/ip4/54.187.182.170/tcp/1347/p2p/12D3KooWKmHh5mQofRhFr6f6qsT4ksL7qUtd2BWC24wPHVFL9gej
/dns4/peer1.interopnet.kittyhawk.wtf/tcp/1347/p2p/12D3KooWCWWtn3GMFVSn2PY7k9K7QkQTVA6p6wojUr5PgS5h1xtK
/ip4/52.24.84.39/tcp/1347/p2p/12D3KooWCWWtn3GMFVSn2PY7k9K7QkQTVA6p6wojUr5PgS5h1xtK
-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.
+1 -1
View File
@@ -2,6 +2,6 @@ package build
import rice "github.com/GeertJohan/go.rice"
func ParametersJSON() []byte {
func ParametersJson() []byte {
return rice.MustFindBox("proof-params").MustBytes("parameters.json")
}
+5 -8
View File
@@ -7,22 +7,19 @@ import (
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/builtin/power"
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
)
func init() {
power.ConsensusMinerMinPower = big.NewInt(2048)
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
abi.RegisteredProof_StackedDRG2KiBSeal: {},
}
verifreg.MinVerifiedDealSize = big.NewInt(256)
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
// which the miner is slashed
-1
View File
@@ -4,7 +4,6 @@ package build
func init() {
InsecurePoStValidation = true
BuildType |= BuildDebug
}
// NOTE: Also includes settings from params_2k
@@ -1,9 +1,10 @@
// +build !testground
package build
import (
"math/big"
"sort"
"github.com/libp2p/go-libp2p-core/protocol"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin"
@@ -12,6 +13,32 @@ import (
"github.com/filecoin-project/lotus/node/modules/dtypes"
)
func DefaultSectorSize() abi.SectorSize {
szs := make([]abi.SectorSize, 0, len(miner.SupportedProofTypes))
for spt := range miner.SupportedProofTypes {
ss, err := spt.SectorSize()
if err != nil {
panic(err)
}
szs = append(szs, ss)
}
sort.Slice(szs, func(i, j int) bool {
return szs[i] < szs[i]
})
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
@@ -21,7 +48,8 @@ const UnixfsLinksPerLevel = 1024
// /////
// Consensus / Network
const AllowableClockDriftSecs = uint64(1)
// Seconds
const AllowableClockDrift = 1
// Epochs
const ForkLengthThreshold = Finality
@@ -31,12 +59,11 @@ var BlocksPerEpoch = uint64(builtin.ExpectedLeadersPerEpoch)
// Epochs
const Finality = miner.ChainFinalityish
const MessageConfidence = uint64(5)
// constants for Weight calculation
// The ratio of weight contributed by short-term vs long-term factors in a given round
const WRatioNum = int64(1)
const WRatioDen = uint64(2)
const WRatioDen = 2
// /////
// Proofs
@@ -54,25 +81,25 @@ const MaxSealLookback = SealRandomnessLookbackLimit + 2000 // TODO: Get from spe
// Mining
// Epochs
const TicketRandomnessLookback = abi.ChainEpoch(1)
const TicketRandomnessLookback = 1
const WinningPoStSectorSetLookback = abi.ChainEpoch(10)
const WinningPoStSectorSetLookback = 10
// /////
// Devnet settings
const TotalFilecoin = uint64(2_000_000_000)
const MiningRewardTotal = uint64(1_400_000_000)
const TotalFilecoin = 2_000_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
// TODO: Move other important consts here
func init() {
InitialRewardBalance = big.NewInt(int64(MiningRewardTotal))
InitialRewardBalance = InitialRewardBalance.Mul(InitialRewardBalance, big.NewInt(int64(FilecoinPrecision)))
InitialRewardBalance = big.NewInt(MiningRewardTotal)
InitialRewardBalance = InitialRewardBalance.Mul(InitialRewardBalance, big.NewInt(FilecoinPrecision))
}
// Sync
@@ -82,22 +109,16 @@ const BadBlockCacheSize = 1 << 15
// 10 block reorg.
const BlsSignatureCacheSize = 40000
// Size of signature verification cache
// 32k keeps the cache around 10MB in size, max
const VerifSigCacheSize = 32000
// ///////
// Limits
// TODO: If this is gonna stay, it should move to specs-actors
const BlockMessageLimit = 512
const BlockGasLimit = 100_000_000_000
const BlockGasLimit = 100_000_000
var DrandConfig = dtypes.DrandConfig{
Servers: []string{
"https://pl-eu.testnet.drand.sh",
"https://pl-us.testnet.drand.sh",
"https://pl-sin.testnet.drand.sh",
},
ChainInfoJSON: `{"public_key":"922a2e93828ff83345bae533f5172669a26c02dc76d6bf59c80892e12ab1455c229211886f35bb56af6d5bea981024df","period":25,"genesis_time":1590445175,"hash":"138a324aa6540f93d0dad002aa89454b1bec2b6e948682cde6bd4db40f4b7c9b"}`,
var DrandCoeffs = []string{
"82c279cce744450e68de98ee08f9698a01dd38f8e3be3c53f2b840fb9d09ad62a0b6b87981e179e1b14bc9a2d284c985",
"82d51308ad346c686f81b8094551597d7b963295cbf313401a93df9baf52d5ae98a87745bee70839a4d6e65c342bd15b",
"94eebfd53f4ba6a3b8304236400a12e73885e5a781509a5c8d41d2e8b476923d8ea6052649b3c17282f596217f96c5de",
"8dc4231e42b4edf39e86ef1579401692480647918275da767d3e558c520d6375ad953530610fd27daf110187877a65d0",
}
-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 !2k
// +build !testground
package build
@@ -13,13 +12,15 @@ import (
)
func init() {
power.ConsensusMinerMinPower = big.NewInt(1024 << 30)
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
abi.RegisteredSealProof_StackedDrg32GiBV1: {},
abi.RegisteredSealProof_StackedDrg64GiBV1: {},
power.ConsensusMinerMinPower = big.NewInt(2 << 30)
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
abi.RegisteredProof_StackedDRG512MiBSeal: {},
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": {
"cid": "QmeDRyxek34F1H6xJY6AkFdWvPsy5F6dKTrebV3ZtWT4ky",
"digest": "f5827f2d8801c62c831e0f972f6dc8bb",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0170db1f394b35d995252228ee359194b13199d259380541dc529fb0099096b0.params": {
"cid": "QmYkygifkXnrnsN4MJsjBFHTQJHx294CyikDgDK8nYxdGh",
"digest": "df3f30442a6d6b4192f5071fb17e820c",
"sector_size": 2048
},
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0170db1f394b35d995252228ee359194b13199d259380541dc529fb0099096b0.vk": {
"cid": "QmUw1ZmG4BBbX19MsbH3zAEGKUc42iFJc5ZAyomDHeJTsA",
"digest": "398fecdb4b2de445125852bc3c080b35",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0170db1f394b35d995252228ee359194b13199d259380541dc529fb0099096b0.vk": {
"cid": "QmdXyqbmy2bkJA9Kyhh6z25GrTCq48LwX6c1mxPsm54wi7",
"digest": "0bea3951abf9557a3569f68e52a30c6c",
"sector_size": 2048
},
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.params": {
"cid": "QmUeNKp9YZpiAFm81RV5KuxH1FDGJx2DuwcbU2XNSZLLSv",
"digest": "2b6d2972ac9e862e8134d98fb695b0c5",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.params": {
"cid": "Qmf5XZZtP5VcYTf65MbKjLVabcS6cYMbr2rFShmfJzh5e5",
"digest": "655e6277638edc8c658094f6f0b33d54",
"sector_size": 536870912
},
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.vk": {
"cid": "QmQaQmTXX995Akd66ggtJY5bNx6Gkxk8P34JTdMMq8393G",
"digest": "3688c9eb256b7b17f411dad78d5ef74a",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.vk": {
"cid": "QmPuhdWnAXBks43emnkqi9FQzyU1gASKyz23zrD27BPGs8",
"digest": "57690e3a6a94c3f704802a674b34f36b",
"sector_size": 536870912
},
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.params": {
"cid": "QmfEYTMSkwGJTumQx26iKXGNKiYh3mmAC4SkdybZpJCj5p",
"digest": "09bff16aed893349d94485cfae366a9c",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.params": {
"cid": "QmPNVgTN7N5vDtD5u7ERMTLcvUtrKRBfYVUDr6uW3pKhX7",
"digest": "3d390654f58e603b896ac70c653f5676",
"sector_size": 2048
},
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.vk": {
"cid": "QmP4ThPieSUJyRanjibWpT5R5cCMzMAU4j8Y7kBn7CSW1Q",
"digest": "142f2f7e8f1b1779290315cabfd2c803",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.vk": {
"cid": "Qmbj61Zez7v5xA7nSCnmWbyLYznWJDWeusz7Yg8EcgVdoN",
"digest": "8c170a164743c39576a7f47a1b51e6f3",
"sector_size": 2048
},
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.params": {
"cid": "QmcAixrHsz29DgvtZiMc2kQjvPRvWxYUp36QYmRDZbmREm",
"digest": "8f987f64d434365562180b96ec12e299",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.params": {
"cid": "QmRApb8RZoBK3cqicT7V3ydXg8yVvqPFMPrQNXP33aBihp",
"digest": "b1b58ff9a297b82885e8a7dfb035f83c",
"sector_size": 8388608
},
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.vk": {
"cid": "QmT4iFnbL6r4txS5PXsiV7NTzbhCxHy54PvdkJJGV2VFXb",
"digest": "94b6c24ac01924f4feeecedd16b5d77d",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.vk": {
"cid": "QmcytF1dTdqMFoyXi931j1RgmGtLfR9LLLaBznRt1tPQyD",
"digest": "1a09e00c641f192f55af3433a028f050",
"sector_size": 8388608
},
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.params": {
"cid": "QmbjFst6SFCK1KsTQrfwPdxf3VTNa1raed574tEZZ9PoyQ",
"digest": "2c245fe8179839dd6c6cdea207c67ae8",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.params": {
"cid": "QmPvr54tWaVeP4WnekivzUAJitTqsQfvikBvAHNEaDNQSw",
"digest": "9380e41368ed4083dbc922b290d3b786",
"sector_size": 8388608
},
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.vk": {
"cid": "QmQJKmvZN1a5cQ1Nw6CDyXs3nuRPzvyU5NvCFMUL2BfcZC",
"digest": "56ae47bfda53bb8d22981ed8d8d27d72",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.vk": {
"cid": "QmXyVLVDRCcxA9SjT7PeK8HFtyxZ2ZH3SHa8KoGLw8VGJt",
"digest": "f0731a7e20f90704bd38fc5d27882f6d",
"sector_size": 8388608
},
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.params": {
"cid": "QmQCABxeTpdvXTyjDyk7nPBxkQzCh7MXfGztWnSXEPKMLW",
"digest": "7e6b2eb5ecbb11ac651ad66ebbb2075a",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.params": {
"cid": "Qmf5f6ko3dqj7qauzXpZqxM9B2x2sL977K6gE2ppNwuJPv",
"digest": "273ebb8c896326b7c292bee8b775fd38",
"sector_size": 536870912
},
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.vk": {
"cid": "QmPBweyugh5Sx4umk8ULhgEGbjY8xmWLfU6M7EMpc8Mad6",
"digest": "94a8d9e25a9ab9674d339833664eba25",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.vk": {
"cid": "QmfP3MQe8koW63n5MkDENENVHxib78MJYYyZvbneCsuze8",
"digest": "3dd94da9da64e51b3445bc528d84e76d",
"sector_size": 536870912
},
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.params": {
"cid": "QmY5yax1E9KymBnCeHksE9Zi8NieZbmwcpoDGoabkeeb9h",
"digest": "c909ea9e3fe25ab9b391a64593afdbba",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.params": {
"cid": "QmYEeeCE8uT2bsVkxcqqUYeMmMEbe6rfmo8wQCv7jFHqqm",
"digest": "c947f2021304ed43b7216f7a8436e294",
"sector_size": 34359738368
},
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.vk": {
"cid": "QmXnPo4yH5mwMguwrvqgRfduSttbmPrXtbBfbwU21wQWHt",
"digest": "caf900461e988bbf86dbcaca087b7864",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.vk": {
"cid": "QmXB63ExriFjB4ywWnXTnFwCcLFfCeEP3h15qtL5i7F4aX",
"digest": "ab20d7b253e7e9a0d2ccdf7599ec8ec3",
"sector_size": 34359738368
},
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.params": {
"cid": "QmZtzzPWwmZEgR7MSMvXRbt9KVK8k4XZ5RLWHybHJW9SdE",
"digest": "a2844f0703f186d143a06146a04577d8",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.params": {
"cid": "QmW5Yxg3L1NSzuQVcRMHMbG3uvVoi4dTLzVaDpnEUPQpnA",
"digest": "079ba19645828ae42b22b0e3f4866e8d",
"sector_size": 34359738368
},
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.vk": {
"cid": "QmWxEA7EdQCUJTzjNpxg5XTF45D2uVyYnN1QRUb5TRYU8M",
"digest": "2306247a1e616dbe07f01b88196c2044",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.vk": {
"cid": "QmQzZ5dJ11tcSBees38WX41tZLXS9BqpEti253m5QcnTNs",
"digest": "c76125a50a7de315165de359b5174ae4",
"sector_size": 34359738368
},
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.params": {
"cid": "QmP676KwuvyF9Y64uJnXvLtvD1xcuWQ6wD23RzYtQ6dd4f",
"digest": "215b1c667a4f46a1d0178338df568615",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.params": {
"cid": "QmNk3wga1tS53FUu1QnkK8ehWA2cqpCnSEAPv3KLxdJxNa",
"digest": "421e4790c0b80e0107a7ff67acf14084",
"sector_size": 68719476736
},
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.vk": {
"cid": "QmPvPwbJtcSGyqB1rQJhSF5yvFbX9ZBSsHVej5F8JUyHUJ",
"digest": "0c9c423b28b1455fcbc329a1045fd4dd",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.vk": {
"cid": "QmVQCHGsrUtbn9RjHs1e6GXfeXDW5m9w4ge48PSX3Z2as2",
"digest": "8b60e9cc1470a6729c687d6cf0a1f79c",
"sector_size": 68719476736
},
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.params": {
"cid": "QmUxPQfvckzm1t6MFRdDZ1fDK5UJzAjK7pTZ97cwyachdr",
"digest": "965132f51ae445b0e6d32692b7561995",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.params": {
"cid": "QmTL3VvydaMFWKvE5VzxjgKsJYgL9JMM4JVYNtQxdj9JK1",
"digest": "2685f31124b22ea6b2857e5a5e87ffa3",
"sector_size": 68719476736
},
"v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.vk": {
"cid": "QmTxq2EBnQWb5R8tS4MHdchj4vNfLYGoSXxwJFvs5xgW4K",
"digest": "fc8c3d26e0e56373ad96cb41520d55a6",
"v26-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.vk": {
"cid": "QmSVWbLqQYbUbbJyfsRMzEib2rfSqMtnPks1Nw22omcBQm",
"digest": "efe703cd2839597c7ca5c2a906b74296",
"sector_size": 68719476736
},
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.params": {
"cid": "QmRjgZHERgqGoRagR788Kh6ybi26csVYa8mqbqhmZm57Jx",
"digest": "cfc7b0897d1eee48c586f7beb89e67f7",
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.params": {
"cid": "QmU9dH31nZZUJnsogR4Ld4ySUcH6wm2RgmGiujwnqtbU6k",
"digest": "fcef8e87ae2afd7a28aae44347b804cf",
"sector_size": 2048
},
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.vk": {
"cid": "QmNjvnvFP7KgovHUddULoB19fBHT81iz7NcUbzEHZUUPsm",
"digest": "fb59bd061c987eac7068008c44de346b",
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.vk": {
"cid": "QmdJ15DMGPooye5NaPcRfXUdHUDibcN7hKjbmTGuu1K4AQ",
"digest": "2ee2b3518229680db15161d4f582af37",
"sector_size": 2048
},
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.params": {
"cid": "QmTpRPBA4dt8fgGpcVzi4L1KA1U2eBHCE8WVmS2GUygMvT",
"digest": "36d465915b0afbf96bd08e7915e00952",
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.params": {
"cid": "QmZgtxcY3tMXXQxZTA7ZTUDXLVUnfxNcerXgeW4gG2NnfP",
"digest": "3273c7135cb75684248b475781b738ee",
"sector_size": 536870912
},
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.vk": {
"cid": "QmRzDyVfQCLsxspoVsed5bcQRsG6KiktngJfcNBL3TJPZe",
"digest": "99d16df0eb6a7e227a4f4570c4f6b6f1",
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.vk": {
"cid": "QmSS6ZkAV2aGZcgKgdPpEEgihXF1ryZX8PSAZDWSoeL1d4",
"digest": "1519b5f61d9044a59f2bdc57537c094b",
"sector_size": 536870912
},
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.params": {
"cid": "QmV8ZjTSGzDUWmFvsq9NSyPBR7eDDUcvCPNgj2yE7HMAFu",
"digest": "34f3ddf1d1c9f41c0cd73b91e8b4bc27",
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.params": {
"cid": "QmQBGXeiNn6hVwbR6qFarQqiNGDdKk4h9ucfyvcXyfYz2N",
"digest": "7d5f896f435c38e93bcda6dd168d860b",
"sector_size": 8388608
},
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.vk": {
"cid": "QmTa3VbjTiqJWU6r4WKayaQrUaaBsrpp5UDqYvPDd2C5hs",
"digest": "ec62d59651daa5631d3d1e9c782dd940",
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.vk": {
"cid": "QmPrZgBVGMckEAeu5eSJnLmiAwcPQjKjZe5ir6VaQ5AxKs",
"digest": "fe6d2de44580a0db5a4934688899b92f",
"sector_size": 8388608
},
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.params": {
"cid": "Qmf8ngfArxrv9tFWDqBcNegdBMymvuakwyHKd1pbW3pbsb",
"digest": "a16d6f4c6424fb280236739f84b24f97",
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.params": {
"cid": "QmZL2cq45XJn5BFzagAZwgFmLrcM1W6CXoiEF9C5j5tjEF",
"digest": "acdfed9f0512bc85a01a9fb871d475d5",
"sector_size": 34359738368
},
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.vk": {
"cid": "QmfQgVFerArJ6Jupwyc9tKjLD9n1J9ajLHBdpY465tRM7M",
"digest": "7a139d82b8a02e35279d657e197f5c1f",
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.vk": {
"cid": "QmQ4zB7nNa1tDYNifBkExRnZtwtxZw775iaqvVsZyRi6Q2",
"digest": "524a2f3e9d6826593caebc41bb545c40",
"sector_size": 34359738368
},
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.params": {
"cid": "QmfDha8271nXJn14Aq3qQeghjMBWbs6HNSGa6VuzCVk4TW",
"digest": "5d3cd3f107a3bea8a96d1189efd2965c",
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.params": {
"cid": "QmY7DitNKXFeLQt9QoVQkfjM1EvRnprqUVxjmkTXkHDNka",
"digest": "f27271c0537ba65ade2ec045f8fbd069",
"sector_size": 68719476736
},
"v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.vk": {
"cid": "QmRVtTtiFzHJTHurYzaCvetGAchux9cktixT4aGHthN6Zt",
"digest": "62c366405404e60f171e661492740b1c",
"v26-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.vk": {
"cid": "QmUJsvoCuQ4LszPmeRVAkMYb5qY95ctz3UXKhu8xLzyFKo",
"digest": "576b292938c6c9d0a0e721bd867a543b",
"sector_size": 68719476736
}
}
+3 -26
View File
@@ -3,33 +3,11 @@ package build
import "fmt"
var CurrentCommit string
var BuildType int
const (
BuildDefault = 0
Build2k = 0x1
BuildDebug = 0x3
)
func buildType() string {
switch BuildType {
case BuildDefault:
return ""
case BuildDebug:
return "+debug"
case Build2k:
return "+2k"
default:
return "+huh?"
}
}
// BuildVersion is the local build version, set by build system
const BuildVersion = "0.4.1"
const BuildVersion = "0.3.0"
func UserVersion() string {
return BuildVersion + buildType() + CurrentCommit
}
var UserVersion = BuildVersion + CurrentCommit
type Version uint32
@@ -53,9 +31,8 @@ func (ve Version) EqMajorMinor(v2 Version) bool {
}
// APIVersion is a semver version of the rpc api exposed
var APIVersion Version = newVer(0, 5, 0)
var APIVersion Version = newVer(0, 3, 0)
//nolint:varcheck,deadcode
const (
majorMask = 0xff0000
minorMask = 0xffff00
-1
View File
@@ -50,7 +50,6 @@ func Newf(retCode exitcode.ExitCode, format string, args ...interface{}) ActorEr
}
// todo: bit hacky
func NewfSkip(skip int, retCode exitcode.ExitCode, format string, args ...interface{}) ActorError {
if retCode == 0 {
return &actorError{
-4
View File
@@ -17,10 +17,6 @@ type Response struct {
Err error
}
// RandomBeacon represents a system that provides randomness to Lotus.
// Other components interrogate the RandomBeacon to acquire randomness that's
// valid for a specific chain epoch. Also to verify beacon entries that have
// been posted on chain.
type RandomBeacon interface {
Entry(context.Context, uint64) <-chan Response
VerifyEntry(types.BeaconEntry, types.BeaconEntry) error
+125 -83
View File
@@ -1,33 +1,48 @@
package drand
import (
"bytes"
"context"
"math/rand"
"sync"
"time"
dchain "github.com/drand/drand/chain"
dclient "github.com/drand/drand/client"
hclient "github.com/drand/drand/client/http"
dlog "github.com/drand/drand/log"
gclient "github.com/drand/drand/lp2p/client"
"github.com/drand/kyber"
kzap "github.com/go-kit/kit/log/zap"
"go.uber.org/zap/zapcore"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/beacon"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/specs-actors/actors/abi"
"golang.org/x/xerrors"
logging "github.com/ipfs/go-log"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/lotus/chain/beacon"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/node/modules/dtypes"
dbeacon "github.com/drand/drand/beacon"
"github.com/drand/drand/core"
dkey "github.com/drand/drand/key"
dnet "github.com/drand/drand/net"
dproto "github.com/drand/drand/protobuf/drand"
)
var log = logging.Logger("drand")
var drandServers = []string{
"nicolas.drand.fil-test.net:443",
"philipp.drand.fil-test.net:443",
"mathilde.drand.fil-test.net:443",
"ludovic.drand.fil-test.net:443",
"gabbi.drand.fil-test.net:443",
"linus.drand.fil-test.net:443",
"jeff.drand.fil-test.net:443",
}
var drandPubKey *dkey.DistPublic
func init() {
drandPubKey = new(dkey.DistPublic)
err := drandPubKey.FromTOML(&dkey.DistPublicTOML{Coefficients: build.DrandCoeffs})
if err != nil {
panic(err)
}
}
type drandPeer struct {
addr string
tls bool
@@ -41,17 +56,14 @@ func (dp *drandPeer) IsTLS() bool {
return dp.tls
}
// DrandBeacon connects Lotus with a drand network in order to provide
// randomness to the system in a way that's aligned with Filecoin rounds/epochs.
//
// We connect to drand peers via their public HTTP endpoints. The peers are
// enumerated in the drandServers variable.
//
// The root trust for the Drand chain is configured from build.DrandChain.
type DrandBeacon struct {
client dclient.Client
client dnet.Client
pubkey kyber.Point
peers []dnet.Peer
peersIndex int
peersIndexMtx sync.Mutex
pubkey *dkey.DistPublic
// seconds
interval time.Duration
@@ -64,91 +76,120 @@ type DrandBeacon struct {
localCache map[uint64]types.BeaconEntry
}
func NewDrandBeacon(genesisTs, interval uint64, ps *pubsub.PubSub, config dtypes.DrandConfig) (*DrandBeacon, error) {
func NewDrandBeacon(genesisTs, interval uint64) (*DrandBeacon, error) {
if genesisTs == 0 {
panic("what are you doing this cant be zero")
}
drandChain, err := dchain.InfoFromJSON(bytes.NewReader([]byte(config.ChainInfoJSON)))
if err != nil {
return nil, xerrors.Errorf("unable to unmarshal drand chain info: %w", err)
}
dlogger := dlog.NewKitLoggerFrom(kzap.NewZapSugarLogger(
log.SugaredLogger.Desugar(), zapcore.InfoLevel))
var clients []dclient.Client
for _, url := range config.Servers {
hc, err := hclient.NewWithInfo(url, drandChain, nil)
if err != nil {
return nil, xerrors.Errorf("could not create http drand client: %w", err)
}
clients = append(clients, hc)
}
opts := []dclient.Option{
dclient.WithChainInfo(drandChain),
dclient.WithCacheSize(1024),
dclient.WithLogger(dlogger),
dclient.WithAutoWatch(),
}
if ps != nil {
opts = append(opts, gclient.WithPubsub(ps))
} else {
log.Info("drand beacon without pubsub")
}
client, err := dclient.Wrap(clients, opts...)
if err != nil {
return nil, xerrors.Errorf("creating drand client")
}
db := &DrandBeacon{
client: client,
client: dnet.NewGrpcClient(),
localCache: make(map[uint64]types.BeaconEntry),
}
for _, ds := range drandServers {
db.peers = append(db.peers, &drandPeer{addr: ds, tls: true})
}
db.pubkey = drandChain.PublicKey
db.interval = drandChain.Period
db.drandGenTime = uint64(drandChain.GenesisTime)
db.peersIndex = rand.Intn(len(db.peers))
groupResp, err := db.client.Group(context.TODO(), db.peers[db.peersIndex], &dproto.GroupRequest{})
if err != nil {
return nil, xerrors.Errorf("failed to get group response from beacon peer: %w", err)
}
kgroup, err := core.ProtoToGroup(groupResp)
if err != nil {
return nil, xerrors.Errorf("failed to parse group response: %w", err)
}
// TODO: verify these values are what we expect them to be
if !kgroup.PublicKey.Equal(drandPubKey) {
return nil, xerrors.Errorf("public key does not match")
}
// fmt.Printf("Drand Pubkey:\n%#v\n", kgroup.PublicKey.TOML()) // use to print public key
db.pubkey = drandPubKey
db.interval = kgroup.Period
db.drandGenTime = uint64(kgroup.GenesisTime)
db.filRoundTime = interval
db.filGenTime = genesisTs
// TODO: the stream currently gives you back *all* values since drand genesis.
// Having the stream in the background is merely an optimization, so not a big deal to disable it for now
// go db.handleStreamingUpdates()
return db, nil
}
func (db *DrandBeacon) Entry(ctx context.Context, round uint64) <-chan beacon.Response {
out := make(chan beacon.Response, 1)
if round != 0 {
be := db.getCachedValue(round)
if be != nil {
out <- beacon.Response{Entry: *be}
close(out)
return out
func (db *DrandBeacon) rotatePeersIndex() {
db.peersIndexMtx.Lock()
nval := rand.Intn(len(db.peers))
db.peersIndex = nval
db.peersIndexMtx.Unlock()
log.Warnf("rotated to drand peer %d, %q", nval, db.peers[nval].Address())
}
func (db *DrandBeacon) getPeerIndex() int {
db.peersIndexMtx.Lock()
defer db.peersIndexMtx.Unlock()
return db.peersIndex
}
func (db *DrandBeacon) handleStreamingUpdates() {
for {
p := db.peers[db.getPeerIndex()]
ch, err := db.client.PublicRandStream(context.Background(), p, &dproto.PublicRandRequest{})
if err != nil {
log.Warnf("failed to get public rand stream to peer %q: %s", p.Address(), err)
log.Warnf("trying again in 10 seconds")
db.rotatePeersIndex()
time.Sleep(time.Second * 10)
continue
}
for e := range ch {
db.cacheValue(types.BeaconEntry{
Round: e.Round,
Data: e.Signature,
})
}
log.Warnf("drand beacon stream to peer %q broke, reconnecting in 10 seconds", p.Address())
db.rotatePeersIndex()
time.Sleep(time.Second * 10)
}
}
func (db *DrandBeacon) Entry(ctx context.Context, round uint64) <-chan beacon.Response {
// check cache, it it if there, otherwise query the endpoint
cres := db.getCachedValue(round)
if cres != nil {
out := make(chan beacon.Response, 1)
out <- beacon.Response{Entry: *cres}
close(out)
return out
}
out := make(chan beacon.Response, 1)
go func() {
start := time.Now()
log.Infow("start fetching randomness", "round", round)
resp, err := db.client.Get(ctx, round)
p := db.peers[db.getPeerIndex()]
resp, err := db.client.PublicRand(ctx, p, &dproto.PublicRandRequest{Round: round})
var br beacon.Response
if err != nil {
br.Err = xerrors.Errorf("drand failed Get request: %w", err)
db.rotatePeersIndex()
br.Err = xerrors.Errorf("drand peer %q failed publicRand request: %w", p.Address(), err)
} else {
br.Entry.Round = resp.Round()
br.Entry.Data = resp.Signature()
br.Entry.Round = resp.GetRound()
br.Entry.Data = resp.GetSignature()
}
log.Infow("done fetching randomness", "round", round, "took", time.Since(start))
out <- br
close(out)
}()
return out
}
func (db *DrandBeacon) cacheValue(e types.BeaconEntry) {
db.cacheLk.Lock()
defer db.cacheLk.Unlock()
@@ -170,12 +211,13 @@ func (db *DrandBeacon) VerifyEntry(curr types.BeaconEntry, prev types.BeaconEntr
// TODO handle genesis better
return nil
}
b := &dchain.Beacon{
b := &dbeacon.Beacon{
PreviousSig: prev.Data,
Round: curr.Round,
Signature: curr.Data,
}
err := dchain.VerifyBeacon(db.pubkey, b)
//log.Warnw("VerifyEntry", "beacon", b)
err := dbeacon.VerifyBeacon(db.pubkey.Key(), b)
if err == nil {
db.cacheValue(curr)
}
+7 -18
View File
@@ -1,25 +1,14 @@
package drand
import (
"os"
"fmt"
"testing"
dchain "github.com/drand/drand/chain"
hclient "github.com/drand/drand/client/http"
"github.com/stretchr/testify/assert"
"github.com/filecoin-project/lotus/build"
)
func TestPrintGroupInfo(t *testing.T) {
server := build.DrandConfig.Servers[0]
c, err := hclient.New(server, nil, nil)
assert.NoError(t, err)
cg := c.(interface {
FetchChainInfo(groupHash []byte) (*dchain.Info, error)
})
chain, err := cg.FetchChainInfo(nil)
assert.NoError(t, err)
err = chain.ToJSON(os.Stdout)
assert.NoError(t, err)
func TestPrintDrandPubkey(t *testing.T) {
bc, err := NewDrandBeacon(1, 1)
if err != nil {
t.Fatal(err)
}
fmt.Printf("Drand Pubkey:\n%#v\n", bc.pubkey.TOML())
}
+2 -21
View File
@@ -10,7 +10,6 @@ import (
"golang.org/x/xerrors"
cborutil "github.com/filecoin-project/go-cbor-util"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
@@ -28,24 +27,6 @@ const BlockSyncProtocolID = "/fil/sync/blk/0.0.1"
const BlockSyncMaxRequestLength = 800
// BlockSyncService is the component that services BlockSync requests from
// peers.
//
// BlockSync is the basic chain synchronization protocol of Filecoin. BlockSync
// is an RPC-oriented protocol, with a single operation to request blocks.
//
// A request contains a start anchor block (referred to with a CID), and a
// amount of blocks requested beyond the anchor (including the anchor itself).
//
// A client can also pass options, encoded as a 64-bit bitfield. Lotus supports
// two options at the moment:
//
// - include block contents
// - include block messages
//
// The response will include a status code, an optional message, and the
// response payload in case of success. The payload is a slice of serialized
// tipsets.
type BlockSyncService struct {
cs *store.ChainStore
}
@@ -110,7 +91,7 @@ func (bss *BlockSyncService) HandleStream(s inet.Stream) {
ctx, span := trace.StartSpan(context.Background(), "blocksync.HandleStream")
defer span.End()
defer s.Close() //nolint:errcheck
defer s.Close()
var req BlockSyncRequest
if err := cborutil.ReadCborRPC(bufio.NewReader(s), &req); err != nil {
@@ -126,7 +107,7 @@ func (bss *BlockSyncService) HandleStream(s inet.Stream) {
}
writeDeadline := 60 * time.Second
_ = s.SetDeadline(time.Now().Add(writeDeadline))
s.SetDeadline(time.Now().Add(writeDeadline))
if err := cborutil.WriteCborRPC(s, resp); err != nil {
log.Warnw("failed to write back response for handle stream", "err", err, "peer", s.Conn().RemotePeer())
return
+12 -24
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) {
ctx, span := trace.StartSpan(ctx, "bsync.GetBlocks")
defer span.End()
@@ -85,9 +80,7 @@ func (bs *BlockSync) GetBlocks(ctx context.Context, tsk types.TipSetKey, count i
Options: BSOptBlocks,
}
// this peerset is sorted by latency and failure counting.
peers := bs.getPeers()
// randomize the first few peers so we don't always pick the same peer
shufflePrefix(peers)
@@ -290,14 +283,14 @@ func (bs *BlockSync) fetchBlocksBlockSync(ctx context.Context, p peer.ID, req *B
bs.RemovePeer(p)
return nil, xerrors.Errorf("failed to open stream to peer: %w", err)
}
_ = s.SetWriteDeadline(time.Now().Add(5 * time.Second))
s.SetWriteDeadline(time.Now().Add(5 * time.Second))
if err := cborutil.WriteCborRPC(s, req); err != nil {
_ = s.SetWriteDeadline(time.Time{})
s.SetWriteDeadline(time.Time{})
bs.syncPeers.logFailure(p, time.Since(start))
return nil, err
}
_ = s.SetWriteDeadline(time.Time{})
s.SetWriteDeadline(time.Time{})
var res BlockSyncResponse
r := incrt.New(s, 50<<10, 5*time.Second)
@@ -363,7 +356,6 @@ func (bs *BlockSync) RemovePeer(p peer.ID) {
bs.syncPeers.removePeer(p)
}
// getPeers returns a preference-sorted set of peers to query.
func (bs *BlockSync) getPeers() []peer.ID {
return bs.syncPeers.prefSortedPeers()
}
@@ -569,30 +561,26 @@ func (bpt *bsPeerTracker) logSuccess(p peer.ID, dur time.Duration) {
bpt.lk.Lock()
defer bpt.lk.Unlock()
var pi *peerStats
var ok bool
if pi, ok = bpt.peers[p]; !ok {
if pi, ok := bpt.peers[p]; !ok {
log.Warnw("log success called on peer not in tracker", "peerid", p.String())
return
}
} else {
pi.successes++
pi.successes++
logTime(pi, dur)
logTime(pi, dur)
}
}
func (bpt *bsPeerTracker) logFailure(p peer.ID, dur time.Duration) {
bpt.lk.Lock()
defer bpt.lk.Unlock()
var pi *peerStats
var ok bool
if pi, ok = bpt.peers[p]; !ok {
if pi, ok := bpt.peers[p]; !ok {
log.Warn("log failure called on peer not in tracker", "peerid", p.String())
return
} else {
pi.failures++
logTime(pi, dur)
}
pi.failures++
logTime(pi, dur)
}
func (bpt *bsPeerTracker) removePeer(p peer.ID) {
+20 -15
View File
@@ -19,7 +19,7 @@ import (
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 RevertHandler func(ctx context.Context, ts *types.TipSet) error
@@ -31,18 +31,17 @@ type heightHandler struct {
revert RevertHandler
}
type eventAPI interface {
type eventApi interface {
ChainNotify(context.Context) (<-chan []*api.HeadChange, error)
ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error)
ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error)
StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error)
ChainGetTipSet(context.Context, types.TipSetKey) (*types.TipSet, error)
StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) // optional / for CalledMsg
}
type Events struct {
api eventAPI
api eventApi
tsc *tipSetCache
lk sync.Mutex
@@ -51,10 +50,10 @@ type Events struct {
readyOnce sync.Once
heightEvents
*hcEvents
calledEvents
}
func NewEvents(ctx context.Context, api eventAPI) *Events {
func NewEvents(ctx context.Context, api eventApi) *Events {
gcConfidence := 2 * build.ForkLengthThreshold
tsc := newTSCache(gcConfidence, api.ChainGetTipSetByHeight)
@@ -67,14 +66,25 @@ func NewEvents(ctx context.Context, api eventAPI) *Events {
heightEvents: heightEvents{
tsc: tsc,
ctx: ctx,
gcConfidence: gcConfidence,
gcConfidence: abi.ChainEpoch(gcConfidence),
heightTriggers: map[uint64]*heightHandler{},
htTriggerHeights: 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)
@@ -132,7 +142,7 @@ func (e *Events) listenHeadChangesOnce(ctx context.Context) error {
}
e.readyOnce.Do(func() {
e.lastTs = cur[0].Val
e.at = cur[0].Val.Height()
e.ready.Done()
})
@@ -153,11 +163,6 @@ func (e *Events) listenHeadChangesOnce(ctx context.Context) error {
if err := e.headChange(rev, app); err != nil {
log.Warnf("headChange failed: %s", err)
}
// sync with fake chainstore (for tests)
if fcs, ok := e.api.(interface{ notifDone() }); ok {
fcs.notifDone()
}
}
return nil
@@ -175,5 +180,5 @@ func (e *Events) headChange(rev, app []*types.TipSet) error {
return err
}
return e.processHeadChangeEvent(rev, app)
return e.headChangeCalled(rev, app)
}
+112 -372
View File
@@ -13,9 +13,8 @@ import (
)
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
type msgH = abi.ChainEpoch
@@ -24,60 +23,53 @@ type msgH = abi.ChainEpoch
// message (msgH+confidence)
type triggerH = abi.ChainEpoch
type eventData interface{}
// EventHandler arguments:
// `prevTs` is the previous tipset, eg the "from" tipset for a state change.
// `ts` is the event tipset, eg the tipset in which the `msg` is included.
// `ts` is the tipset, in which the `msg` is included.
// `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
// wait for has already happened in tipset `ts`
//
// If `done` is true, timeout won't be triggered
// If `more` is false, no messages will be sent to EventHandler (RevertHandler
// If `more` is false, no messages will be sent to CalledHandler (RevertHandler
// may still be called)
type CheckFunc func(ts *types.TipSet) (done bool, more bool, err error)
// Keep track of information for an event handler
type handlerInfo struct {
type MatchFunc func(msg *types.Message) (bool, error)
type callHandler struct {
confidence int
timeout abi.ChainEpoch
disabled bool // TODO: GC after gcConfidence reached
handle EventHandler
handle CalledHandler
revert RevertHandler
}
// When a change occurs, a queuedEvent is created and put into a queue
// until the required confidence is reached
type queuedEvent struct {
trigger triggerID
trigger triggerId
prevH abi.ChainEpoch
h abi.ChainEpoch
data eventData
h abi.ChainEpoch
msg *types.Message
called bool
}
// Manages chain head change events, which may be forward (new tipset added to
// chain) or backward (chain branch discarded in favour of heavier branch)
type hcEvents struct {
cs eventAPI
type calledEvents struct {
cs eventApi
tsc *tipSetCache
ctx context.Context
gcConfidence uint64
lastTs *types.TipSet
at abi.ChainEpoch
lk sync.Mutex
ctr triggerID
ctr triggerId
triggers map[triggerID]*handlerInfo
triggers map[triggerId]*callHandler
matchers map[triggerId][]MatchFunc
// maps block heights to events
// [triggerH][msgH][event]
@@ -86,81 +78,29 @@ type hcEvents struct {
// [msgH][triggerH]
revertQueue map[msgH][]triggerH
// [timeoutH+confidence][triggerID]{calls}
timeouts map[abi.ChainEpoch]map[triggerID]int
messageEvents
watcherEvents
// [timeoutH+confidence][triggerId]{calls}
timeouts map[abi.ChainEpoch]map[triggerId]int
}
func newHCEvents(ctx context.Context, cs eventAPI, tsc *tipSetCache, gcConfidence uint64) *hcEvents {
e := hcEvents{
ctx: ctx,
cs: cs,
tsc: tsc,
gcConfidence: gcConfidence,
confQueue: map[triggerH]map[msgH][]*queuedEvent{},
revertQueue: map[msgH][]triggerH{},
triggers: map[triggerID]*handlerInfo{},
timeouts: map[abi.ChainEpoch]map[triggerID]int{},
}
e.messageEvents = newMessageEvents(ctx, &e, cs)
e.watcherEvents = newWatcherEvents(ctx, &e, cs)
return &e
}
// Called when there is a change to the head with tipsets to be
// reverted / applied
func (e *hcEvents) processHeadChangeEvent(rev, app []*types.TipSet) error {
e.lk.Lock()
defer e.lk.Unlock()
func (e *calledEvents) headChangeCalled(rev, app []*types.TipSet) error {
for _, ts := range rev {
e.handleReverts(ts)
e.lastTs = ts
e.at = ts.Height()
}
for _, ts := range app {
// Check if the head change caused any state changes that we were
// waiting for
stateChanges := e.watcherEvents.checkStateChanges(e.lastTs, ts)
// Queue up calls until there have been enough blocks to reach
// confidence on the state changes
for tid, data := range stateChanges {
e.queueForConfidence(tid, data, e.lastTs, ts)
}
// Check if the head change included any new message calls
newCalls, err := e.messageEvents.checkNewCalls(ts)
if err != nil {
return err
}
// Queue up calls until there have been enough blocks to reach
// confidence on the message calls
for tid, data := range newCalls {
e.queueForConfidence(tid, data, nil, ts)
}
for at := e.lastTs.Height(); at <= ts.Height(); at++ {
// Apply any queued events and timeouts that were targeted at the
// current chain height
e.applyWithConfidence(ts, at)
// called triggers
e.checkNewCalls(ts)
for ; e.at <= ts.Height(); e.at++ {
e.applyWithConfidence(ts, e.at)
e.applyTimeouts(ts)
}
// Update the latest known tipset
e.lastTs = ts
}
return nil
}
func (e *hcEvents) handleReverts(ts *types.TipSet) {
func (e *calledEvents) handleReverts(ts *types.TipSet) {
reverts, ok := e.revertQueue[ts.Height()]
if !ok {
return // nothing to do
@@ -176,7 +116,7 @@ func (e *hcEvents) handleReverts(ts *types.TipSet) {
trigger := e.triggers[event.trigger]
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())
@@ -184,16 +124,38 @@ func (e *hcEvents) handleReverts(ts *types.TipSet) {
delete(e.revertQueue, ts.Height())
}
// Queue up events until the chain has reached a height that reflects the
// desired confidence
func (e *hcEvents) queueForConfidence(trigID uint64, data eventData, prevTs, ts *types.TipSet) {
trigger := e.triggers[trigID]
func (e *calledEvents) checkNewCalls(ts *types.TipSet) {
e.messagesForTs(ts, func(msg *types.Message) {
// TODO: provide receipts
prevH := NoHeight
if prevTs != nil {
prevH = prevTs.Height()
}
appliedH := ts.Height()
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]
// messages are not applied in the tipset they are included in
appliedH := ts.Height() + 1
triggerH := appliedH + abi.ChainEpoch(trigger.confidence)
@@ -204,20 +166,18 @@ func (e *hcEvents) queueForConfidence(trigID uint64, data eventData, prevTs, ts
}
byOrigH[appliedH] = append(byOrigH[appliedH], &queuedEvent{
trigger: trigID,
prevH: prevH,
trigger: triggerId,
h: appliedH,
data: data,
msg: msg,
})
e.revertQueue[appliedH] = append(e.revertQueue[appliedH], triggerH)
}
// Apply any events that were waiting for this chain height for confidence
func (e *hcEvents) applyWithConfidence(ts *types.TipSet, height abi.ChainEpoch) {
func (e *calledEvents) applyWithConfidence(ts *types.TipSet, height abi.ChainEpoch) {
byOrigH, ok := e.confQueue[height]
if !ok {
return // no triggers at this height
return // no triggers at thin height
}
for origH, events := range byOrigH {
@@ -236,20 +196,15 @@ func (e *hcEvents) applyWithConfidence(ts *types.TipSet, height abi.ChainEpoch)
continue
}
// Previous tipset - this is relevant for example in a state change
// from one tipset to another
var prevTs *types.TipSet
if event.prevH != NoHeight {
prevTs, err = e.tsc.get(event.prevH)
if err != nil {
log.Errorf("events: applyWithConfidence didn't find tipset for previous event; wanted %d; current %d", event.prevH, height)
continue
}
rec, err := e.cs.StateGetReceipt(e.ctx, event.msg.Cid(), ts.Key())
if err != nil {
log.Error(err)
return
}
more, err := trigger.handle(event.data, prevTs, triggerTs, height)
more, err := trigger.handle(event.msg, rec, triggerTs, height)
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
}
@@ -265,18 +220,17 @@ func (e *hcEvents) applyWithConfidence(ts *types.TipSet, height abi.ChainEpoch)
}
}
// Apply any timeouts that expire at this height
func (e *hcEvents) applyTimeouts(ts *types.TipSet) {
func (e *calledEvents) applyTimeouts(ts *types.TipSet) {
triggers, ok := e.timeouts[ts.Height()]
if !ok {
return // nothing to do
}
for triggerID, calls := range triggers {
for triggerId, calls := range triggers {
if calls > 0 {
continue // don't timeout if the method was called
}
trigger := e.triggers[triggerID]
trigger := e.triggers[triggerId]
if trigger.disabled {
continue
}
@@ -296,225 +250,12 @@ func (e *hcEvents) applyTimeouts(ts *types.TipSet) {
}
}
// Listen for an event
// - CheckFunc: immediately checks if the event already occurred
// - EventHandler: called when the event has occurred, after confidence tipsets
// - RevertHandler: called if the chain head changes causing the event to revert
// - confidence: wait this many tipsets before calling EventHandler
// - timeout: at this chain height, timeout on waiting for this event
func (e *hcEvents) onHeadChanged(check CheckFunc, hnd EventHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch) (triggerID, error) {
e.lk.Lock()
defer e.lk.Unlock()
// Check if the event has already occurred
ts := e.tsc.best()
done, more, err := check(ts)
if err != nil {
return 0, xerrors.Errorf("called check error (h: %d): %w", ts.Height(), err)
}
if done {
timeout = NoTimeout
}
// Create a trigger for the event
id := e.ctr
e.ctr++
e.triggers[id] = &handlerInfo{
confidence: confidence,
timeout: timeout + abi.ChainEpoch(confidence),
disabled: !more,
handle: hnd,
revert: rev,
}
// If there's a timeout, set up a timeout check at that height
if timeout != NoTimeout {
if e.timeouts[timeout+abi.ChainEpoch(confidence)] == nil {
e.timeouts[timeout+abi.ChainEpoch(confidence)] = map[uint64]int{}
}
e.timeouts[timeout+abi.ChainEpoch(confidence)][id] = 0
}
return id, nil
}
// headChangeAPI is used to allow the composed event APIs to call back to hcEvents
// to listen for changes
type headChangeAPI interface {
onHeadChanged(check CheckFunc, hnd EventHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch) (triggerID, error)
}
// watcherEvents watches for a state change
type watcherEvents struct {
ctx context.Context
cs eventAPI
hcAPI headChangeAPI
lk sync.RWMutex
matchers map[triggerID]StateMatchFunc
}
func newWatcherEvents(ctx context.Context, hcAPI headChangeAPI, cs eventAPI) watcherEvents {
return watcherEvents{
ctx: ctx,
cs: cs,
hcAPI: hcAPI,
matchers: make(map[triggerID]StateMatchFunc),
}
}
// Run each of the matchers against the previous and current state to see if
// there's a change
func (we *watcherEvents) checkStateChanges(oldState, newState *types.TipSet) map[triggerID]eventData {
we.lk.RLock()
defer we.lk.RUnlock()
res := make(map[triggerID]eventData)
for tid, matchFn := range we.matchers {
ok, data, err := matchFn(oldState, newState)
if err != nil {
log.Errorf("event diff fn failed: %s", err)
continue
}
if ok {
res[tid] = data
}
}
return res
}
// StateChange represents a change in state
type StateChange interface{}
// StateChangeHandler arguments:
// `oldTs` is the state "from" tipset
// `newTs` is the state "to" tipset
// `states` is the change in state
// `curH`-`ts.Height` = `confidence`
type StateChangeHandler func(oldTs, newTs *types.TipSet, states StateChange, curH abi.ChainEpoch) (more bool, err error)
type StateMatchFunc func(oldTs, newTs *types.TipSet) (bool, StateChange, error)
// StateChanged registers a callback which is triggered when a specified state
// change occurs or a timeout is reached.
//
// * `CheckFunc` callback is invoked immediately with a recent tipset, it
// returns two booleans - `done`, and `more`.
//
// * `done` should be true when some on-chain state change we are waiting
// for has happened. When `done` is set to true, timeout trigger is disabled.
//
// * `more` should be false when we don't want to receive new notifications
// through StateChangeHandler. Note that notifications may still be delivered to
// RevertHandler
//
// * `StateChangeHandler` is called when the specified state change was observed
// on-chain, and a confidence threshold was reached, or the specified `timeout`
// height was reached with no state change observed. When this callback is
// invoked on a timeout, `oldState` and `newState` are set to nil.
// This callback returns a boolean specifying whether further notifications
// should be sent, like `more` return param from `CheckFunc` above.
//
// * `RevertHandler` is called after apply handler, when we drop the tipset
// containing the message. The tipset passed as the argument is the tipset
// that is being dropped. Note that the event dropped may be re-applied
// in a different tipset in small amount of time.
//
// * `StateMatchFunc` is called against each tipset state. If there is a match,
// the state change is queued up until the confidence interval has elapsed (and
// `StateChangeHandler` is called)
func (we *watcherEvents) StateChanged(check CheckFunc, scHnd StateChangeHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, mf StateMatchFunc) error {
hnd := func(data eventData, prevTs, ts *types.TipSet, height abi.ChainEpoch) (bool, error) {
states, ok := data.(StateChange)
if data != nil && !ok {
panic("expected StateChange")
}
return scHnd(prevTs, ts, states, height)
}
id, err := we.hcAPI.onHeadChanged(check, hnd, rev, confidence, timeout)
if err != nil {
return err
}
we.lk.Lock()
defer we.lk.Unlock()
we.matchers[id] = mf
return nil
}
// messageEvents watches for message calls to actors
type messageEvents struct {
ctx context.Context
cs eventAPI
hcAPI headChangeAPI
lk sync.RWMutex
matchers map[triggerID][]MsgMatchFunc
}
func newMessageEvents(ctx context.Context, hcAPI headChangeAPI, cs eventAPI) messageEvents {
return messageEvents{
ctx: ctx,
cs: cs,
hcAPI: hcAPI,
matchers: map[triggerID][]MsgMatchFunc{},
}
}
// Check if there are any new actor calls
func (me *messageEvents) checkNewCalls(ts *types.TipSet) (map[triggerID]eventData, error) {
pts, err := me.cs.ChainGetTipSet(me.ctx, ts.Parents()) // we actually care about messages in the parent tipset here
if err != nil {
log.Errorf("getting parent tipset in checkNewCalls: %s", err)
return nil, err
}
me.lk.RLock()
defer me.lk.RUnlock()
res := make(map[triggerID]eventData)
me.messagesForTs(pts, func(msg *types.Message) {
// TODO: provide receipts
for tid, matchFns := range me.matchers {
var matched bool
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)) {
func (e *calledEvents) messagesForTs(ts *types.TipSet, consume func(*types.Message)) {
seen := map[cid.Cid]struct{}{}
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 {
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
@@ -543,27 +284,20 @@ func (me *messageEvents) messagesForTs(ts *types.TipSet, consume func(*types.Mes
}
}
// MsgHandler arguments:
// `ts` is the tipset, in which the `msg` is included.
// `curH`-`ts.Height` = `confidence`
type MsgHandler func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (more bool, err error)
type MsgMatchFunc func(msg *types.Message) (bool, error)
// Called registers a callback which is triggered when a specified method is
// Called registers a callbacks which are triggered when a specified method is
// called on an actor, or a timeout is reached.
//
// * `CheckFunc` callback is invoked immediately with a recent tipset, it
// returns two booleans - `done`, and `more`.
//
// * `done` should be true when some on-chain action we are waiting for has
// happened. When `done` is set to true, timeout trigger is disabled.
// * `done` should be true when some on-chain action we are waiting for has
// happened. When `done` is set to true, timeout trigger is disabled.
//
// * `more` should be false when we don't want to receive new notifications
// through MsgHandler. Note that notifications may still be delivered to
// RevertHandler
// * `more` should be false when we don't want to receive new notifications
// through CalledHandler. Note that notifications may still be delivered to
// 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
// 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
@@ -574,38 +308,44 @@ type MsgMatchFunc func(msg *types.Message) (bool, error)
// containing the message. The tipset passed as the argument is the tipset
// that is being dropped. Note that the message dropped may be re-applied
// in a different tipset in small amount of time.
//
// * `MsgMatchFunc` is called against each message. If there is a match, the
// message is queued up until the confidence interval has elapsed (and
// `MsgHandler` is called)
func (me *messageEvents) Called(check CheckFunc, msgHnd MsgHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, mf MsgMatchFunc) error {
hnd := func(data eventData, prevTs, ts *types.TipSet, height abi.ChainEpoch) (bool, error) {
msg, ok := data.(*types.Message)
if data != nil && !ok {
panic("expected msg")
}
func (e *calledEvents) Called(check CheckFunc, hnd CalledHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, mf MatchFunc) error {
e.lk.Lock()
defer e.lk.Unlock()
rec, err := me.cs.StateGetReceipt(me.ctx, msg.Cid(), ts.Key())
if err != nil {
return false, err
}
return msgHnd(msg, rec, ts, height)
}
id, err := me.hcAPI.onHeadChanged(check, hnd, rev, confidence, timeout)
ts := e.tsc.best()
done, more, err := check(ts)
if err != nil {
return err
return xerrors.Errorf("called check error (h: %d): %w", ts.Height(), err)
}
if done {
timeout = NoTimeout
}
me.lk.Lock()
defer me.lk.Unlock()
me.matchers[id] = append(me.matchers[id], mf)
id := e.ctr
e.ctr++
e.triggers[id] = &callHandler{
confidence: confidence,
timeout: timeout + abi.ChainEpoch(confidence),
disabled: !more,
handle: hnd,
revert: rev,
}
e.matchers[id] = append(e.matchers[id], mf)
if timeout != NoTimeout {
if e.timeouts[timeout+abi.ChainEpoch(confidence)] == nil {
e.timeouts[timeout+abi.ChainEpoch(confidence)] = map[uint64]int{}
}
e.timeouts[timeout+abi.ChainEpoch(confidence)][id] = 0
}
return nil
}
// Convenience function for checking and matching messages
func (me *messageEvents) CalledMsg(ctx context.Context, hnd MsgHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, msg types.ChainMsg) error {
return me.Called(me.CheckMsg(ctx, msg, hnd), hnd, rev, confidence, timeout, me.MatchMsg(msg.VMMessage()))
func (e *calledEvents) CalledMsg(ctx context.Context, hnd CalledHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, msg types.ChainMsg) error {
return e.Called(e.CheckMsg(ctx, msg, hnd), hnd, rev, confidence, timeout, e.MatchMsg(msg.VMMessage()))
}
+7 -15
View File
@@ -15,26 +15,23 @@ type heightEvents struct {
tsc *tipSetCache
gcConfidence abi.ChainEpoch
ctr triggerID
ctr triggerId
heightTriggers map[triggerID]*heightHandler
heightTriggers map[triggerId]*heightHandler
htTriggerHeights map[triggerH][]triggerID
htHeights map[msgH][]triggerID
htTriggerHeights map[triggerH][]triggerId
htHeights map[msgH][]triggerId
ctx context.Context
}
func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error {
ctx, span := trace.StartSpan(e.ctx, "events.HeightHeadChange")
defer span.End()
span.AddAttributes(trace.Int64Attribute("endHeight", int64(app[0].Height())))
span.AddAttributes(trace.Int64Attribute("reverts", int64(len(rev))))
span.AddAttributes(trace.Int64Attribute("applies", int64(len(app))))
e.lk.Lock()
defer e.lk.Unlock()
for _, ts := range rev {
// TODO: log error if h below gcconfidence
// revert height-based triggers
@@ -43,10 +40,7 @@ func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error {
for _, tid := range e.htHeights[h] {
ctx, span := trace.StartSpan(ctx, "events.HeightRevert")
rev := e.heightTriggers[tid].revert
e.lk.Unlock()
err := rev(ctx, ts)
e.lk.Lock()
err := e.heightTriggers[tid].revert(ctx, ts)
e.heightTriggers[tid].called = false
span.End()
@@ -104,10 +98,8 @@ func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error {
ctx, span := trace.StartSpan(ctx, "events.HeightApply")
span.AddAttributes(trace.BoolAttribute("immediate", false))
handle := hnd.handle
e.lk.Unlock()
err = handle(ctx, incTs, h)
e.lk.Lock()
err = hnd.handle(ctx, incTs, h)
span.End()
if err != nil {
+31 -394
View File
@@ -3,20 +3,21 @@ package events
import (
"context"
"fmt"
"sync"
"testing"
"time"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/store"
"github.com/ipfs/go-cid"
"github.com/multiformats/go-multihash"
"github.com/stretchr/testify/require"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
)
@@ -39,17 +40,9 @@ type fakeCS struct {
msgs map[cid.Cid]fakeMsg
blkMsgs map[cid.Cid]cid.Cid
sync sync.Mutex
tipsets map[types.TipSetKey]*types.TipSet
sub func(rev, app []*types.TipSet)
}
func (fcs *fakeCS) ChainGetTipSet(ctx context.Context, key types.TipSetKey) (*types.TipSet, error) {
return fcs.tipsets[key], nil
}
func (fcs *fakeCS) StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error) {
return nil, nil
}
@@ -62,7 +55,7 @@ func (fcs *fakeCS) ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types
panic("Not Implemented")
}
func (fcs *fakeCS) makeTs(t *testing.T, parents []cid.Cid, h abi.ChainEpoch, msgcid cid.Cid) *types.TipSet {
func makeTs(t *testing.T, h abi.ChainEpoch, msgcid cid.Cid) *types.TipSet {
a, _ := address.NewFromString("t00")
b, _ := address.NewFromString("t02")
var ts, err = types.NewTipSet([]*types.BlockHeader{
@@ -70,8 +63,6 @@ func (fcs *fakeCS) makeTs(t *testing.T, parents []cid.Cid, h abi.ChainEpoch, msg
Height: h,
Miner: a,
Parents: parents,
Ticket: &types.Ticket{VRFProof: []byte{byte(h % 2)}},
ParentStateRoot: dummyCid,
@@ -85,8 +76,6 @@ func (fcs *fakeCS) makeTs(t *testing.T, parents []cid.Cid, h abi.ChainEpoch, msg
Height: h,
Miner: b,
Parents: parents,
Ticket: &types.Ticket{VRFProof: []byte{byte((h + 1) % 2)}},
ParentStateRoot: dummyCid,
@@ -98,11 +87,6 @@ func (fcs *fakeCS) makeTs(t *testing.T, parents []cid.Cid, h abi.ChainEpoch, msg
},
})
if fcs.tipsets == nil {
fcs.tipsets = map[types.TipSetKey]*types.TipSet{}
}
fcs.tipsets[ts.Key()] = ts
require.NoError(t, err)
return ts
@@ -196,7 +180,7 @@ func (fcs *fakeCS) advance(rev, app int, msgs map[int]cid.Cid, nulls ...int) { /
continue
}
ts := fcs.makeTs(fcs.t, fcs.tsc.best().Key().Cids(), fcs.h, mc)
ts := makeTs(fcs.t, fcs.h, mc)
require.NoError(fcs.t, fcs.tsc.add(ts))
if hasMsgs {
@@ -206,19 +190,11 @@ func (fcs *fakeCS) advance(rev, app int, msgs map[int]cid.Cid, nulls ...int) { /
apps = append(apps, ts)
}
fcs.sync.Lock()
fcs.sub(revs, apps)
fcs.sync.Lock()
fcs.sync.Unlock() //nolint:staticcheck
time.Sleep(100 * time.Millisecond) // TODO: :c
}
func (fcs *fakeCS) notifDone() {
fcs.sync.Unlock()
}
var _ eventAPI = &fakeCS{}
var _ eventApi = &fakeCS{}
func TestAt(t *testing.T) {
fcs := &fakeCS{
@@ -226,7 +202,7 @@ func TestAt(t *testing.T) {
h: 1,
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
events := NewEvents(context.Background(), fcs)
@@ -291,7 +267,7 @@ func TestAtDoubleTrigger(t *testing.T) {
h: 1,
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
events := NewEvents(context.Background(), fcs)
@@ -333,7 +309,7 @@ func TestAtNullTrigger(t *testing.T) {
h: 1,
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
events := NewEvents(context.Background(), fcs)
@@ -367,7 +343,7 @@ func TestAtNullConf(t *testing.T) {
h: 1,
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
events := NewEvents(context.Background(), fcs)
@@ -406,7 +382,7 @@ func TestAtStart(t *testing.T) {
h: 1,
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
events := NewEvents(context.Background(), fcs)
@@ -440,7 +416,7 @@ func TestAtStartConfidence(t *testing.T) {
h: 1,
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
events := NewEvents(context.Background(), fcs)
@@ -470,7 +446,7 @@ func TestAtChained(t *testing.T) {
h: 1,
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
events := NewEvents(context.Background(), fcs)
@@ -504,7 +480,7 @@ func TestAtChainedConfidence(t *testing.T) {
h: 1,
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
events := NewEvents(context.Background(), fcs)
@@ -538,7 +514,7 @@ func TestAtChainedConfidenceNull(t *testing.T) {
h: 1,
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
events := NewEvents(context.Background(), fcs)
@@ -576,7 +552,7 @@ func TestCalled(t *testing.T) {
blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
events := NewEvents(context.Background(), fcs)
@@ -652,7 +628,7 @@ func TestCalled(t *testing.T) {
// revert the message
fcs.advance(2, 1, nil) // H=7, we reverted ts with the msg execution, but not the msg itself
fcs.advance(2, 1, nil) // H=7, we reverted ts with the msg
require.Equal(t, false, applied)
require.Equal(t, true, reverted)
@@ -666,17 +642,10 @@ func TestCalled(t *testing.T) {
},
})
fcs.advance(0, 3, map[int]cid.Cid{ // (n2msg confidence=1)
fcs.advance(0, 5, map[int]cid.Cid{ // (confidence=3)
0: n2msg,
})
require.Equal(t, true, applied) // msg from H=7, which had reverted execution
require.Equal(t, false, reverted)
require.Equal(t, abi.ChainEpoch(10), appliedH)
applied = false
fcs.advance(0, 2, nil) // (confidence=3)
require.Equal(t, true, applied)
require.Equal(t, false, reverted)
applied = false
@@ -690,7 +659,7 @@ func TestCalled(t *testing.T) {
// revert and apply at different height
fcs.advance(8, 6, map[int]cid.Cid{ // (confidence=3)
fcs.advance(4, 6, map[int]cid.Cid{ // (confidence=3)
1: n2msg,
})
@@ -702,9 +671,9 @@ func TestCalled(t *testing.T) {
reverted = false
applied = false
require.Equal(t, abi.ChainEpoch(7), appliedTs.Height())
require.Equal(t, abi.ChainEpoch(11), appliedTs.Height())
require.Equal(t, "bafkqaaa", appliedTs.Blocks()[0].Messages.String())
require.Equal(t, abi.ChainEpoch(10), appliedH)
require.Equal(t, abi.ChainEpoch(14), appliedH)
require.Equal(t, t0123, appliedMsg.To)
require.Equal(t, uint64(2), appliedMsg.Nonce)
require.Equal(t, abi.MethodNum(5), appliedMsg.Method)
@@ -728,7 +697,7 @@ func TestCalled(t *testing.T) {
}),
})
fcs.advance(2, 5, nil) // H=19, but message reverted
fcs.advance(1, 4, nil) // H=19, but message reverted
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
@@ -788,7 +757,7 @@ func TestCalledTimeout(t *testing.T) {
blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
events := NewEvents(context.Background(), fcs)
@@ -828,7 +797,7 @@ func TestCalledTimeout(t *testing.T) {
blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
events = NewEvents(context.Background(), fcs)
@@ -862,7 +831,7 @@ func TestCalledOrder(t *testing.T) {
blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
events := NewEvents(context.Background(), fcs)
@@ -925,7 +894,7 @@ func TestCalledNull(t *testing.T) {
blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
events := NewEvents(context.Background(), fcs)
@@ -980,335 +949,3 @@ func TestCalledNull(t *testing.T) {
require.Equal(t, false, applied)
require.Equal(t, true, reverted)
}
func TestRemoveTriggersOnMessage(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)
t0123, err := address.NewFromString("t0123")
require.NoError(t, err)
more := true
var applied, reverted bool
err = events.Called(func(ts *types.TipSet) (d bool, m bool, e error) {
return false, true, nil
}, func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, 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
}, 3, 20, matchAddrMethod(t0123, 5))
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 blocks with message (but below confidence threshold)
fcs.advance(0, 3, map[int]cid.Cid{ // msg occurs at H=5, applied at H=6; H=8 (confidence=2)
0: fcs.fakeMsgs(fakeMsg{
bmsgs: []*types.Message{
{To: t0123, From: t0123, Method: 5, Nonce: 1},
},
}),
})
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// revert applied TS & message TS
fcs.advance(3, 1, nil) // H=6 (tipset message applied in reverted, AND message reverted)
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// create additional blocks so we are above confidence threshold, but message not applied
// as it was reverted
fcs.advance(0, 5, nil) // H=11 (confidence=3, apply)
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// create blocks with message again (but below confidence threshold)
fcs.advance(0, 3, map[int]cid.Cid{ // msg occurs at H=12, applied at H=13; H=15 (confidence=2)
0: fcs.fakeMsgs(fakeMsg{
bmsgs: []*types.Message{
{To: t0123, From: t0123, Method: 5, Nonce: 2},
},
}),
})
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// revert applied height TS, but don't remove message trigger
fcs.advance(2, 1, nil) // H=13 (tipset message applied in reverted, by tipset with message not reverted)
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// create additional blocks so we are above confidence threshold
fcs.advance(0, 4, nil) // H=18 (confidence=3, apply)
require.Equal(t, true, applied)
require.Equal(t, false, reverted)
}
type testStateChange struct {
from string
to string
}
func TestStateChanged(t *testing.T) {
fcs := &fakeCS{
t: t,
h: 1,
msgs: map[cid.Cid]fakeMsg{},
blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
events := NewEvents(context.Background(), fcs)
more := true
var applied, reverted bool
var appliedData StateChange
var appliedOldTs *types.TipSet
var appliedNewTs *types.TipSet
var appliedH abi.ChainEpoch
var matchData StateChange
confidence := 3
timeout := abi.ChainEpoch(20)
err := events.StateChanged(func(ts *types.TipSet) (d bool, m bool, e error) {
return false, true, nil
}, func(oldTs, newTs *types.TipSet, data StateChange, curH abi.ChainEpoch) (bool, error) {
require.Equal(t, false, applied)
applied = true
appliedData = data
appliedOldTs = oldTs
appliedNewTs = newTs
appliedH = curH
return more, nil
}, func(_ context.Context, ts *types.TipSet) error {
reverted = true
return nil
}, confidence, timeout, func(oldTs, newTs *types.TipSet) (bool, StateChange, error) {
if matchData == nil {
return false, matchData, nil
}
d := matchData
matchData = nil
return true, d, nil
})
require.NoError(t, err)
// create few blocks to make sure nothing get's randomly called
fcs.advance(0, 4, nil) // H=5
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// create state change (but below confidence threshold)
matchData = testStateChange{from: "a", to: "b"}
fcs.advance(0, 3, nil)
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// create additional block so we are above confidence threshold
fcs.advance(0, 2, nil) // H=10 (confidence=3, apply)
require.Equal(t, true, applied)
require.Equal(t, false, reverted)
applied = false
// dip below confidence (should not apply again)
fcs.advance(2, 2, nil) // H=10 (confidence=3, apply)
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// Change happens from 5 -> 6
require.Equal(t, abi.ChainEpoch(5), appliedOldTs.Height())
require.Equal(t, abi.ChainEpoch(6), appliedNewTs.Height())
// Actually applied (with confidence) at 9
require.Equal(t, abi.ChainEpoch(9), appliedH)
// Make sure the state change was correctly passed through
rcvd := appliedData.(testStateChange)
require.Equal(t, "a", rcvd.from)
require.Equal(t, "b", rcvd.to)
}
func TestStateChangedRevert(t *testing.T) {
fcs := &fakeCS{
t: t,
h: 1,
msgs: map[cid.Cid]fakeMsg{},
blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
events := NewEvents(context.Background(), fcs)
more := true
var applied, reverted bool
var matchData StateChange
confidence := 1
timeout := abi.ChainEpoch(20)
err := events.StateChanged(func(ts *types.TipSet) (d bool, m bool, e error) {
return false, true, nil
}, func(oldTs, newTs *types.TipSet, data StateChange, curH abi.ChainEpoch) (bool, error) {
require.Equal(t, false, applied)
applied = true
return more, nil
}, func(_ context.Context, ts *types.TipSet) error {
reverted = true
return nil
}, confidence, timeout, func(oldTs, newTs *types.TipSet) (bool, StateChange, error) {
if matchData == nil {
return false, matchData, nil
}
d := matchData
matchData = nil
return true, d, nil
})
require.NoError(t, err)
fcs.advance(0, 2, nil) // H=3
// Make a state change from TS at height 3 to TS at height 4
matchData = testStateChange{from: "a", to: "b"}
fcs.advance(0, 1, nil) // H=4
// Haven't yet reached confidence
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// Advance to reach confidence level
fcs.advance(0, 1, nil) // H=5
// Should now have called the handler
require.Equal(t, true, applied)
require.Equal(t, false, reverted)
applied = false
// Advance 3 more TS
fcs.advance(0, 3, nil) // H=8
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// Regress but not so far as to cause a revert
fcs.advance(3, 1, nil) // H=6
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// Regress back to state where change happened
fcs.advance(3, 1, nil) // H=4
// Expect revert to have happened
require.Equal(t, false, applied)
require.Equal(t, true, reverted)
}
func TestStateChangedTimeout(t *testing.T) {
fcs := &fakeCS{
t: t,
h: 1,
msgs: map[cid.Cid]fakeMsg{},
blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
events := NewEvents(context.Background(), fcs)
called := false
err := events.StateChanged(func(ts *types.TipSet) (d bool, m bool, e error) {
return false, true, nil
}, func(oldTs, newTs *types.TipSet, data StateChange, curH abi.ChainEpoch) (bool, error) {
called = true
require.Nil(t, data)
require.Equal(t, abi.ChainEpoch(20), newTs.Height())
require.Equal(t, abi.ChainEpoch(23), curH)
return false, nil
}, func(_ context.Context, ts *types.TipSet) error {
t.Fatal("revert on timeout")
return nil
}, 3, 20, func(oldTs, newTs *types.TipSet) (bool, StateChange, error) {
return false, nil, nil
})
require.NoError(t, err)
fcs.advance(0, 21, nil)
require.False(t, called)
fcs.advance(0, 5, nil)
require.True(t, called)
called = false
// with check func reporting done
fcs = &fakeCS{
t: t,
h: 1,
msgs: map[cid.Cid]fakeMsg{},
blkMsgs: map[cid.Cid]cid.Cid{},
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
events = NewEvents(context.Background(), fcs)
err = events.StateChanged(func(ts *types.TipSet) (d bool, m bool, e error) {
return true, true, nil
}, func(oldTs, newTs *types.TipSet, data StateChange, curH abi.ChainEpoch) (bool, error) {
called = true
require.Nil(t, data)
require.Equal(t, abi.ChainEpoch(20), newTs.Height())
require.Equal(t, abi.ChainEpoch(23), curH)
return false, nil
}, func(_ context.Context, ts *types.TipSet) error {
t.Fatal("revert on timeout")
return nil
}, 3, 20, func(oldTs, newTs *types.TipSet) (bool, StateChange, error) {
return false, nil, nil
})
require.NoError(t, err)
fcs.advance(0, 21, nil)
require.False(t, called)
fcs.advance(0, 5, nil)
require.False(t, called)
}
-137
View File
@@ -1,137 +0,0 @@
package state
import (
"context"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/lotus/api/apibstore"
"github.com/filecoin-project/lotus/chain/types"
"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/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
)
// UserData is the data returned from the DiffFunc
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)),
}
}
// DiffFunc 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 DiffFunc func(ctx context.Context, oldState, newState *types.TipSet) (changed bool, user UserData, err error)
type DiffStateFunc 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 DiffStateFunc) DiffFunc {
return func(ctx context.Context, oldState, newState *types.TipSet) (changed bool, user UserData, err error) {
oldActor, err := sp.api.StateGetActor(ctx, addr, oldState.Key())
if err != nil {
return false, nil, err
}
newActor, err := sp.api.StateGetActor(ctx, addr, newState.Key())
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) DiffFunc {
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 DiffDealStatesFunc func(ctx context.Context, oldDealStateRoot *amt.Root, newDealStateRoot *amt.Root) (changed bool, user UserData, err error)
// OnDealStateChanged calls diffDealStates when the market state changes
func (sp *StatePredicates) OnDealStateChanged(diffDealStates DiffDealStatesFunc) 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
}
oldRoot, err := amt.LoadAMT(ctx, sp.cst, oldState.States)
if err != nil {
return false, nil, err
}
newRoot, err := amt.LoadAMT(ctx, sp.cst, newState.States)
if err != nil {
return false, nil, err
}
return diffDealStates(ctx, oldRoot, newRoot)
}
}
// 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 {
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) DiffDealStatesFunc {
return func(ctx context.Context, oldDealStateRoot *amt.Root, newDealStateRoot *amt.Root) (changed bool, user UserData, err error) {
changedDeals := make(ChangedDeals)
for _, dealID := range dealIds {
var oldDeal, newDeal market.DealState
err := oldDealStateRoot.Get(ctx, uint64(dealID), &oldDeal)
if err != nil {
return false, nil, err
}
err = newDealStateRoot.Get(ctx, uint64(dealID), &newDeal)
if err != nil {
return false, nil, err
}
if oldDeal != newDeal {
changedDeals[dealID] = DealStateChange{oldDeal, newDeal}
}
}
if len(changedDeals) > 0 {
return true, changedDeals, nil
}
return false, nil, nil
}
}
-201
View File
@@ -1,201 +0,0 @@
package state
import (
"context"
"testing"
"github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/ipfs/go-hamt-ipld"
"github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/specs-actors/actors/builtin/market"
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"
"golang.org/x/xerrors"
"github.com/ipfs/go-cid"
"github.com/stretchr/testify/require"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/specs-actors/actors/abi"
)
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 TestPredicates(t *testing.T) {
ctx := context.Background()
bs := bstore.NewBlockstore(ds_sync.MutexWrap(ds.NewMapDatastore()))
store := cbornode.NewCborStore(bs)
oldDeals := map[abi.DealID]*market.DealState{
abi.DealID(1): {
SectorStartEpoch: 1,
LastUpdatedEpoch: 2,
SlashEpoch: 0,
},
abi.DealID(2): {
SectorStartEpoch: 4,
LastUpdatedEpoch: 5,
SlashEpoch: 0,
},
}
oldStateC := createMarketState(ctx, t, store, oldDeals)
newDeals := map[abi.DealID]*market.DealState{
abi.DealID(1): {
SectorStartEpoch: 1,
LastUpdatedEpoch: 3,
SlashEpoch: 0,
},
abi.DealID(2): {
SectorStartEpoch: 4,
LastUpdatedEpoch: 6,
SlashEpoch: 6,
},
}
newStateC := createMarketState(ctx, t, store, newDeals)
miner, err := address.NewFromString("t00")
require.NoError(t, err)
oldState, err := mockTipset(miner, 1)
require.NoError(t, err)
newState, err := mockTipset(miner, 2)
require.NoError(t, err)
api := newMockAPI(bs)
api.setActor(oldState.Key(), &types.Actor{Head: oldStateC})
api.setActor(newState.Key(), &types.Actor{Head: newStateC})
preds := NewStatePredicates(api)
dealIds := []abi.DealID{abi.DealID(1), abi.DealID(2)}
diffFn := preds.OnStorageMarketActorChanged(preds.OnDealStateChanged(preds.DealStateChangedForIDs(dealIds)))
// Diff a state against itself: expect no change
changed, _, err := diffFn(ctx, oldState, oldState)
require.NoError(t, err)
require.False(t, changed)
// Diff old state against new state
changed, val, err := diffFn(ctx, oldState, newState)
require.NoError(t, err)
require.True(t, changed)
changedDeals, ok := val.(ChangedDeals)
require.True(t, ok)
require.Len(t, changedDeals, 2)
require.Contains(t, changedDeals, abi.DealID(1))
require.Contains(t, changedDeals, abi.DealID(2))
deal1 := changedDeals[abi.DealID(1)]
if deal1.From.LastUpdatedEpoch != 2 || deal1.To.LastUpdatedEpoch != 3 {
t.Fatal("Unexpected change to LastUpdatedEpoch")
}
deal2 := changedDeals[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, oldState)
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, *amt.Root, *amt.Root) (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)
}
func mockTipset(miner address.Address, timestamp uint64) (*types.TipSet, error) {
return types.NewTipSet([]*types.BlockHeader{{
Miner: miner,
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) cid.Cid {
rootCid := createAMT(ctx, t, store, deals)
state := createEmptyMarketState(t, store)
state.States = rootCid
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 createAMT(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
}
+5 -5
View File
@@ -8,11 +8,11 @@ import (
"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()
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 {
return false, true, err
}
@@ -22,7 +22,7 @@ func (me *messageEvents) CheckMsg(ctx context.Context, smsg types.ChainMsg, hnd
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 {
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) {
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
+19 -18
View File
@@ -45,10 +45,6 @@ var log = logging.Logger("gen")
const msgsPerBlock = 20
var ValidWpostForTesting = []abi.PoStProof{{
ProofBytes: []byte("valid proof"),
}}
type ChainGen struct {
msgsPerBlock int
@@ -93,8 +89,8 @@ func (m mybs) Get(c cid.Cid) (block.Block, error) {
}
func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
saminer.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
saminer.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
abi.RegisteredProof_StackedDRG2KiBSeal: {},
}
mr := repo.NewMemory(nil)
@@ -108,7 +104,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
return nil, xerrors.Errorf("failed to get metadata datastore: %w", err)
}
bds, err := lr.Datastore("/chain")
bds, err := lr.Datastore("/blocks")
if err != nil {
return nil, xerrors.Errorf("failed to get blocks datastore: %w", err)
}
@@ -145,7 +141,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
return nil, err
}
genm1, k1, err := seed.PreSeal(maddr1, abi.RegisteredSealProof_StackedDrg2KiBV1, 0, numSectors, m1temp, []byte("some randomness"), nil)
genm1, k1, err := seed.PreSeal(maddr1, abi.RegisteredProof_StackedDRG2KiBPoSt, 0, numSectors, m1temp, []byte("some randomness"), nil)
if err != nil {
return nil, err
}
@@ -157,7 +153,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
return nil, err
}
genm2, k2, err := seed.PreSeal(maddr2, abi.RegisteredSealProof_StackedDrg2KiBV1, 0, numSectors, m2temp, []byte("some randomness"), nil)
genm2, k2, err := seed.PreSeal(maddr2, abi.RegisteredProof_StackedDRG2KiBPoSt, 0, numSectors, m2temp, []byte("some randomness"), nil)
if err != nil {
return nil, err
}
@@ -196,7 +192,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
*genm2,
},
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)
@@ -223,10 +219,6 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
miners := []address.Address{maddr1, maddr2}
beac := beacon.NewMockBeacon(time.Second)
//beac, err := drand.NewDrandBeacon(tpl.Timestamp, build.BlockDelaySecs)
//if err != nil {
//return nil, xerrors.Errorf("creating drand beacon: %w", err)
//}
gen := &ChainGen{
bs: bs,
@@ -414,7 +406,7 @@ func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, vrfticke
if cg.Timestamper != nil {
ts = cg.Timestamper(parents, height-parents.Height())
} else {
ts = parents.MinTimestamp() + uint64(height-parents.Height())*build.BlockDelaySecs
ts = parents.MinTimestamp() + uint64((height-parents.Height())*build.BlockDelay)
}
fblk, err := MinerCreateBlock(context.TODO(), cg.sm, cg.w, &api.BlockTemplate{
@@ -435,7 +427,7 @@ func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, vrfticke
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
func (cg *ChainGen) ResyncBankerNonce(ts *types.TipSet) error {
act, err := cg.sm.GetActor(cg.banker, ts)
@@ -537,7 +529,16 @@ func (wpp *wppProvider) GenerateCandidates(ctx context.Context, _ abi.PoStRandom
}
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,
@@ -613,6 +614,6 @@ func (m genFakeVerifier) VerifyWindowPoSt(ctx context.Context, info abi.WindowPo
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")
}
+2 -4
View File
@@ -7,18 +7,16 @@ import (
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/builtin/power"
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
)
func init() {
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
abi.RegisteredProof_StackedDRG2KiBSeal: {},
}
power.ConsensusMinerMinPower = big.NewInt(2048)
verifreg.MinVerifiedDealSize = big.NewInt(256)
}
func testGeneration(t testing.TB, n int, msgs int, sectors int) {
-73
View File
@@ -5,10 +5,8 @@ import (
"encoding/json"
"github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/specs-actors/actors/abi"
"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/verifreg"
"github.com/filecoin-project/specs-actors/actors/runtime"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
@@ -22,7 +20,6 @@ import (
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm"
"github.com/filecoin-project/lotus/genesis"
)
@@ -218,72 +215,9 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
}
}
vregroot, err := address.NewIDAddress(80)
if err != nil {
return nil, err
}
vrst, err := cst.Put(ctx, &account.State{Address: RootVerifierAddr})
if err != nil {
return nil, err
}
err = state.SetActor(vregroot, &types.Actor{
Code: builtin.AccountActorCodeID,
Balance: types.NewInt(0),
Head: vrst,
})
if err != nil {
return nil, xerrors.Errorf("setting account from actmap: %w", err)
}
return state, nil
}
func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot cid.Cid, template genesis.Template) (cid.Cid, error) {
verifNeeds := make(map[address.Address]abi.PaddedPieceSize)
var sum abi.PaddedPieceSize
for _, m := range template.Miners {
for _, s := range m.Sectors {
amt := s.Deal.PieceSize
verifNeeds[s.Deal.Client] += amt
sum += amt
}
}
verifier, err := address.NewIDAddress(80)
if err != nil {
return cid.Undef, err
}
vm, err := vm.NewVM(stateroot, 0, &fakeRand{}, cs.Blockstore(), &fakedSigSyscalls{cs.VMSys()})
if err != nil {
return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err)
}
_, err = doExecValue(ctx, vm, builtin.VerifiedRegistryActorAddr, RootVerifierAddr, types.NewInt(0), builtin.MethodsVerifiedRegistry.AddVerifier, mustEnc(&verifreg.AddVerifierParams{
Address: verifier,
Allowance: abi.NewStoragePower(int64(sum)), // eh, close enough
}))
if err != nil {
return cid.Undef, xerrors.Errorf("failed to failed to create verifier: %w", err)
}
for c, amt := range verifNeeds {
_, err := doExecValue(ctx, vm, builtin.VerifiedRegistryActorAddr, verifier, types.NewInt(0), builtin.MethodsVerifiedRegistry.AddVerifiedClient, mustEnc(&verifreg.AddVerifiedClientParams{
Address: c,
Allowance: abi.NewStoragePower(int64(amt)),
}))
if err != nil {
return cid.Undef, xerrors.Errorf("failed to add verified client: %w", err)
}
}
return vm.Flush(ctx)
}
func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys runtime.Syscalls, template genesis.Template) (*GenesisBootstrap, error) {
st, err := MakeInitialStateTree(ctx, bs, template)
if err != nil {
@@ -297,13 +231,6 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys runtime.Sys
// temp chainstore
cs := store.NewChainStore(bs, datastore.NewMapDatastore(), sys)
// Verify PreSealed Data
stateroot, err = VerifyPreSealedData(ctx, cs, stateroot, template)
if err != nil {
return nil, xerrors.Errorf("failed to verify presealed data: %w", err)
}
stateroot, err = SetupStorageMiners(ctx, cs, stateroot, template.Miners)
if err != nil {
return nil, xerrors.Errorf("setup storage miners failed: %w", err)
+7 -14
View File
@@ -58,8 +58,6 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
for i, m := range miners {
// Create miner through power actor
i := i
m := m
spt, err := ffiwrapper.SealProofTypeFromSectorSize(m.SectorSize)
if err != nil {
@@ -71,7 +69,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
constructorParams := &power.CreateMinerParams{
Owner: m.Worker,
Worker: m.Worker,
Peer: []byte(m.PeerId),
Peer: m.PeerId,
SealProofType: spt,
}
@@ -132,7 +130,6 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
params := &market.PublishStorageDealsParams{}
for _, preseal := range m.Sectors {
preseal.Deal.VerifiedDeal = true
params.Deals = append(params.Deals, market.ClientDealProposal{
Proposal: preseal.Deal,
ClientSignature: crypto.Signature{Type: crypto.SigTypeBLS}, // TODO: do we want to sign these? Or do we want to fake signatures for genesis setup?
@@ -156,7 +153,6 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
// Commit sectors
for pi, preseal := range m.Sectors {
preseal := preseal
// TODO: Maybe check seal (Can just be snark inputs, doesn't go into the genesis file)
// check deals, get dealWeight
@@ -204,12 +200,12 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
{
newSectorInfo := &miner.SectorOnChainInfo{
Info: miner.SectorPreCommitInfo{
SealProof: preseal.ProofType,
SectorNumber: preseal.SectorID,
SealedCID: preseal.CommR,
SealRandEpoch: 0,
DealIDs: []abi.DealID{dealIDs[pi]},
Expiration: preseal.Deal.EndEpoch,
RegisteredProof: preseal.ProofType,
SectorNumber: preseal.SectorID,
SealedCID: preseal.CommR,
SealRandEpoch: 0,
DealIDs: []abi.DealID{dealIDs[pi]},
Expiration: preseal.Deal.EndEpoch,
},
ActivationEpoch: 0,
DealWeight: dealWeight.DealWeight,
@@ -242,9 +238,6 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
st.TotalQualityAdjPower = big.Sub(st.TotalQualityAdjPower, big.NewInt(1))
return nil
})
if err != nil {
return cid.Undef, xerrors.Errorf("mutating state: %w", err)
}
c, err := vm.Flush(ctx)
if err != nil {
-5
View File
@@ -4,7 +4,6 @@ import (
"context"
"encoding/json"
"fmt"
"github.com/filecoin-project/specs-actors/actors/builtin"
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
@@ -46,10 +45,6 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi
}
}
if err := amap.Set(context.TODO(), string(RootVerifierAddr.Bytes()), 80); err != nil {
return nil, err
}
if err := amap.Flush(context.TODO()); err != nil {
return nil, err
}
+6 -21
View File
@@ -2,6 +2,7 @@ package genesis
import (
"context"
"crypto/rand"
"github.com/filecoin-project/go-address"
"github.com/ipfs/go-hamt-ipld"
@@ -14,26 +15,6 @@ import (
"github.com/filecoin-project/lotus/chain/types"
)
var RootVerifierAddr address.Address
var RootVerifierID address.Address
func init() {
k, err := address.NewFromString("t3qfoulel6fy6gn3hjmbhpdpf6fs5aqjb5fkurhtwvgssizq4jey5nw4ptq5up6h7jk7frdvvobv52qzmgjinq")
if err != nil {
panic(err)
}
RootVerifierAddr = k
idk, err := address.NewFromString("t080")
if err != nil {
panic(err)
}
RootVerifierID = idk
}
func SetupVerifiedRegistryActor(bs bstore.Blockstore) (*types.Actor, error) {
cst := cbor.NewCborStore(bs)
@@ -42,7 +23,11 @@ func SetupVerifiedRegistryActor(bs bstore.Blockstore) (*types.Actor, error) {
return nil, err
}
sms := verifreg.ConstructState(h, RootVerifierID)
var r [32]byte // TODO: grab from genesis template
_, _ = rand.Read(r[:])
k, _ := address.NewSecp256k1Address(r[:])
sms := verifreg.ConstructState(h, k)
stcid, err := cst.Put(context.TODO(), sms)
if err != nil {
-11
View File
@@ -150,17 +150,6 @@ func aggregateSignatures(sigs []crypto.Signature) (*crypto.Signature, error) {
}
aggSig := bls.Aggregate(blsSigs)
if aggSig == nil {
if len(sigs) > 0 {
return nil, xerrors.Errorf("bls.Aggregate returned nil with %d signatures", len(sigs))
}
return &crypto.Signature{
Type: crypto.SigTypeBLS,
Data: new(bls.Signature)[:],
}, nil
}
return &crypto.Signature{
Type: crypto.SigTypeBLS,
Data: aggSig[:],
+8 -50
View File
@@ -4,7 +4,6 @@ import (
"bytes"
"context"
"errors"
"fmt"
"math"
"sort"
"sync"
@@ -88,8 +87,6 @@ type MessagePool struct {
localMsgs datastore.Datastore
netName dtypes.NetworkName
sigValCache *lru.TwoQueueCache
}
type msgSet struct {
@@ -183,17 +180,14 @@ func (mpp *mpoolProvider) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error)
func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*MessagePool, error) {
cache, _ := lru.New2Q(build.BlsSignatureCacheSize)
verifcache, _ := lru.New2Q(build.VerifSigCacheSize)
mp := &MessagePool{
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{}),
pending: make(map[address.Address]*msgSet),
minGasPrice: types.NewInt(0),
maxTxPoolSize: 5000,
blsSigCache: cache,
sigValCache: verifcache,
changes: lps.New(50),
localMsgs: namespace.Wrap(ds, datastore.NewKey(localMsgsDs)),
api: api,
@@ -319,6 +313,12 @@ func (mp *MessagePool) Push(m *types.SignedMessage) (cid.Cid, error) {
}
func (mp *MessagePool) Add(m *types.SignedMessage) error {
mp.curTsLk.Lock()
defer mp.curTsLk.Unlock()
return mp.addTs(m, mp.curTs)
}
func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet) error {
// big messages are bad, anti DOS
if m.Size() > 32*1024 {
return xerrors.Errorf("mpool message too large (%dB): %w", m.Size(), ErrMessageTooBig)
@@ -332,53 +332,11 @@ func (mp *MessagePool) Add(m *types.SignedMessage) error {
return ErrMessageValueTooHigh
}
if err := mp.VerifyMsgSig(m); err != nil {
if err := sigs.Verify(&m.Signature, m.Message.From, m.Message.Cid().Bytes()); err != nil {
log.Warnf("mpooladd signature verification failed: %s", err)
return err
}
mp.curTsLk.Lock()
defer mp.curTsLk.Unlock()
return mp.addTs(m, mp.curTs)
}
func sigCacheKey(m *types.SignedMessage) (string, error) {
switch m.Signature.Type {
case crypto.SigTypeBLS:
if len(m.Signature.Data) < 90 {
return "", fmt.Errorf("bls signature too short")
}
return string(m.Cid().Bytes()) + string(m.Signature.Data[64:]), nil
case crypto.SigTypeSecp256k1:
return string(m.Cid().Bytes()), nil
default:
return "", xerrors.Errorf("unrecognized signature type: %d", m.Signature.Type)
}
}
func (mp *MessagePool) VerifyMsgSig(m *types.SignedMessage) error {
sck, err := sigCacheKey(m)
if err != nil {
return err
}
_, ok := mp.sigValCache.Get(sck)
if ok {
// already validated, great
return nil
}
if err := sigs.Verify(&m.Signature, m.Message.From, m.Message.Cid().Bytes()); err != nil {
return err
}
mp.sigValCache.Add(sck, struct{}{})
return nil
}
func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet) error {
snonce, err := mp.getStateNonce(m.Message.From, curTs)
if err != nil {
return xerrors.Errorf("failed to look up actor state nonce: %s: %w", err, ErrBroadcastAnyway)
+17 -17
View File
@@ -16,7 +16,7 @@ import (
"github.com/ipfs/go-datastore"
)
type testMpoolAPI struct {
type testMpoolApi struct {
cb func(rev, app []*types.TipSet) error
bmsgs map[cid.Cid][]*types.SignedMessage
@@ -25,68 +25,68 @@ type testMpoolAPI struct {
tipsets []*types.TipSet
}
func newTestMpoolAPI() *testMpoolAPI {
return &testMpoolAPI{
func newTestMpoolApi() *testMpoolApi {
return &testMpoolApi{
bmsgs: make(map[cid.Cid][]*types.SignedMessage),
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()
if err := tma.cb(nil, []*types.TipSet{mock.TipSet(b)}); err != nil {
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()
if err := tma.cb([]*types.TipSet{mock.TipSet(b)}, nil); err != nil {
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
}
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.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
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
}
func (tma *testMpoolAPI) PubSubPublish(string, []byte) error {
func (tma *testMpoolApi) PubSubPublish(string, []byte) error {
return nil
}
func (tma *testMpoolAPI) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
func (tma *testMpoolApi) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
return &types.Actor{
Nonce: tma.statenonce[addr],
Balance: types.NewInt(90000000),
}, 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 {
return address.Undef, fmt.Errorf("given address was not a key addr")
}
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
}
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 {
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
}
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 {
if types.CidArrsEqual(tsk.Cids(), ts.Cids()) {
return ts, nil
@@ -138,7 +138,7 @@ func mustAdd(t *testing.T, mp *MessagePool, msg *types.SignedMessage) {
}
func TestMessagePool(t *testing.T) {
tma := newTestMpoolAPI()
tma := newTestMpoolApi()
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
if err != nil {
@@ -179,7 +179,7 @@ func TestMessagePool(t *testing.T) {
}
func TestRevertMessages(t *testing.T) {
tma := newTestMpoolAPI()
tma := newTestMpoolApi()
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
if err != nil {
+2 -2
View File
@@ -21,7 +21,7 @@ import (
var log = logging.Logger("statetree")
// StateTree stores actors state by their ID.
// Stores actors state by their ID.
type StateTree struct {
root *hamt.Node
Store cbor.IpldStore
@@ -149,7 +149,7 @@ func (st *StateTree) SetActor(addr address.Address, act *types.Actor) error {
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) {
if addr.Protocol() == address.ID {
return addr, nil
+1 -4
View File
@@ -255,15 +255,12 @@ func TestStateTreeConsistency(t *testing.T) {
}
for i, a := range addrs {
err := st.SetActor(a, &types.Actor{
st.SetActor(a, &types.Actor{
Code: randomCid,
Head: randomCid,
Balance: types.NewInt(uint64(10000 + i)),
Nonce: uint64(1000 - i),
})
if err != nil {
t.Fatalf("while setting actor: %+v", err)
}
}
root, err := st.Flush(context.TODO())
+5 -5
View File
@@ -62,11 +62,11 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate
}
return &api.InvocResult{
Msg: msg,
MsgRct: &ret.MessageReceipt,
ExecutionTrace: ret.ExecutionTrace,
Error: errs,
Duration: ret.Duration,
Msg: msg,
MsgRct: &ret.MessageReceipt,
InternalExecutions: ret.InternalExecutions,
Error: errs,
Duration: ret.Duration,
}, nil
}
+2 -4
View File
@@ -13,7 +13,6 @@ import (
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/builtin/power"
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
"github.com/filecoin-project/specs-actors/actors/runtime"
"github.com/filecoin-project/specs-actors/actors/util/adt"
"golang.org/x/xerrors"
@@ -37,11 +36,10 @@ import (
)
func init() {
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
abi.RegisteredProof_StackedDRG2KiBSeal: {},
}
power.ConsensusMinerMinPower = big.NewInt(2048)
verifreg.MinVerifiedDealSize = big.NewInt(256)
}
const testForkHeight = 40
+21 -51
View File
@@ -121,10 +121,10 @@ func (sm *StateManager) ExecutionTrace(ctx context.Context, ts *types.TipSet) (c
var trace []*api.InvocResult
st, _, err := sm.computeTipSetState(ctx, ts.Blocks(), func(mcid cid.Cid, msg *types.Message, ret *vm.ApplyRet) error {
ir := &api.InvocResult{
Msg: msg,
MsgRct: &ret.MessageReceipt,
ExecutionTrace: ret.ExecutionTrace,
Duration: ret.Duration,
Msg: msg,
MsgRct: &ret.MessageReceipt,
InternalExecutions: ret.InternalExecutions,
Duration: ret.Duration,
}
if ret.ActorErr != nil {
ir.Error = ret.ActorErr.Error()
@@ -184,9 +184,10 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, pstate cid.Cid, bms []B
var err error
params, err := actors.SerializeParams(&reward.AwardBlockRewardParams{
Miner: b.Miner,
Penalty: penalty,
GasReward: gasReward,
Miner: b.Miner,
Penalty: penalty,
GasReward: gasReward,
TicketCount: 1, // TODO: no longer need ticket count here.
})
if err != nil {
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)
}
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 {
@@ -381,8 +382,8 @@ func (sm *StateManager) LoadActorState(ctx context.Context, a address.Address, o
cst := cbor.NewCborStore(sm.cs.Blockstore())
if err := cst.Get(ctx, act.Head, out); err != nil {
var r cbg.Deferred
_ = cst.Get(ctx, act.Head, &r)
log.Errorw("bad actor head", "error", err, "raw", r.Raw, "address", a)
cst.Get(ctx, act.Head, &r)
fmt.Printf("badhead %x\n", r.Raw)
return nil, err
}
@@ -404,8 +405,8 @@ func (sm *StateManager) LoadActorStateRaw(ctx context.Context, a address.Address
return act, nil
}
// ResolveToKeyAddress is similar to `vm.ResolveToKeyAddr` but does not allow `Actor` type of addresses.
// Uses the `TipSet` `ts` to generate the VM state.
// Similar to `vm.ResolveToKeyAddr` but does not allow `Actor` type of addresses. Uses the `TipSet` `ts`
// to generate the VM state.
func (sm *StateManager) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
switch addr.Protocol() {
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
}
// WaitForMessage blocks until a message appears on chain. It looks backwards in the chain to see if this has already
// 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) {
func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid) (*types.TipSet, *types.MessageReceipt, error) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
@@ -530,11 +528,6 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confid
close(backSearchWait)
}()
var candidateTs *types.TipSet
var candidateRcp *types.MessageReceipt
heightOfHead := head[0].Val.Height()
reverts := map[types.TipSetKey]bool{}
for {
select {
case notif, ok := <-tsub:
@@ -544,44 +537,21 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confid
for _, val := range notif {
switch val.Type {
case store.HCRevert:
if val.Val.Equals(candidateTs) {
candidateTs = nil
candidateRcp = nil
}
if backSearchWait != nil {
reverts[val.Val.Key()] = true
}
continue
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())
if err != nil {
return nil, nil, err
}
if r != nil {
if confidence == 0 {
return val.Val, r, err
}
candidateTs = val.Val
candidateRcp = r
return val.Val, r, nil
}
heightOfHead = val.Val.Height()
}
}
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 && !reverts[backTs.Key()] {
// 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
if backTs != nil {
return backTs, backRcp, nil
}
reverts = nil
backSearchWait = nil
case <-ctx.Done():
return nil, nil, ctx.Err()
@@ -640,9 +610,9 @@ func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet
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,
// either way, no reason to lookback, it ain't there
if act.Nonce == 0 || act.Nonce < m.VMMessage().Nonce {
if act.Nonce < m.VMMessage().Nonce {
// nonce on chain is before message nonce we're looking for, its
// not going to be here
return nil, nil, nil
}
+21 -78
View File
@@ -13,7 +13,6 @@ import (
"github.com/filecoin-project/go-address"
amt "github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/go-bitfield"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin"
@@ -139,24 +138,6 @@ func PreCommitInfo(ctx context.Context, sm *StateManager, maddr address.Address,
return *i, nil
}
func MinerSectorInfo(ctx context.Context, sm *StateManager, maddr address.Address, sid abi.SectorNumber, ts *types.TipSet) (*miner.SectorOnChainInfo, error) {
var mas miner.State
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
if err != nil {
return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
}
sectorInfo, ok, err := mas.GetSector(sm.cs.Store(ctx), sid)
if err != nil {
return nil, err
}
if !ok {
return nil, xerrors.New("sector not found")
}
return sectorInfo, nil
}
func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address, filter *abi.BitField, filterOut bool) ([]*api.ChainSectorInfo, error) {
var mas miner.State
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
@@ -174,34 +155,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)
}
cst := cbor.NewCborStore(sm.cs.Blockstore())
var deadlines miner.Deadlines
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)
// TODO: Optimization: we could avoid loaditg the whole proving set here if we had AMT.GetNth with bitfield filtering
sectorSet, err := GetProvingSetRaw(ctx, sm, mas)
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 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 {
if len(sectorSet) == 0 {
return nil, nil
}
@@ -220,34 +180,17 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S
return nil, xerrors.Errorf("getting miner ID: %w", err)
}
ids, err := pv.GenerateWinningPoStSectorChallenge(ctx, wpt, abi.ActorID(mid), rand, numProvSect)
ids, err := pv.GenerateWinningPoStSectorChallenge(ctx, wpt, abi.ActorID(mid), rand, uint64(len(sectorSet)))
if err != nil {
return nil, xerrors.Errorf("generating winning post challenges: %w", err)
}
sectors, err := provingSectors.All(miner.SectorsMax)
if err != nil {
return nil, xerrors.Errorf("failed to enumerate all sector IDs: %w", err)
}
sectorAmt, err := amt.LoadAMT(ctx, cst, mas.Sectors)
if err != nil {
return nil, xerrors.Errorf("failed to load sectors amt: %w", err)
}
out := make([]abi.SectorInfo, len(ids))
for i, n := range ids {
sid := sectors[n]
var sinfo miner.SectorOnChainInfo
if err := sectorAmt.Get(ctx, sid, &sinfo); err != nil {
return nil, xerrors.Errorf("failed to get sector %d: %w", sid, err)
}
out[i] = abi.SectorInfo{
SealProof: spt,
SectorNumber: sinfo.Info.SectorNumber,
SealedCID: sinfo.Info.SealedCID,
RegisteredProof: wpt,
SectorNumber: sectorSet[n].ID,
SealedCID: sectorSet[n].Info.Info.SealedCID,
}
}
@@ -305,27 +248,27 @@ func GetMinerDeadlines(ctx context.Context, sm *StateManager, ts *types.TipSet,
return mas.LoadDeadlines(sm.cs.Store(ctx))
}
func GetMinerFaults(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (*abi.BitField, error) {
func GetMinerFaults(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) ([]abi.SectorNumber, error) {
var mas miner.State
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
if err != nil {
return nil, xerrors.Errorf("(get faults) failed to load miner actor state: %w", err)
return nil, xerrors.Errorf("(get ssize) failed to load miner actor state: %w", err)
}
return mas.Faults, nil
}
func GetMinerRecoveries(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (*abi.BitField, error) {
var mas miner.State
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
faults, err := mas.Faults.All(miner.SectorsMax)
if err != nil {
return nil, xerrors.Errorf("(get recoveries) failed to load miner actor state: %w", err)
return nil, xerrors.Errorf("reading fault bit set: %w", err)
}
return mas.Recoveries, nil
out := make([]abi.SectorNumber, len(faults))
for i, fault := range faults {
out[i] = abi.SectorNumber(fault)
}
return out, 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
if _, err := sm.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil {
return nil, err
@@ -337,7 +280,7 @@ func GetStorageDeal(ctx context.Context, sm *StateManager, dealID abi.DealID, ts
}
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
}
@@ -346,7 +289,7 @@ func GetStorageDeal(ctx context.Context, sm *StateManager, dealID abi.DealID, ts
return nil, err
}
st, found, err := sa.Get(dealID)
st, found, err := sa.Get(dealId)
if err != nil {
return nil, err
}
-3
View File
@@ -32,11 +32,8 @@ func (fts *FullTipSet) Cids() []cid.Cid {
return cids
}
// TipSet returns a narrower view of this FullTipSet elliding the block
// messages.
func (fts *FullTipSet) TipSet() *types.TipSet {
if fts.tipset != nil {
// FIXME: fts.tipset is actually never set. Should it memoize?
return fts.tipset
}
-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())
}
}
+49 -104
View File
@@ -18,6 +18,7 @@ import (
"github.com/filecoin-project/specs-actors/actors/util/adt"
"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/vm"
"github.com/filecoin-project/lotus/metrics"
@@ -47,20 +48,7 @@ import (
var log = logging.Logger("chainstore")
var chainHeadKey = dstore.NewKey("head")
var blockValidationCacheKeyPrefix = dstore.NewKey("blockValidation")
// ReorgNotifee represents a callback that gets called upon reorgs.
type ReorgNotifee func(rev, app []*types.TipSet) error
// ChainStore is the main point of access to chain data.
//
// Raw chain data is stored in the Blockstore, with relevant markers (genesis,
// latest head tipset references) being tracked in the Datastore (key-value
// store).
//
// To alleviate disk access, the ChainStore has two ARC caches:
// 1. a tipset cache
// 2. a block => messages references cache.
type ChainStore struct {
bs bstore.Blockstore
ds dstore.Datastore
@@ -74,10 +62,8 @@ type ChainStore struct {
tstLk sync.Mutex
tipsets map[abi.ChainEpoch][]cid.Cid
cindex *ChainIndex
reorgCh chan<- reorg
reorgNotifeeCh chan ReorgNotifee
reorgCh chan<- reorg
headChangeNotifs []func(rev, app []*types.TipSet) error
mmCache *lru.ARCCache
tsCache *lru.ARCCache
@@ -98,9 +84,7 @@ func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls runtime.Sys
vmcalls: vmcalls,
}
ci := NewChainIndex(cs.LoadTipSet)
cs.cindex = ci
cs.reorgCh = cs.reorgWorker(context.TODO())
hcnf := func(rev, app []*types.TipSet) error {
cs.pubLk.Lock()
@@ -133,8 +117,7 @@ func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls runtime.Sys
return nil
}
cs.reorgNotifeeCh = make(chan ReorgNotifee)
cs.reorgCh = cs.reorgWorker(context.TODO(), []ReorgNotifee{hcnf, hcmetric})
cs.headChangeNotifs = append(cs.headChangeNotifs, hcnf, hcmetric)
return cs
}
@@ -223,24 +206,8 @@ func (cs *ChainStore) SubHeadChanges(ctx context.Context) chan []*api.HeadChange
return out
}
func (cs *ChainStore) SubscribeHeadChanges(f ReorgNotifee) {
cs.reorgNotifeeCh <- f
}
func (cs *ChainStore) IsBlockValidated(ctx context.Context, blkid cid.Cid) (bool, error) {
key := blockValidationCacheKeyPrefix.Instance(blkid.String())
return cs.ds.Has(key)
}
func (cs *ChainStore) MarkBlockAsValidated(ctx context.Context, blkid cid.Cid) error {
key := blockValidationCacheKeyPrefix.Instance(blkid.String())
if err := cs.ds.Put(key, []byte{0}); err != nil {
return xerrors.Errorf("cache block validation: %w", err)
}
return nil
func (cs *ChainStore) SubscribeHeadChanges(f func(rev, app []*types.TipSet) error) {
cs.headChangeNotifs = append(cs.headChangeNotifs, f)
}
func (cs *ChainStore) SetGenesis(b *types.BlockHeader) error {
@@ -275,9 +242,6 @@ func (cs *ChainStore) PutTipSet(ctx context.Context, ts *types.TipSet) error {
return nil
}
// MaybeTakeHeavierTipSet evaluates the incoming tipset and locks it in our
// internal state as our new head, if and only if it is heavier than the current
// head.
func (cs *ChainStore) MaybeTakeHeavierTipSet(ctx context.Context, ts *types.TipSet) error {
cs.heaviestLk.Lock()
defer cs.heaviestLk.Unlock()
@@ -304,19 +268,13 @@ type reorg struct {
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)
notifees := make([]ReorgNotifee, len(initialNotifees))
copy(notifees, initialNotifees)
go func() {
defer log.Warn("reorgWorker quit")
for {
select {
case n := <-cs.reorgNotifeeCh:
notifees = append(notifees, n)
case r := <-out:
revert, apply, err := cs.ReorgOps(r.old, r.new)
if err != nil {
@@ -330,7 +288,7 @@ func (cs *ChainStore) reorgWorker(ctx context.Context, initialNotifees []ReorgNo
apply[i], apply[opp] = apply[opp], apply[i]
}
for _, hcf := range notifees {
for _, hcf := range cs.headChangeNotifs {
if err := hcf(revert, apply); err != nil {
log.Error("head change func errored (BAD): ", err)
}
@@ -343,9 +301,6 @@ func (cs *ChainStore) reorgWorker(ctx context.Context, initialNotifees []ReorgNo
return out
}
// takeHeaviestTipSet actually sets the incoming tipset as our head both in
// memory and in the ChainStore. It also sends a notification to deliver to
// ReorgNotifees.
func (cs *ChainStore) takeHeaviestTipSet(ctx context.Context, ts *types.TipSet) error {
_, span := trace.StartSpan(ctx, "takeHeaviestTipSet")
defer span.End()
@@ -383,7 +338,6 @@ func (cs *ChainStore) SetHead(ts *types.TipSet) error {
return cs.takeHeaviestTipSet(context.TODO(), ts)
}
// Contains returns whether our BlockStore has all blocks in the supplied TipSet.
func (cs *ChainStore) Contains(ts *types.TipSet) (bool, error) {
for _, c := range ts.Cids() {
has, err := cs.bs.Has(c)
@@ -398,8 +352,6 @@ func (cs *ChainStore) Contains(ts *types.TipSet) (bool, error) {
return true, nil
}
// GetBlock fetches a BlockHeader with the supplied CID. It returns
// blockstore.ErrNotFound if the block was not found in the BlockStore.
func (cs *ChainStore) GetBlock(c cid.Cid) (*types.BlockHeader, error) {
sb, err := cs.bs.Get(c)
if err != nil {
@@ -435,7 +387,7 @@ func (cs *ChainStore) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) {
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) {
if b.Height() <= a.Height() {
return false, nil
@@ -492,7 +444,6 @@ func (cs *ChainStore) ReorgOps(a, b *types.TipSet) ([]*types.TipSet, []*types.Ti
return leftChain, rightChain, nil
}
// GetHeaviestTipSet returns the current heaviest tipset known (i.e. our head).
func (cs *ChainStore) GetHeaviestTipSet() *types.TipSet {
cs.heaviestLk.Lock()
defer cs.heaviestLk.Unlock()
@@ -944,50 +895,39 @@ func DrawRandomness(rbase []byte, pers crypto.DomainSeparationTag, round abi.Cha
return nil, xerrors.Errorf("deriving randomness: %w", err)
}
VRFDigest := blake2b.Sum256(rbase)
_, err := h.Write(VRFDigest[:])
if err != nil {
return nil, xerrors.Errorf("hashing VRFDigest: %w", err)
}
h.Write(VRFDigest[:])
if err := binary.Write(h, binary.BigEndian, round); err != nil {
return nil, xerrors.Errorf("deriving randomness: %w", err)
}
_, err = h.Write(entropy)
if err != nil {
return nil, xerrors.Errorf("hashing entropy: %w", err)
}
h.Write(entropy)
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")
defer span.End()
span.AddAttributes(trace.Int64Attribute("round", int64(round)))
ts, err := cs.LoadTipSet(types.NewTipSetKey(blks...))
if err != nil {
return nil, err
//defer func() {
//log.Infof("getRand %v %d %d %x -> %x", blks, pers, round, entropy, out)
//}()
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
@@ -1000,31 +940,35 @@ func (cs *ChainStore) GetTipsetByHeight(ctx context.Context, h abi.ChainEpoch, t
}
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() {
return ts, nil
}
lbts, err := cs.cindex.GetTipsetByHeight(ctx, ts, h)
if err != nil {
return nil, err
if ts.Height()-h > build.ForkLengthThreshold {
log.Warnf("expensive call to GetTipsetByHeight, seeking %d levels", ts.Height()-h)
}
if lbts.Height() < h {
log.Warnf("chain index returned the wrong tipset at height %d, using slow retrieval", h)
lbts, err = cs.cindex.GetTipsetByHeightWithoutCache(ts, h)
for {
pts, err := cs.LoadTipSet(ts.Parents())
if err != nil {
return nil, err
}
}
if lbts.Height() == h || !prev {
return lbts, nil
}
if h > pts.Height() {
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) {
@@ -1204,6 +1148,7 @@ func (cr *chainRand) GetRandomness(ctx context.Context, pers crypto.DomainSepara
func (cs *ChainStore) GetTipSetFromKey(tsk types.TipSetKey) (*types.TipSet, error) {
if tsk.IsEmpty() {
return cs.GetHeaviestTipSet(), nil
} else {
return cs.LoadTipSet(tsk)
}
return cs.LoadTipSet(tsk)
}
+3 -5
View File
@@ -12,7 +12,6 @@ import (
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/builtin/power"
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
"github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/filecoin-project/lotus/chain/gen"
@@ -22,11 +21,10 @@ import (
)
func init() {
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
abi.RegisteredProof_StackedDRG2KiBSeal: {},
}
power.ConsensusMinerMinPower = big.NewInt(2048)
verifreg.MinVerifiedDealSize = big.NewInt(256)
}
func BenchmarkGetRandomness(b *testing.B) {
@@ -55,7 +53,7 @@ func BenchmarkGetRandomness(b *testing.B) {
b.Fatal(err)
}
bds, err := lr.Datastore("/chain")
bds, err := lr.Datastore("/blocks")
if err != nil {
b.Fatal(err)
}
+19 -196
View File
@@ -1,45 +1,30 @@
package sub
import (
"bytes"
"context"
"fmt"
"sync"
"time"
"golang.org/x/xerrors"
address "github.com/filecoin-project/go-address"
amt "github.com/filecoin-project/go-amt-ipld/v2"
miner "github.com/filecoin-project/specs-actors/actors/builtin/miner"
lru "github.com/hashicorp/golang-lru"
"github.com/ipfs/go-cid"
dstore "github.com/ipfs/go-datastore"
bstore "github.com/ipfs/go-ipfs-blockstore"
cbor "github.com/ipfs/go-ipld-cbor"
logging "github.com/ipfs/go-log/v2"
connmgr "github.com/libp2p/go-libp2p-core/connmgr"
"github.com/libp2p/go-libp2p-core/peer"
pubsub "github.com/libp2p/go-libp2p-pubsub"
cbg "github.com/whyrusleeping/cbor-gen"
"go.opencensus.io/stats"
"go.opencensus.io/tag"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain"
"github.com/filecoin-project/lotus/chain/messagepool"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/bufbstore"
"github.com/filecoin-project/lotus/lib/sigs"
"github.com/filecoin-project/lotus/metrics"
)
var log = logging.Logger("sub")
func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *chain.Syncer, cmgr connmgr.ConnManager) {
func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *chain.Syncer, cmgr connmgr.ConnManager, bv *BlockValidator) {
for {
msg, err := bsub.Next(ctx)
if err != nil {
@@ -57,20 +42,25 @@ func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *cha
return
}
src := msg.GetFrom()
//nolint:golint
src := peer.ID(msg.GetFrom())
go func() {
log.Infof("New block over pubsub: %s", blk.Cid())
start := time.Now()
log.Debug("about to fetch messages for block from pubsub")
bmsgs, err := s.Bsync.FetchMessagesByCids(context.TODO(), blk.BlsMessages)
if err != nil {
log.Errorf("failed to fetch all bls messages for block received over pubusb: %s; source: %s", err, src)
log.Errorf("failed to fetch all bls messages for block received over pubusb: %s; flagging source %s", err, src)
bv.flagPeer(src)
return
}
smsgs, err := s.Bsync.FetchSignedMessagesByCids(context.TODO(), blk.SecpkMessages)
if err != nil {
log.Errorf("failed to fetch all secpk messages for block received over pubusb: %s; source: %s", err, src)
log.Errorf("failed to fetch all secpk messages for block received over pubusb: %s; flagging source %s", err, src)
bv.flagPeer(src)
return
}
@@ -99,25 +89,15 @@ type BlockValidator struct {
recvBlocks *blockReceiptCache
blacklist func(peer.ID)
// necessary for block validation
chain *store.ChainStore
stmgr *stmgr.StateManager
mx sync.Mutex
keycache map[string]address.Address
}
func NewBlockValidator(chain *store.ChainStore, stmgr *stmgr.StateManager, blacklist func(peer.ID)) *BlockValidator {
func NewBlockValidator(blacklist func(peer.ID)) *BlockValidator {
p, _ := lru.New2Q(4096)
return &BlockValidator{
peers: p,
killThresh: 10,
blacklist: blacklist,
recvBlocks: newBlockReceiptCache(),
chain: chain,
stmgr: stmgr,
keycache: make(map[string]address.Address),
}
}
@@ -140,190 +120,35 @@ func (bv *BlockValidator) flagPeer(p peer.ID) {
}
func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub.Message) pubsub.ValidationResult {
// track validation time
begin := time.Now()
defer func() {
log.Debugf("block validation time: %s", time.Since(begin))
}()
stats.Record(ctx, metrics.BlockReceived.M(1))
recordFailure := func(what string) {
ctx, _ = tag.New(ctx, tag.Insert(metrics.FailureType, what))
stats.Record(ctx, metrics.BlockValidationFailure.M(1))
bv.flagPeer(pid)
}
// make sure the block can be decoded
blk, err := types.DecodeBlockMsg(msg.GetData())
if err != nil {
log.Error("got invalid block over pubsub: ", err)
recordFailure("invalid")
ctx, _ = tag.New(ctx, tag.Insert(metrics.FailureType, "invalid"))
stats.Record(ctx, metrics.BlockValidationFailure.M(1))
bv.flagPeer(pid)
return pubsub.ValidationReject
}
// check the message limit constraints
if len(blk.BlsMessages)+len(blk.SecpkMessages) > build.BlockMessageLimit {
log.Warnf("received block with too many messages over pubsub")
recordFailure("too_many_messages")
ctx, _ = tag.New(ctx, tag.Insert(metrics.FailureType, "too_many_messages"))
stats.Record(ctx, metrics.BlockValidationFailure.M(1))
bv.flagPeer(pid)
return pubsub.ValidationReject
}
// make sure we have a signature
if blk.Header.BlockSig == nil {
log.Warnf("received block without a signature over pubsub")
recordFailure("missing_signature")
return pubsub.ValidationReject
}
// validate the block meta: the Message CID in the header must match the included messages
err = bv.validateMsgMeta(ctx, blk)
if err != nil {
log.Warnf("error validating message metadata: %s", err)
recordFailure("invalid_block_meta")
return pubsub.ValidationReject
}
// we want to ensure that it is a block from a known miner; we reject blocks from unknown miners
// to prevent spam attacks.
// the logic works as follows: we lookup the miner in the chain for its key.
// if we can find it then it's a known miner and we can validate the signature.
// if we can't find it, we check whether we are (near) synced in the chain.
// if we are not synced we cannot validate the block and we must ignore it.
// if we are synced and the miner is unknown, then the block is rejcected.
key, err := bv.getMinerWorkerKey(ctx, blk)
if err != nil {
if bv.isChainNearSynced() {
log.Warnf("received block message from unknown miner over pubsub; rejecting message")
recordFailure("unknown_miner")
return pubsub.ValidationReject
} else {
log.Warnf("cannot validate block message; unknown miner in unsynced chain")
return pubsub.ValidationIgnore
}
}
err = sigs.CheckBlockSignature(ctx, blk.Header, key)
if err != nil {
log.Errorf("block signature verification failed: %s", err)
recordFailure("signature_verification_failed")
return pubsub.ValidationReject
}
// it's a good block! make sure we've only seen it once
if bv.recvBlocks.add(blk.Header.Cid()) > 0 {
// TODO: once these changes propagate to the network, we can consider
// dropping peers who send us the same block multiple times
return pubsub.ValidationIgnore
}
// all good, accept the block
msg.ValidatorData = blk
stats.Record(ctx, metrics.BlockValidationSuccess.M(1))
return pubsub.ValidationAccept
}
func (bv *BlockValidator) isChainNearSynced() bool {
ts := bv.chain.GetHeaviestTipSet()
timestamp := ts.MinTimestamp()
now := time.Now().UnixNano()
cutoff := uint64(now) - uint64(6*time.Hour)
return timestamp > cutoff
}
func (bv *BlockValidator) validateMsgMeta(ctx context.Context, msg *types.BlockMsg) error {
var bcids, scids []cbg.CBORMarshaler
for _, m := range msg.BlsMessages {
c := cbg.CborCid(m)
bcids = append(bcids, &c)
}
for _, m := range msg.SecpkMessages {
c := cbg.CborCid(m)
scids = append(scids, &c)
}
// TODO there has to be a simpler way to do this without the blockstore dance
bs := cbor.NewCborStore(bstore.NewBlockstore(dstore.NewMapDatastore()))
bmroot, err := amt.FromArray(ctx, bs, bcids)
if err != nil {
return err
}
smroot, err := amt.FromArray(ctx, bs, scids)
if err != nil {
return err
}
mrcid, err := bs.Put(ctx, &types.MsgMeta{
BlsMessages: bmroot,
SecpkMessages: smroot,
})
if err != nil {
return err
}
if msg.Header.Messages != mrcid {
return fmt.Errorf("messages didn't match root cid in header")
}
return nil
}
func (bv *BlockValidator) getMinerWorkerKey(ctx context.Context, msg *types.BlockMsg) (address.Address, error) {
addr := msg.Header.Miner
bv.mx.Lock()
key, ok := bv.keycache[addr.String()]
bv.mx.Unlock()
if ok {
return key, nil
}
// TODO I have a feeling all this can be simplified by cleverer DI to use the API
ts := bv.chain.GetHeaviestTipSet()
st, _, err := bv.stmgr.TipSetState(ctx, ts)
if err != nil {
return address.Undef, err
}
buf := bufbstore.NewBufferedBstore(bv.chain.Blockstore())
cst := cbor.NewCborStore(buf)
state, err := state.LoadStateTree(cst, st)
if err != nil {
return address.Undef, err
}
act, err := state.GetActor(addr)
if err != nil {
return address.Undef, err
}
blk, err := bv.chain.Blockstore().Get(act.Head)
if err != nil {
return address.Undef, err
}
aso := blk.RawData()
var mst miner.State
err = mst.UnmarshalCBOR(bytes.NewReader(aso))
if err != nil {
return address.Undef, err
}
worker := mst.Info.Worker
key, err = bv.stmgr.ResolveToKeyAddress(ctx, worker, ts)
if err != nil {
return address.Undef, err
}
bv.mx.Lock()
bv.keycache[addr.String()] = key
bv.mx.Unlock()
return key, nil
}
type blockReceiptCache struct {
blocks *lru.TwoQueueCache
}
@@ -372,12 +197,10 @@ func (mv *MessageValidator) Validate(ctx context.Context, pid peer.ID, msg *pubs
tag.Insert(metrics.FailureType, "add"),
)
stats.Record(ctx, metrics.MessageValidationFailure.M(1))
switch {
case xerrors.Is(err, messagepool.ErrBroadcastAnyway):
return pubsub.ValidationIgnore
default:
return pubsub.ValidationReject
if xerrors.Is(err, messagepool.ErrBroadcastAnyway) {
return pubsub.ValidationAccept
}
return pubsub.ValidationIgnore
}
stats.Record(ctx, metrics.MessageValidationSuccess.M(1))
return pubsub.ValidationAccept
+79 -214
View File
@@ -8,6 +8,7 @@ import (
"os"
"sort"
"strings"
"sync"
"time"
"github.com/Gurpartap/async"
@@ -30,6 +31,7 @@ import (
amt "github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/power"
"github.com/filecoin-project/specs-actors/actors/crypto"
@@ -49,37 +51,10 @@ import (
"github.com/filecoin-project/lotus/metrics"
)
// Blocks that are more than MaxHeightDrift epochs above
//the theoretical max height based on systime are quickly rejected
const MaxHeightDrift = 5
var log = logging.Logger("chain")
var LocalIncoming = "incoming"
// Syncer is in charge of running the chain synchronization logic. As such, it
// is tasked with these functions, amongst others:
//
// * Fast-forwards the chain as it learns of new TipSets from the network via
// the SyncManager.
// * Applies the fork choice rule to select the correct side when confronted
// with a fork in the network.
// * Requests block headers and messages from other peers when not available
// in our BlockStore.
// * Tracks blocks marked as bad in a cache.
// * Keeps the BlockStore and ChainStore consistent with our view of the world,
// the latter of which in turn informs other components when a reorg has been
// committed.
//
// The Syncer does not run workers itself. It's mainly concerned with
// ensuring a consistent state of chain consensus. The reactive and network-
// interfacing processes are part of other components, such as the SyncManager
// (which owns the sync scheduler and sync workers), BlockSync, the HELLO
// protocol, and the gossipsub block propagation layer.
//
// {hint/concept} The fork-choice rule as it currently stands is: "pick the
// chain with the heaviest weight, so long as it hasnt deviated one finality
// threshold from our head (900 epochs, parameter determined by spec-actors)".
type Syncer struct {
// The interface for accessing and putting tipsets into local storage
store *store.ChainStore
@@ -112,7 +87,6 @@ type Syncer struct {
verifier ffiwrapper.Verifier
}
// NewSyncer creates a new Syncer object.
func NewSyncer(sm *stmgr.StateManager, bsync *blocksync.BlockSync, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*Syncer, error) {
gen, err := sm.ChainStore().GetGenesis()
if err != nil {
@@ -161,11 +135,6 @@ func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
return false
}
if syncer.IsEpochBeyondCurrMax(fts.TipSet().Height()) {
log.Errorf("Received block with impossibly large height %d", fts.TipSet().Height())
return false
}
for _, b := range fts.Blocks {
if reason, ok := syncer.bad.Has(b.Cid()); ok {
log.Warnf("InformNewHead called on block marked as bad: %s (reason: %s)", b.Cid(), reason)
@@ -215,11 +184,6 @@ func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
return true
}
// IncomingBlocks spawns a goroutine that subscribes to the local eventbus to
// receive new block headers as they arrive from the network, and sends them to
// the returned channel.
//
// These blocks have not necessarily been incorporated to our view of the chain.
func (syncer *Syncer) IncomingBlocks(ctx context.Context) (<-chan *types.BlockHeader, error) {
sub := syncer.incoming.Sub(LocalIncoming)
out := make(chan *types.BlockHeader, 10)
@@ -247,15 +211,11 @@ func (syncer *Syncer) IncomingBlocks(ctx context.Context) (<-chan *types.BlockHe
return out, nil
}
// ValidateMsgMeta performs structural and content hash validation of the
// messages within this block. If validation passes, it stores the messages in
// the underlying IPLD block store.
func (syncer *Syncer) ValidateMsgMeta(fblk *types.FullBlock) error {
if msgc := len(fblk.BlsMessages) + len(fblk.SecpkMessages); msgc > build.BlockMessageLimit {
return xerrors.Errorf("block %s has too many messages (%d)", fblk.Header.Cid(), msgc)
}
// Collect the CIDs of both types of messages separately: BLS and Secpk.
var bcids, scids []cbg.CBORMarshaler
for _, m := range fblk.BlsMessages {
c := cbg.CborCid(m.Cid())
@@ -273,14 +233,11 @@ func (syncer *Syncer) ValidateMsgMeta(fblk *types.FullBlock) error {
blockstore := syncer.store.Blockstore()
bs := cbor.NewCborStore(blockstore)
// Compute the root CID of the combined message trie.
smroot, err := computeMsgMeta(bs, bcids, scids)
if err != nil {
return xerrors.Errorf("validating msgmeta, compute failed: %w", err)
}
// Check that the message trie root matches with what's in the block.
if fblk.Header.Messages != smroot {
return xerrors.Errorf("messages in full block did not match msgmeta root in header (%s != %s)", fblk.Header.Messages, smroot)
}
@@ -390,8 +347,6 @@ func zipTipSetAndMessages(bs cbor.IpldStore, ts *types.TipSet, allbmsgs []*types
return fts, nil
}
// computeMsgMeta computes the root CID of the combined arrays of message CIDs
// of both types (BLS and Secpk).
func computeMsgMeta(bs cbor.IpldStore, bmsgCids, smsgCids []cbg.CBORMarshaler) (cid.Cid, error) {
ctx := context.TODO()
bmroot, err := amt.FromArray(ctx, bs, bmsgCids)
@@ -415,24 +370,14 @@ func computeMsgMeta(bs cbor.IpldStore, bmsgCids, smsgCids []cbg.CBORMarshaler) (
return mrcid, nil
}
// FetchTipSet tries to load the provided tipset from the store, and falls back
// to the network (BlockSync) by querying the supplied peer if not found
// locally.
//
// {hint/usage} This is used from the HELLO protocol, to fetch the greeting
// peer's heaviest tipset if we don't have it.
func (syncer *Syncer) FetchTipSet(ctx context.Context, p peer.ID, tsk types.TipSetKey) (*store.FullTipSet, error) {
if fts, err := syncer.tryLoadFullTipSet(tsk); err == nil {
return fts, nil
}
// fall back to the network.
return syncer.Bsync.GetFullTipSet(ctx, p, tsk)
}
// tryLoadFullTipSet queries the tipset in the ChainStore, and returns a full
// representation of it containing FullBlocks. If ALL blocks are not found
// locally, it errors entirely with blockstore.ErrNotFound.
func (syncer *Syncer) tryLoadFullTipSet(tsk types.TipSetKey) (*store.FullTipSet, error) {
ts, err := syncer.store.LoadTipSet(tsk)
if err != nil {
@@ -457,12 +402,6 @@ func (syncer *Syncer) tryLoadFullTipSet(tsk types.TipSetKey) (*store.FullTipSet,
return fts, nil
}
// Sync tries to advance our view of the chain to `maybeHead`. It does nothing
// if our current head is heavier than the requested tipset, or if we're already
// at the requested head, or if the head is the genesis.
//
// Most of the heavy-lifting logic happens in syncer#collectChain. Refer to the
// godocs on that method for a more detailed view.
func (syncer *Syncer) Sync(ctx context.Context, maybeHead *types.TipSet) error {
ctx, span := trace.StartSpan(ctx, "chain.Sync")
defer span.End()
@@ -491,8 +430,6 @@ func (syncer *Syncer) Sync(ctx context.Context, maybeHead *types.TipSet) error {
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 {
span.AddAttributes(trace.StringAttribute("put_error", err.Error()))
span.SetStatus(trace.Status{
@@ -529,27 +466,16 @@ func (syncer *Syncer) ValidateTipSet(ctx context.Context, fts *store.FullTipSet)
return nil
}
var futures []async.ErrorFuture
for _, b := range fts.Blocks {
b := b // rebind to a scoped variable
futures = append(futures, async.Err(func() error {
if err := syncer.ValidateBlock(ctx, b); err != nil {
if isPermanent(err) {
syncer.bad.Add(b.Cid(), err.Error())
}
return xerrors.Errorf("validating block %s: %w", b.Cid(), err)
if err := syncer.ValidateBlock(ctx, b); err != nil {
if isPermanent(err) {
syncer.bad.Add(b.Cid(), err.Error())
}
return xerrors.Errorf("validating block %s: %w", b.Cid(), err)
}
if err := syncer.sm.ChainStore().AddToTipSetTracker(b.Header); err != nil {
return xerrors.Errorf("failed to add validated header to tipset tracker: %w", err)
}
return nil
}))
}
for _, f := range futures {
if err := f.AwaitContext(ctx); err != nil {
return err
if err := syncer.sm.ChainStore().AddToTipSetTracker(b.Header); err != nil {
return xerrors.Errorf("failed to add validated header to tipset tracker: %w", err)
}
}
return nil
@@ -601,36 +527,10 @@ func blockSanityChecks(h *types.BlockHeader) error {
return nil
}
// ValidateBlock should match up with 'Semantical Validation' in validation.md in the spec
func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (err error) {
defer func() {
// b.Cid() could panic for empty blocks that are used in tests.
if rerr := recover(); rerr != nil {
err = xerrors.Errorf("validate block panic: %w", rerr)
return
}
}()
isValidated, err := syncer.store.IsBlockValidated(ctx, b.Cid())
if err != nil {
return xerrors.Errorf("check block validation cache %s: %w", b.Cid(), err)
}
if isValidated {
return nil
}
validationStart := 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)
}()
// Should match up with 'Semantical Validation' in validation.md in the spec
func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) error {
ctx, span := trace.StartSpan(ctx, "validateBlock")
defer span.End()
if build.InsecurePoStValidation {
log.Warn("insecure test validation is enabled, if you see this outside of a test, it is a severe bug!")
}
@@ -666,18 +566,18 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
// fast checks first
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)
}
if h.Timestamp > now {
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())
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 {
@@ -740,7 +640,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
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)
}
@@ -766,7 +666,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
})
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 nil
@@ -801,7 +701,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
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 {
return xerrors.Errorf("validating block tickets failed: %w", err)
}
@@ -849,11 +749,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
}
}
if err := syncer.store.MarkBlockAsValidated(ctx, b.Cid()); err != nil {
return xerrors.Errorf("caching block validation %s: %w", b.Cid(), err)
}
return nil
return merr
}
func (syncer *Syncer) VerifyWinningPoStProof(ctx context.Context, h *types.BlockHeader, prevBeacon types.BeaconEntry, lbst cid.Cid, waddr address.Address) error {
@@ -946,13 +842,44 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
return xerrors.Errorf("failed to load base state tree: %w", err)
}
checkMsg := func(msg types.ChainMsg) error {
m := msg.VMMessage()
checkMsg := func(m *types.Message) error {
// Phase 1: syntactic validation, as defined in the spec
minGas := vm.PricelistByEpoch(baseTs.Height()).OnChainMessage(msg.ChainLength())
if err := m.ValidForBlockInclusion(minGas.Total()); err != nil {
return err
if m.Version != 0 {
return xerrors.New("'Version' unsupported")
}
if m.To == address.Undef {
return xerrors.New("'To' address cannot be empty")
}
if m.From == address.Undef {
return xerrors.New("'From' address cannot be empty")
}
if m.Value.LessThan(big.Zero()) {
return xerrors.New("'Value' field cannot be negative")
}
if m.Value.GreaterThan(types.TotalFilecoinInt) {
return xerrors.New("'Value' field cannot be greater than total filecoin supply")
}
if len(m.Params) != 0 && m.Method == 0 {
return xerrors.New("'Params' field should be empty if no 'Method' is being called")
}
if m.GasPrice.LessThan(big.Zero()) {
return xerrors.New("'GasPrice' field cannot be negative")
}
if m.GasLimit > build.BlockGasLimit {
return xerrors.New("'GasLimit' field cannot be greater than a block's gas limit")
}
// since prices might vary with time, this is technically semantic validation
if m.GasLimit < vm.PricelistByEpoch(baseTs.Height()).OnChainMessage(m.ChainLength()) {
return xerrors.New("'GasLimit' field cannot be less than the cost of storing a message on chain")
}
// Phase 2: (Partial) semantic validation:
@@ -992,7 +919,7 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
var secpkCids []cbg.CBORMarshaler
for i, m := range b.SecpkMessages {
if err := checkMsg(m); err != nil {
if err := checkMsg(&m.Message); err != nil {
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
}
@@ -1043,14 +970,23 @@ func (syncer *Syncer) verifyBlsAggregate(ctx context.Context, sig *crypto.Signat
trace.Int64Attribute("msgCount", int64(len(msgs))),
)
bmsgs := make([]bls.Message, len(msgs))
for i, m := range msgs {
bmsgs[i] = m.Bytes()
var wg sync.WaitGroup
digests := make([]bls.Digest, len(msgs))
for i := 0; i < 10; i++ {
wg.Add(1)
go func(w int) {
defer wg.Done()
for j := 0; (j*10)+w < len(msgs); j++ {
digests[j*10+w] = bls.Hash(bls.Message(msgs[j*10+w].Bytes()))
}
}(i)
}
wg.Wait()
var bsig bls.Signature
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")
}
@@ -1067,39 +1003,6 @@ func extractSyncState(ctx context.Context) *SyncerState {
return nil
}
// collectHeaders collects the headers from the blocks between any two tipsets.
//
// `from` is the heaviest/projected/target tipset we have learned about, and
// `to` 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/naming}: `from` and `to` is in inverse order. `from` is the highest,
// and `to` is the lowest. This method traverses the chain backwards.
//
// {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. Travers 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, from *types.TipSet, to *types.TipSet) ([]*types.TipSet, error) {
ctx, span := trace.StartSpan(ctx, "collectHeaders")
defer span.End()
@@ -1116,8 +1019,6 @@ func (syncer *Syncer) collectHeaders(ctx context.Context, from *types.TipSet, to
}
}
// Check if the parents of the from block are in the denylist.
// i.e. if a fork of the chain has been requested that we know to be bad.
for _, pcid := range from.Parents().Cids() {
if reason, ok := syncer.bad.Has(pcid); ok {
markBad("linked to %s", pcid)
@@ -1188,8 +1089,8 @@ loop:
}
// NB: GetBlocks validates that the blocks are in-fact the ones we
// requested, and that they are correctly linked to one another. It does
// not validate any state transitions.
// requested, and that they are correctly linked to eachother. It does
// not validate any state transitions
window := 500
if gap := int(blockSet[len(blockSet)-1].Height() - untilHeight); gap < window {
window = gap
@@ -1230,6 +1131,7 @@ loop:
at = blks[len(blks)-1].Parents()
}
// We have now ascertained that this is *not* a 'fast forward'
if !types.CidArrsEqual(blockSet[len(blockSet)-1].Parents().Cids(), to.Cids()) {
last := blockSet[len(blockSet)-1]
if last.Parents() == to.Parents() {
@@ -1237,8 +1139,6 @@ loop:
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)
if err != nil {
@@ -1260,12 +1160,6 @@ loop:
var ErrForkTooLong = fmt.Errorf("fork longer than threshold")
// syncFork tries to obtain the chain fragment that links a fork into a common
// ancestor in our view of the chain.
//
// If the fork is too long (build.ForkLengthThreshold), we add the entire subchain to the
// denylist. Else, we find the common ancestor, and add the missing chain
// fragment until the fork point to the returned []TipSet.
func (syncer *Syncer) syncFork(ctx context.Context, from *types.TipSet, to *types.TipSet) ([]*types.TipSet, error) {
tips, err := syncer.Bsync.GetBlocks(ctx, from.Parents(), int(build.ForkLengthThreshold))
if err != nil {
@@ -1417,25 +1311,6 @@ func persistMessages(bs bstore.Blockstore, bst *blocksync.BSTipSet) error {
return nil
}
// collectChain tries to advance our view of the chain to the purported head.
//
// It goes through various stages:
//
// 1. StageHeaders: we proceed in the sync process by requesting block headers
// from our peers, moving back from their heads, until we reach a tipset
// that we have in common (such a common tipset must exist, thought it may
// simply be the genesis block).
//
// If the common tipset is our head, we treat the sync as a "fast-forward",
// else we must drop part of our chain to connect to the peer's head
// (referred to as "forking").
//
// 2. StagePersistHeaders: now that we've collected the missing headers,
// augmented by those on the other side of a fork, we persist them to the
// BlockStore.
//
// 3. StageMessages: having acquired the headers and found a common tipset,
// we then move forward, requesting the full blocks, including the messages.
func (syncer *Syncer) collectChain(ctx context.Context, ts *types.TipSet) error {
ctx, span := trace.StartSpan(ctx, "collectChain")
defer span.End()
@@ -1482,11 +1357,12 @@ func (syncer *Syncer) collectChain(ctx context.Context, ts *types.TipSet) error
return nil
}
func VerifyElectionPoStVRF(ctx context.Context, worker address.Address, rand []byte, evrf []byte) error {
if build.InsecurePoStValidation {
return nil
func VerifyElectionPoStVRF(ctx context.Context, evrf []byte, rand []byte, worker address.Address) error {
if err := gen.VerifyVRF(ctx, worker, rand, evrf); err != nil {
return xerrors.Errorf("failed to verify post_randomness vrf: %w", err)
}
return gen.VerifyVRF(ctx, worker, rand, evrf)
return nil
}
func (syncer *Syncer) State() []SyncerState {
@@ -1497,7 +1373,6 @@ func (syncer *Syncer) State() []SyncerState {
return out
}
// MarkBad manually adds a block to the "bad blocks" cache.
func (syncer *Syncer) MarkBad(blk cid.Cid) {
syncer.bad.Add(blk, "manually marked bad")
}
@@ -1505,7 +1380,7 @@ func (syncer *Syncer) MarkBad(blk cid.Cid) {
func (syncer *Syncer) CheckBadBlockCache(blk cid.Cid) (string, bool) {
return syncer.bad.Has(blk)
}
func (syncer *Syncer) getLatestBeaconEntry(_ context.Context, ts *types.TipSet) (*types.BeaconEntry, error) {
func (syncer *Syncer) getLatestBeaconEntry(ctx context.Context, ts *types.TipSet) (*types.BeaconEntry, error) {
cur := ts
for i := 0; i < 20; i++ {
cbe := cur.Blocks()[0].BeaconEntries
@@ -1526,13 +1401,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")
}
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
// Normally this handler is set to `(*Syncer).Sync()`.
doSync func(context.Context, *types.TipSet) error
stop chan struct{}
@@ -281,7 +280,7 @@ func (sm *SyncManager) syncScheduler() {
}
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 {
sm.setBootstrapState(BSStateScheduled)
sm.syncTargets <- ts
+5 -7
View File
@@ -17,7 +17,6 @@ import (
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/builtin/power"
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
@@ -34,11 +33,10 @@ import (
func init() {
build.InsecurePoStValidation = true
os.Setenv("TRUST_PARAMS", "1")
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
abi.RegisteredProof_StackedDRG2KiBSeal: {},
}
power.ConsensusMinerMinPower = big.NewInt(2048)
verifreg.MinVerifiedDealSize = big.NewInt(256)
}
const source = 0
@@ -408,7 +406,7 @@ func TestSyncBadTimestamp(t *testing.T) {
base := tu.g.CurTipset
tu.g.Timestamper = func(pts *types.TipSet, tl abi.ChainEpoch) uint64 {
return pts.MinTimestamp() + (build.BlockDelaySecs / 2)
return pts.MinTimestamp() + (build.BlockDelay / 2)
}
fmt.Println("BASE: ", base.Cids())
@@ -417,7 +415,7 @@ func TestSyncBadTimestamp(t *testing.T) {
a1 := tu.mineOnBlock(base, 0, nil, false, true)
tu.g.Timestamper = nil
require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet()))
tu.g.ResyncBankerNonce(a1.TipSet())
fmt.Println("After mine bad block!")
tu.printHeads()
@@ -479,7 +477,7 @@ func TestSyncFork(t *testing.T) {
a := tu.mineOnBlock(a1, p1, []int{0}, true, false)
a = tu.mineOnBlock(a, p1, []int{0}, true, false)
require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet()))
tu.g.ResyncBankerNonce(a1.TipSet())
// chain B will now be heaviest
b := tu.mineOnBlock(base, p2, []int{1}, true, false)
b = tu.mineOnBlock(b, p2, []int{1}, true, false)
+1 -1
View File
@@ -76,7 +76,7 @@ func SizeStr(bi BigInt) string {
}
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"}
+1 -24
View File
@@ -3,12 +3,7 @@ package types
import (
"bytes"
"math/big"
"math/rand"
"strings"
"testing"
"time"
"github.com/docker/go-units"
"github.com/stretchr/testify/assert"
)
@@ -65,10 +60,8 @@ func TestSizeStr(t *testing.T) {
}{
{0, "0 B"},
{1, "1 B"},
{1016, "1016 B"},
{1024, "1 KiB"},
{1000 * 1024, "1000 KiB"},
{2000, "1.953 KiB"},
{2000, "1.95 KiB"},
{5 << 20, "5 MiB"},
{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) {
ZiB := big.NewInt(50000)
ZiB = ZiB.Lsh(ZiB, 70)
+4 -15
View File
@@ -69,13 +69,10 @@ type BlockHeader struct {
BlockSig *crypto.Signature // 13
ForkSignaling uint64 // 14
// internal
validated bool // true if the signature has been validated
}
func (blk *BlockHeader) ToStorageBlock() (block.Block, error) {
data, err := blk.Serialize()
func (b *BlockHeader) ToStorageBlock() (block.Block, error) {
data, err := b.Serialize()
if err != nil {
return nil, err
}
@@ -89,8 +86,8 @@ func (blk *BlockHeader) ToStorageBlock() (block.Block, error) {
return block.NewBlockWithCid(data, c)
}
func (blk *BlockHeader) Cid() cid.Cid {
sb, err := blk.ToStorageBlock()
func (b *BlockHeader) Cid() cid.Cid {
sb, err := b.ToStorageBlock()
if err != nil {
panic(err) // Not sure i'm entirely comfortable with this one, needs to be checked
}
@@ -127,14 +124,6 @@ func (blk *BlockHeader) SigningBytes() ([]byte, error) {
return blkcopy.Serialize()
}
func (blk *BlockHeader) SetValidated() {
blk.validated = true
}
func (blk *BlockHeader) IsValidated() bool {
return blk.validated
}
type MsgMeta struct {
BlsMessages cid.Cid
SecpkMessages cid.Cid
+1 -59
View File
@@ -2,17 +2,13 @@ package types
import (
"bytes"
"encoding/hex"
"fmt"
"github.com/stretchr/testify/require"
"reflect"
"testing"
cid "github.com/ipfs/go-cid"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/crypto"
cid "github.com/ipfs/go-cid"
)
func testBlockHeader(t testing.TB) *BlockHeader {
@@ -67,60 +63,6 @@ func TestBlockHeaderSerialization(t *testing.T) {
}
}
func TestInteropBH(t *testing.T) {
newAddr, err := address.NewSecp256k1Address([]byte("address0"))
if err != nil {
t.Fatal(err)
}
mcid, err := cid.Parse("bafy2bzaceaxyj7xq27gc2747adjcirpxx52tt7owqx6z6kckun7tqivvoym4y")
if err != nil {
t.Fatal(err)
}
posts := []abi.PoStProof{
{abi.RegisteredPoStProof_StackedDrgWinning2KiBV1, []byte{0x07}},
}
bh := &BlockHeader{
Miner: newAddr,
Ticket: &Ticket{[]byte{0x01, 0x02, 0x03}},
ElectionProof: &ElectionProof{[]byte{0x0a, 0x0b}},
BeaconEntries: []BeaconEntry{
{
Round: 5,
Data: []byte{0x0c},
//prevRound: 0,
},
},
Height: 2,
Messages: mcid,
ParentMessageReceipts: mcid,
Parents: []cid.Cid{mcid},
ParentWeight: NewInt(1000),
ForkSignaling: 3,
ParentStateRoot: mcid,
Timestamp: 1,
WinPoStProof: posts,
BlockSig: &crypto.Signature{
Type: crypto.SigTypeBLS,
Data: []byte{0x3},
},
BLSAggregate: &crypto.Signature{},
}
bhsb, err := bh.SigningBytes()
if err != nil {
t.Fatal(err)
}
// acquired from go-filecoin
gfc := "8f5501d04cb15021bf6bd003073d79e2238d4e61f1ad22814301020381420a0b818205410c818200410781d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc430003e802d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc410001f603"
require.Equal(t, gfc, hex.EncodeToString(bhsb))
}
func BenchmarkBlockHeaderMarshal(b *testing.B) {
bh := testBlockHeader(b)
+5 -99
View File
@@ -1,103 +1,9 @@
package types
import (
"encoding/json"
"fmt"
"runtime"
"strings"
"time"
)
type ExecutionResult struct {
Msg *Message
MsgRct *MessageReceipt
Error string
type ExecutionTrace struct {
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)
Subcalls []*ExecutionResult
}
+2 -2
View File
@@ -11,7 +11,7 @@ import (
type FIL BigInt
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 {
return "0"
}
@@ -33,7 +33,7 @@ func ParseFIL(s string) (FIL, error) {
return FIL{}, fmt.Errorf("failed to parse %q as a decimal number", s)
}
r = r.Mul(r, big.NewRat(int64(build.FilecoinPrecision), 1))
r = r.Mul(r, big.NewRat(build.FilecoinPrecision, 1))
if !r.IsInt() {
return FIL{}, fmt.Errorf("invalid FIL value: %q", s)
}
+10 -47
View File
@@ -4,13 +4,10 @@ import (
"bytes"
"fmt"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
block "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
"github.com/multiformats/go-multihash"
xerrors "golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
)
@@ -21,7 +18,6 @@ type ChainMsg interface {
Cid() cid.Cid
VMMessage() *Message
ToStorageBlock() (block.Block, error)
// FIXME: This is the *message* length, this name is misleading.
ChainLength() int
}
@@ -42,16 +38,20 @@ type Message struct {
Params []byte
}
func (m *Message) Caller() address.Address {
return m.From
func (t *Message) BlockMiner() address.Address {
panic("implement me")
}
func (m *Message) Receiver() address.Address {
return m.To
func (t *Message) Caller() address.Address {
return t.From
}
func (m *Message) ValueReceived() abi.TokenAmount {
return m.Value
func (t *Message) Receiver() address.Address {
return t.To
}
func (t *Message) ValueReceived() abi.TokenAmount {
return t.Value
}
func DecodeMessage(b []byte) (*Message, error) {
@@ -121,40 +121,3 @@ func (m *Message) VMMessage() *Message {
func (m *Message) Equals(o *Message) bool {
return m.Cid() == o.Cid()
}
func (m *Message) ValidForBlockInclusion(minGas int64) error {
if m.Version != 0 {
return xerrors.New("'Version' unsupported")
}
if m.To == address.Undef {
return xerrors.New("'To' address cannot be empty")
}
if m.From == address.Undef {
return xerrors.New("'From' address cannot be empty")
}
if m.Value.LessThan(big.Zero()) {
return xerrors.New("'Value' field cannot be negative")
}
if m.Value.GreaterThan(TotalFilecoinInt) {
return xerrors.New("'Value' field cannot be greater than total filecoin supply")
}
if m.GasPrice.LessThan(big.Zero()) {
return xerrors.New("'GasPrice' field cannot be negative")
}
if m.GasLimit > build.BlockGasLimit {
return xerrors.New("'GasLimit' field cannot be greater than a block's gas limit")
}
// since prices might vary with time, this is technically semantic validation
if m.GasLimit < minGas {
return xerrors.New("'GasLimit' field cannot be less than the cost of storing a message on chain")
}
return nil
}
+1 -6
View File
@@ -49,11 +49,6 @@ func MkBlock(parents *types.TipSet, weightInc uint64, ticketNonce uint64) *types
panic(err)
}
pstateRoot := c
if parents != nil {
pstateRoot = parents.Blocks()[0].ParentStateRoot
}
var pcids []cid.Cid
var height abi.ChainEpoch
weight := types.NewInt(weightInc)
@@ -77,7 +72,7 @@ func MkBlock(parents *types.TipSet, weightInc uint64, ticketNonce uint64) *types
ParentWeight: weight,
Messages: c,
Height: height,
ParentStateRoot: pstateRoot,
ParentStateRoot: c,
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"
)
func (sm *SignedMessage) ToStorageBlock() (block.Block, error) {
if sm.Signature.Type == crypto.SigTypeBLS {
return sm.Message.ToStorageBlock()
func (m *SignedMessage) ToStorageBlock() (block.Block, error) {
if m.Signature.Type == crypto.SigTypeBLS {
return m.Message.ToStorageBlock()
}
data, err := sm.Serialize()
data, err := m.Serialize()
if err != nil {
return nil, err
}
@@ -28,12 +28,12 @@ func (sm *SignedMessage) ToStorageBlock() (block.Block, error) {
return block.NewBlockWithCid(data, c)
}
func (sm *SignedMessage) Cid() cid.Cid {
if sm.Signature.Type == crypto.SigTypeBLS {
return sm.Message.Cid()
func (m *SignedMessage) Cid() cid.Cid {
if m.Signature.Type == crypto.SigTypeBLS {
return m.Message.Cid()
}
sb, err := sm.ToStorageBlock()
sb, err := m.ToStorageBlock()
if err != nil {
panic(err)
}
+2 -2
View File
@@ -23,6 +23,8 @@ type TipSet struct {
height abi.ChainEpoch
}
// why didnt i just export the fields? Because the struct has methods with the
// same names already
type ExpTipSet struct {
Cids []cid.Cid
Blocks []*BlockHeader
@@ -30,8 +32,6 @@ type ExpTipSet struct {
}
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{
Cids: ts.cids,
Blocks: ts.blks,
+3 -3
View File
@@ -61,9 +61,9 @@ func TestTipSetKey(t *testing.T) {
t.Run("JSON", func(t *testing.T) {
k0 := NewTipSetKey()
verifyJSON(t, "[]", k0)
verifyJson(t, "[]", k0)
k3 := NewTipSetKey(c1, c2, c3)
verifyJSON(t, `[`+
verifyJson(t, `[`+
`{"/":"bafy2bzacecesrkxghscnq7vatble2hqdvwat6ed23vdu4vvo3uuggsoaya7ki"},`+
`{"/":"bafy2bzacebxfyh2fzoxrt6kcgc5dkaodpcstgwxxdizrww225vrhsizsfcg4g"},`+
`{"/":"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)
require.NoError(t, err)
assert.Equal(t, expected, string(bytes))
+5 -6
View File
@@ -9,10 +9,10 @@ import (
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/filecoin-project/specs-actors/actors/puppet"
"github.com/filecoin-project/specs-actors/actors/runtime"
"github.com/ipfs/go-cid"
vtypes "github.com/filecoin-project/chain-validation/chain/types"
vdrivers "github.com/filecoin-project/chain-validation/drivers"
vstate "github.com/filecoin-project/chain-validation/state"
"github.com/filecoin-project/lotus/chain/stmgr"
@@ -24,13 +24,12 @@ import (
// Applier applies messages to state trees and storage.
type Applier struct {
stateWrapper *StateWrapper
syscalls runtime.Syscalls
}
var _ vstate.Applier = &Applier{}
func NewApplier(sw *StateWrapper, syscalls runtime.Syscalls) *Applier {
return &Applier{sw, syscalls}
func NewApplier(sw *StateWrapper) *Applier {
return &Applier{sw}
}
func (a *Applier) ApplyMessage(epoch abi.ChainEpoch, message *vtypes.Message) (vtypes.ApplyMessageResult, error) {
@@ -66,7 +65,7 @@ func (a *Applier) ApplySignedMessage(epoch abi.ChainEpoch, msg *vtypes.SignedMes
}
func (a *Applier) ApplyTipSetMessages(epoch abi.ChainEpoch, blocks []vtypes.BlockMessagesInfo, rnd vstate.RandomnessSource) (vtypes.ApplyTipSetResult, error) {
cs := store.NewChainStore(a.stateWrapper.bs, a.stateWrapper.ds, a.syscalls)
cs := store.NewChainStore(a.stateWrapper.bs, a.stateWrapper.ds, vdrivers.NewChainValidationSyscalls())
sm := stmgr.NewStateManager(cs)
var bms []stmgr.BlockMessages
@@ -135,7 +134,7 @@ func (a *Applier) applyMessage(epoch abi.ChainEpoch, lm types.ChainMsg) (vtypes.
ctx := context.TODO()
base := a.stateWrapper.Root()
lotusVM, err := vm.NewVM(base, epoch, &vmRand{}, a.stateWrapper.bs, a.syscalls)
lotusVM, err := vm.NewVM(base, epoch, &vmRand{}, a.stateWrapper.bs, vdrivers.NewChainValidationSyscalls())
// need to modify the VM invoker to add the puppet actor
chainValInvoker := vm.NewInvoker()
chainValInvoker.Register(puppet.PuppetActorCodeID, puppet.Actor{}, puppet.State{})
+16 -3
View File
@@ -1,9 +1,11 @@
package validation
import (
"github.com/filecoin-project/specs-actors/actors/runtime"
"context"
vstate "github.com/filecoin-project/chain-validation/state"
"github.com/filecoin-project/specs-actors/actors/abi"
acrypto "github.com/filecoin-project/specs-actors/actors/crypto"
)
type Factories struct {
@@ -16,15 +18,26 @@ func NewFactories() *Factories {
return &Factories{}
}
func (f *Factories) NewStateAndApplier(syscalls runtime.Syscalls) (vstate.VMWrapper, vstate.Applier) {
func (f *Factories) NewStateAndApplier() (vstate.VMWrapper, vstate.Applier) {
st := NewState()
return st, NewApplier(st, syscalls)
return st, NewApplier(st)
}
func (f *Factories) NewKeyManager() vstate.KeyManager {
return newKeyManager()
}
type fakeRandSrc struct {
}
func (r fakeRandSrc) Randomness(_ context.Context, _ acrypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) (abi.Randomness, error) {
return abi.Randomness("sausages"), nil
}
func (f *Factories) NewRandomnessSource() vstate.RandomnessSource {
return &fakeRandSrc{}
}
func (f *Factories) NewValidationConfig() vstate.ValidationConfig {
trackGas := true
checkExit := true
+2 -7
View File
@@ -7,7 +7,6 @@ import (
"os"
"github.com/filecoin-project/go-address"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/chain/gen"
"github.com/filecoin-project/lotus/chain/types"
@@ -174,18 +173,14 @@ func WriteJsonToFile(fname string, obj interface{}) error {
if err != nil {
return err
}
defer fi.Close() //nolint:errcheck
defer fi.Close()
out, err := json.MarshalIndent(obj, "", " ")
if err != nil {
return err
}
_, err = fi.Write(out)
if err != nil {
return xerrors.Errorf("writing json: %w", err)
}
fi.Write(out)
return nil
}
+1 -40
View File
@@ -1,15 +1,11 @@
package vectors
import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"os"
"path/filepath"
"testing"
"github.com/filecoin-project/lotus/chain/types"
)
func LoadVector(t *testing.T, f string, out interface{}) {
@@ -46,40 +42,5 @@ func TestBlockHeaderVectors(t *testing.T) {
}
func TestMessageSigningVectors(t *testing.T) {
var msvs []MessageSigningVector
LoadVector(t, "message_signing.json", &msvs)
for i, msv := range msvs {
smsg := &types.SignedMessage{
Message: *msv.Unsigned,
Signature: *msv.Signature,
}
if smsg.Cid().String() != msv.Cid {
t.Fatalf("cid of message in vector %d mismatches", i)
}
// TODO: check signature
}
}
func TestUnsignedMessageVectors(t *testing.T) {
var msvs []UnsignedMessageVector
LoadVector(t, "unsigned_messages.json", &msvs)
for i, msv := range msvs {
b, err := msv.Message.Serialize()
if err != nil {
t.Fatal(err)
}
dec, err := hex.DecodeString(msv.HexCbor)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(b, dec) {
t.Fatalf("serialization vector %d mismatches bytes", i)
}
}
// TODO:
}
+15 -82
View File
@@ -3,7 +3,6 @@ package vm
import (
"fmt"
"github.com/filecoin-project/go-address"
addr "github.com/filecoin-project/go-address"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/crypto"
@@ -12,74 +11,34 @@ import (
"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.
//
// Note: this interface should be APPEND ONLY since last chain checkpoint
type Pricelist interface {
// 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(dataSize int) GasCharge
OnChainReturnValue(dataSize int) int64
// 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(dataSize int) GasCharge
OnIpldGet(dataSize int) int64
// 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() GasCharge
OnCreateActor() int64
// OnDeleteActor returns the gas used for deleting an actor
OnDeleteActor() GasCharge
OnDeleteActor() int64
OnVerifySignature(sigType crypto.SigType, planTextSize int) (GasCharge, error)
OnHashing(dataSize int) GasCharge
OnComputeUnsealedSectorCid(proofType abi.RegisteredSealProof, pieces []abi.PieceInfo) GasCharge
OnVerifySeal(info abi.SealVerifyInfo) GasCharge
OnVerifyPost(info abi.WindowPoStVerifyInfo) GasCharge
OnVerifyConsensusFault() GasCharge
OnVerifySignature(sigType crypto.SigType, planTextSize int) (int64, error)
OnHashing(dataSize int) int64
OnComputeUnsealedSectorCid(proofType abi.RegisteredProof, pieces []abi.PieceInfo) int64
OnVerifySeal(info abi.SealVerifyInfo) int64
OnVerifyPost(info abi.WindowPoStVerifyInfo) int64
OnVerifyConsensusFault() int64
}
var prices = map[abi.ChainEpoch]Pricelist{
@@ -133,7 +92,7 @@ func PricelistByEpoch(epoch abi.ChainEpoch) Pricelist {
type pricedSyscalls struct {
under vmr.Syscalls
pl Pricelist
chargeGas func(GasCharge)
chargeGas func(int64)
}
// Verifies that a signature is valid for an address and plaintext.
@@ -143,40 +102,30 @@ func (ps pricedSyscalls) VerifySignature(signature crypto.Signature, signer addr
return err
}
ps.chargeGas(c)
defer ps.chargeGas(gasOnActorExec)
return ps.under.VerifySignature(signature, signer, plaintext)
}
// Hashes input data using blake2b with 256 bit output.
func (ps pricedSyscalls) HashBlake2b(data []byte) [32]byte {
ps.chargeGas(ps.pl.OnHashing(len(data)))
defer ps.chargeGas(gasOnActorExec)
return ps.under.HashBlake2b(data)
}
// Computes an unsealed sector CID (CommD) from its constituent piece CIDs (CommPs) and sizes.
func (ps pricedSyscalls) ComputeUnsealedSectorCID(reg abi.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))
defer ps.chargeGas(gasOnActorExec)
return ps.under.ComputeUnsealedSectorCID(reg, pieces)
}
// Verifies a sector seal proof.
func (ps pricedSyscalls) VerifySeal(vi abi.SealVerifyInfo) error {
ps.chargeGas(ps.pl.OnVerifySeal(vi))
defer ps.chargeGas(gasOnActorExec)
return ps.under.VerifySeal(vi)
}
// Verifies a proof of spacetime.
func (ps pricedSyscalls) VerifyPoSt(vi abi.WindowPoStVerifyInfo) error {
ps.chargeGas(ps.pl.OnVerifyPost(vi))
defer ps.chargeGas(gasOnActorExec)
return ps.under.VerifyPoSt(vi)
}
@@ -192,21 +141,5 @@ func (ps pricedSyscalls) VerifyPoSt(vi abi.WindowPoStVerifyInfo) error {
// Returns nil and an error if the headers don't prove a fault.
func (ps pricedSyscalls) VerifyConsensusFault(h1 []byte, h2 []byte, extra []byte) (*runtime.ConsensusFault, error) {
ps.chargeGas(ps.pl.OnVerifyConsensusFault())
defer ps.chargeGas(gasOnActorExec)
return ps.under.VerifyConsensusFault(h1, h2, extra)
}
func (ps pricedSyscalls) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) {
var gasChargeSum GasCharge
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)
}
+27 -61
View File
@@ -2,9 +2,7 @@ package vm
import (
"fmt"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/crypto"
)
@@ -86,112 +84,80 @@ type pricelistV0 struct {
var _ Pricelist = (*pricelistV0)(nil)
// OnChainMessage returns the gas used for storing a message of a given size in the chain.
func (pl *pricelistV0) OnChainMessage(msgSize int) GasCharge {
return newGasCharge("OnChainMessage", 0, pl.onChainMessageBase+pl.onChainMessagePerByte*int64(msgSize)).WithVirtual(77302, 0)
func (pl *pricelistV0) OnChainMessage(msgSize int) int64 {
return pl.onChainMessageBase + pl.onChainMessagePerByte*int64(msgSize)
}
// OnChainReturnValue returns the gas used for storing the response of a message in the chain.
func (pl *pricelistV0) OnChainReturnValue(dataSize int) GasCharge {
return newGasCharge("OnChainReturnValue", 0, int64(dataSize)*pl.onChainReturnValuePerByte).WithVirtual(107294, 0)
func (pl *pricelistV0) OnChainReturnValue(dataSize int) int64 {
return int64(dataSize) * pl.onChainReturnValuePerByte
}
// 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
extra := ""
virtGas := int64(1072944)
if value != abi.NewTokenAmount(0) {
// TODO: fix this, it is comparing pointers instead of values
// see vv
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 {
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
func (pl *pricelistV0) OnIpldGet(dataSize int) GasCharge {
return newGasCharge("OnIpldGet", pl.ipldGetBase+int64(dataSize)*pl.ipldGetPerByte, 0).
WithExtra(dataSize).WithVirtual(433685, 0)
func (pl *pricelistV0) OnIpldGet(dataSize int) int64 {
return pl.ipldGetBase + int64(dataSize)*pl.ipldGetPerByte
}
// OnIpldPut returns the gas used for storing an object
func (pl *pricelistV0) OnIpldPut(dataSize int) GasCharge {
return newGasCharge("OnIpldPut", pl.ipldPutBase, int64(dataSize)*pl.ipldPutPerByte).
WithExtra(dataSize).WithVirtual(88970, 0)
func (pl *pricelistV0) OnIpldPut(dataSize int) int64 {
return pl.ipldPutBase + int64(dataSize)*pl.ipldPutPerByte
}
// OnCreateActor returns the gas used for creating an actor
func (pl *pricelistV0) OnCreateActor() GasCharge {
return newGasCharge("OnCreateActor", pl.createActorBase, pl.createActorExtra).WithVirtual(65636, 0)
func (pl *pricelistV0) OnCreateActor() int64 {
return pl.createActorBase + pl.createActorExtra
}
// OnDeleteActor returns the gas used for deleting an actor
func (pl *pricelistV0) OnDeleteActor() GasCharge {
return newGasCharge("OnDeleteActor", 0, pl.deleteActor)
func (pl *pricelistV0) OnDeleteActor() int64 {
return pl.deleteActor
}
// OnVerifySignature
func (pl *pricelistV0) OnVerifySignature(sigType crypto.SigType, planTextSize int) (GasCharge, error) {
func (pl *pricelistV0) OnVerifySignature(sigType crypto.SigType, planTextSize int) (int64, error) {
costFn, ok := pl.verifySignature[sigType]
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()
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
return costFn(int64(planTextSize)), nil
}
// OnHashing
func (pl *pricelistV0) OnHashing(dataSize int) GasCharge {
return newGasCharge("OnHashing", pl.hashingBase+int64(dataSize)*pl.hashingPerByte, 0).WithExtra(dataSize).WithVirtual(77300, 0)
func (pl *pricelistV0) OnHashing(dataSize int) int64 {
return pl.hashingBase + int64(dataSize)*pl.hashingPerByte
}
// 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
return newGasCharge("OnComputeUnsealedSectorCid", pl.computeUnsealedSectorCidBase, 0).WithVirtual(382370, 0)
return pl.computeUnsealedSectorCidBase
}
// 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
return newGasCharge("OnVerifySeal", pl.verifySealBase, 0).WithVirtual(199954003, 0)
return pl.verifySealBase
}
// 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
return newGasCharge("OnVerifyPost", pl.verifyPostBase, 0).WithVirtual(2629471704, 0).WithExtra(len(info.ChallengedSectors))
return pl.verifyPostBase
}
// OnVerifyConsensusFault
func (pl *pricelistV0) OnVerifyConsensusFault() GasCharge {
return newGasCharge("OnVerifyConsensusFault", pl.verifyConsensusFault, 0).WithVirtual(551935, 0)
func (pl *pricelistV0) OnVerifyConsensusFault() int64 {
return pl.verifyConsensusFault
}
+8 -6
View File
@@ -32,7 +32,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors/aerrors"
)
type Invoker struct {
type invoker struct {
builtInCode map[cid.Cid]nativeCode
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 nativeCode []invokeFunc
func NewInvoker() *Invoker {
inv := &Invoker{
func NewInvoker() *invoker {
inv := &invoker{
builtInCode: make(map[cid.Cid]nativeCode),
builtInState: make(map[cid.Cid]reflect.Type),
}
@@ -62,7 +62,7 @@ func NewInvoker() *Invoker {
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]
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)
if err != nil {
panic(xerrors.Errorf("%s: %w", string(c.Hash()), err))
@@ -89,7 +89,9 @@ type Invokee 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)
exports := instance.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) {
inv := Invoker{}
inv := invoker{}
code, err := inv.transform(basicContract{})
assert.NoError(t, err)
+1 -2
View File
@@ -2,7 +2,6 @@ package vm
import (
"context"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin"
@@ -28,7 +27,7 @@ func init() {
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) {
addrID, err := rt.state.RegisterNewAddress(addr)
if err != nil {
+83 -136
View File
@@ -5,9 +5,6 @@ import (
"context"
"encoding/binary"
"fmt"
gruntime "runtime"
"time"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
@@ -52,12 +49,10 @@ type Runtime struct {
origin address.Address
originNonce uint64
executionTrace types.ExecutionTrace
numActorsCreated uint64
allowInternal bool
callerValidated bool
lastGasChargeTime time.Time
lastGasCharge *types.GasTrace
internalExecutions []*types.ExecutionResult
numActorsCreated uint64
allowInternal bool
callerValidated bool
}
func (rt *Runtime) TotalFilCircSupply() abi.TokenAmount {
@@ -110,8 +105,8 @@ type notFoundErr interface {
IsNotFound() bool
}
func (rt *Runtime) Get(c cid.Cid, o vmr.CBORUnmarshaler) bool {
if err := rt.cst.Get(context.TODO(), c, o); err != nil {
func (rs *Runtime) Get(c cid.Cid, o vmr.CBORUnmarshaler) bool {
if err := rs.cst.Get(context.TODO(), c, o); err != nil {
var nfe notFoundErr
if xerrors.As(err, &nfe) && nfe.IsNotFound() {
if xerrors.As(err, new(cbor.SerializationError)) {
@@ -125,8 +120,8 @@ func (rt *Runtime) Get(c cid.Cid, o vmr.CBORUnmarshaler) bool {
return true
}
func (rt *Runtime) Put(x vmr.CBORMarshaler) cid.Cid {
c, err := rt.cst.Put(context.TODO(), x)
func (rs *Runtime) Put(x vmr.CBORMarshaler) cid.Cid {
c, err := rs.cst.Put(context.TODO(), x)
if err != nil {
if xerrors.As(err, new(cbor.SerializationError)) {
panic(aerrors.Newf(exitcode.ErrSerialization, "failed to marshal cbor object %s", err))
@@ -138,11 +133,11 @@ func (rt *Runtime) Put(x vmr.CBORMarshaler) cid.Cid {
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() {
if r := recover(); r != nil {
if ar, ok := r.(aerrors.ActorError); ok {
log.Warnf("VM.Call failure: %+v", ar)
log.Errorf("VM.Call failure: %+v", ar)
aerr = ar
return
}
@@ -153,8 +148,8 @@ func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act
ret := f()
if !rt.callerValidated {
rt.Abortf(exitcode.SysErrorIllegalActor, "Caller MUST be validated during method execution")
if !rs.callerValidated {
rs.Abortf(exitcode.SysErrorIllegalActor, "Caller MUST be validated during method execution")
}
switch ret := ret.(type) {
@@ -175,25 +170,25 @@ func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act
}
}
func (rt *Runtime) Message() vmr.Message {
return rt.vmsg
func (rs *Runtime) Message() vmr.Message {
return rs.vmsg
}
func (rt *Runtime) ValidateImmediateCallerAcceptAny() {
rt.abortIfAlreadyValidated()
func (rs *Runtime) ValidateImmediateCallerAcceptAny() {
rs.abortIfAlreadyValidated()
return
}
func (rt *Runtime) CurrentBalance() abi.TokenAmount {
b, err := rt.GetBalance(rt.Message().Receiver())
func (rs *Runtime) CurrentBalance() abi.TokenAmount {
b, err := rs.GetBalance(rs.Message().Receiver())
if err != nil {
rt.Abortf(err.RetCode(), "get current balance: %v", err)
rs.Abortf(exitcode.ExitCode(err.RetCode()), "get current balance: %v", err)
}
return b
}
func (rt *Runtime) GetActorCodeCID(addr address.Address) (ret cid.Cid, ok bool) {
act, err := rt.state.GetActor(addr)
func (rs *Runtime) GetActorCodeCID(addr address.Address) (ret cid.Cid, ok bool) {
act, err := rs.state.GetActor(addr)
if err != nil {
if xerrors.Is(err, types.ErrActorNotFound) {
return cid.Undef, false
@@ -213,8 +208,8 @@ func (rt *Runtime) GetRandomness(personalization crypto.DomainSeparationTag, ran
return res
}
func (rt *Runtime) Store() vmr.Store {
return rt
func (rs *Runtime) Store() vmr.Store {
return rs
}
func (rt *Runtime) NewActorAddress() address.Address {
@@ -239,12 +234,12 @@ func (rt *Runtime) NewActorAddress() address.Address {
return addr
}
func (rt *Runtime) CreateActor(codeID cid.Cid, address address.Address) {
if !builtin.IsBuiltinActor(codeID) {
func (rt *Runtime) CreateActor(codeId cid.Cid, address address.Address) {
if !builtin.IsBuiltinActor(codeId) {
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.")
}
@@ -253,10 +248,10 @@ func (rt *Runtime) CreateActor(codeID cid.Cid, address address.Address) {
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{
Code: codeID,
Code: codeId,
Head: EmptyObjectCid,
Nonce: 0,
Balance: big.Zero(),
@@ -264,11 +259,10 @@ func (rt *Runtime) CreateActor(codeID cid.Cid, address address.Address) {
if err != nil {
panic(aerrors.Fatalf("creating actor entry: %v", err))
}
_ = rt.chargeGasSafe(gasOnActorExec)
}
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())
if err != nil {
if xerrors.Is(err, types.ErrActorNotFound) {
@@ -277,22 +271,20 @@ func (rt *Runtime) DeleteActor(addr address.Address) {
panic(aerrors.Fatalf("failed to get actor: %s", err))
}
if !act.Balance.IsZero() {
if err := rt.vm.transfer(rt.Message().Receiver(), builtin.BurntFundsActorAddr, act.Balance); err != nil {
panic(aerrors.Fatalf("failed to transfer balance to burnt funds actor: %s", err))
}
rt.vm.transfer(rt.Message().Receiver(), builtin.BurntFundsActorAddr, act.Balance)
}
if err := rt.state.DeleteActor(rt.Message().Receiver()); err != nil {
panic(aerrors.Fatalf("failed to delete actor: %s", err))
}
_ = rt.chargeGasSafe(gasOnActorExec)
}
func (rt *Runtime) Syscalls() vmr.Syscalls {
return rt.sys
func (rs *Runtime) Syscalls() vmr.Syscalls {
// 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")
}
@@ -312,12 +304,12 @@ func (rt *Runtime) Context() context.Context {
return rt.ctx
}
func (rt *Runtime) Abortf(code exitcode.ExitCode, msg string, args ...interface{}) {
log.Warnf("Abortf: " + fmt.Sprintf(msg, args...))
func (rs *Runtime) Abortf(code exitcode.ExitCode, msg string, args ...interface{}) {
log.Error("Abortf: ", fmt.Sprintf(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))
}
@@ -335,8 +327,8 @@ func (rt *Runtime) ValidateImmediateCallerType(ts ...cid.Cid) {
rt.Abortf(exitcode.SysErrForbidden, "caller cid type %q was not one of %v", callerCid, ts)
}
func (rt *Runtime) CurrEpoch() abi.ChainEpoch {
return rt.height
func (rs *Runtime) CurrEpoch() abi.ChainEpoch {
return rs.height
}
type dumbWrapperType struct {
@@ -347,34 +339,31 @@ func (dwt *dumbWrapperType) Into(um vmr.CBORUnmarshaler) error {
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) {
if !rt.allowInternal {
rt.Abortf(exitcode.SysErrorIllegalActor, "runtime.Send() is currently disallowed")
func (rs *Runtime) Send(to address.Address, method abi.MethodNum, m vmr.CBORMarshaler, value abi.TokenAmount) (vmr.SendReturn, exitcode.ExitCode) {
if !rs.allowInternal {
rs.Abortf(exitcode.SysErrorIllegalActor, "runtime.Send() is currently disallowed")
}
var params []byte
if m != nil {
buf := new(bytes.Buffer)
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()
}
ret, err := rt.internalSend(rt.Message().Receiver(), to, method, value, params)
ret, err := rs.internalSend(rs.Message().Receiver(), to, method, types.BigInt(value), params)
if err != nil {
if err.IsFatal() {
panic(err)
}
log.Warnf("vmctx send failed: to: %s, method: %d: ret: %d, err: %s", to, method, ret, err)
return nil, err.RetCode()
return nil, exitcode.ExitCode(err.RetCode())
}
_ = rt.chargeGasSafe(gasOnActorExec)
return &dumbWrapperType{ret}, 0
}
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")
defer span.End()
if span.IsRecordingEvents() {
@@ -400,62 +389,76 @@ func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum,
}
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 errRevert := st.Revert(); errRevert != nil {
return nil, aerrors.Escalate(errRevert, "failed to revert state tree after failed subcall")
}
}
mr := types.MessageReceipt{
ExitCode: exitcode.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 {
er.Subcalls = subrt.internalExecutions
rt.numActorsCreated = subrt.numActorsCreated
}
rt.executionTrace.Subcalls = append(rt.executionTrace.Subcalls, subrt.executionTrace)
rt.internalExecutions = append(rt.internalExecutions, &er)
return ret, errSend
}
func (rt *Runtime) State() vmr.StateHandle {
return &shimStateHandle{rt: rt}
func (rs *Runtime) State() vmr.StateHandle {
return &shimStateHandle{rs: rs}
}
type shimStateHandle struct {
rt *Runtime
rs *Runtime
}
func (ssh *shimStateHandle) Create(obj vmr.CBORMarshaler) {
c := ssh.rt.Put(obj)
// TODO: handle error below
ssh.rt.stateCommit(EmptyObjectCid, c)
c := ssh.rs.Put(obj)
ssh.rs.stateCommit(EmptyObjectCid, c)
}
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 {
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{} {
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 {
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
ssh.rt.Get(baseState, obj)
ssh.rs.Get(baseState, obj)
ssh.rt.allowInternal = false
ssh.rs.allowInternal = false
out := f()
ssh.rt.allowInternal = true
ssh.rs.allowInternal = true
c := ssh.rt.Put(obj)
c := ssh.rs.Put(obj)
// TODO: handle error below
ssh.rt.stateCommit(baseState, c)
ssh.rs.stateCommit(baseState, c)
return out
}
@@ -492,78 +495,22 @@ func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
return nil
}
func (rt *Runtime) finilizeGasTracing() {
if rt.lastGasCharge != nil {
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)
func (rt *Runtime) ChargeGas(toUse int64) {
err := rt.chargeGasSafe(toUse)
if err != nil {
panic(err)
}
}
func (rt *Runtime) chargeGas(gas GasCharge) {
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
func (rt *Runtime) chargeGasSafe(toUse int64) aerrors.ActorError {
if rt.gasUsed+toUse > rt.gasAvailable {
rt.gasUsed = rt.gasAvailable
return aerrors.Newf(exitcode.SysErrOutOfGas, "not enough gas: used=%d, available=%d",
rt.gasUsed, rt.gasAvailable)
return aerrors.Newf(exitcode.SysErrOutOfGas, "not enough gas: used=%d, available=%d", rt.gasUsed, rt.gasAvailable)
}
rt.gasUsed += toUse
return nil
}
func (rt *Runtime) chargeGasSafe(gas GasCharge) aerrors.ActorError {
return rt.chargeGasInternal(gas, 1)
}
func (rt *Runtime) Pricelist() Pricelist {
return rt.pricelist
}
+20 -42
View File
@@ -4,8 +4,6 @@ import (
"bytes"
"context"
"fmt"
goruntime "runtime"
"sync"
"github.com/filecoin-project/go-address"
"github.com/ipfs/go-cid"
@@ -43,7 +41,7 @@ type syscallShim struct {
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
for _, p := range pieces {
sum += p.Size
@@ -115,7 +113,7 @@ func (ss *syscallShim) VerifyConsensusFault(a, b, extra []byte) (*runtime.Consen
// (b) time-offset mining fault
// strictly speaking no need to compare heights based on double fork mining check above,
// 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{
Target: blockA.Miner,
Epoch: blockB.Height,
@@ -159,7 +157,7 @@ func (ss *syscallShim) VerifyConsensusFault(a, b, extra []byte) (*runtime.Consen
}
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
@@ -185,7 +183,7 @@ func (ss *syscallShim) VerifyBlockSig(blk *types.BlockHeader) error {
return err
}
if err := sigs.CheckBlockSignature(ss.ctx, blk, waddr); err != nil {
if err := sigs.CheckBlockSignature(blk, ss.ctx, waddr); err != nil {
return err
}
@@ -203,6 +201,20 @@ func (ss *syscallShim) VerifyPoSt(proof abi.WindowPoStVerifyInfo) error {
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 {
//_, span := trace.StartSpan(ctx, "ValidatePoRep")
//defer span.End()
@@ -213,10 +225,10 @@ func (ss *syscallShim) VerifySeal(info abi.SealVerifyInfo) error {
}
ticket := []byte(info.Randomness)
proof := info.Proof
proof := []byte(info.OnChain.Proof)
seed := []byte(info.InteractiveRandomness)
log.Debugf("Verif r:%x; d:%x; m:%s; t:%x; s:%x; N:%d; p:%x", info.SealedCID, info.UnsealedCID, miner, ticket, seed, info.SectorID.Number, proof)
log.Debugf("Verif r:%x; d:%x; m:%s; t:%x; s:%x; N:%d; p:%x", info.OnChain.SealedCID, info.UnsealedCID, miner, ticket, seed, info.SectorID.Number, proof)
//func(ctx context.Context, maddr address.Address, ssize abi.SectorSize, commD, commR, ticket, proof, seed []byte, sectorID abi.SectorNumber)
ok, err := ss.verifier.VerifySeal(info)
@@ -240,37 +252,3 @@ func (ss *syscallShim) VerifySignature(sig crypto.Signature, addr address.Addres
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) {
out := make(map[address.Address][]bool)
sema := make(chan struct{}, BatchSealVerifyParallelism)
var wg sync.WaitGroup
for addr, seals := range inp {
results := make([]bool, len(seals))
out[addr] = results
for i, s := range seals {
wg.Add(1)
go func(ma address.Address, ix int, svi abi.SealVerifyInfo, res []bool) {
defer wg.Done()
sema <- struct{}{}
if err := ss.VerifySeal(svi); err != nil {
log.Warnw("seal verify in batch failed", "miner", ma, "index", ix, "err", err)
res[ix] = false
} else {
res[ix] = true
}
<-sema
}(addr, i, s, results)
}
}
wg.Wait()
return out, nil
}
-2
View File
@@ -41,7 +41,6 @@ func init() {
func TestChainValidationMessageSuite(t *testing.T) {
f := factory.NewFactories()
for _, testCase := range suites.MessageTestCases() {
testCase := testCase
if TestSuiteSkipper.Skip(testCase) {
continue
}
@@ -54,7 +53,6 @@ func TestChainValidationMessageSuite(t *testing.T) {
func TestChainValidationTipSetSuite(t *testing.T) {
f := factory.NewFactories()
for _, testCase := range suites.TipSetTestCases() {
testCase := testCase
if TestSuiteSkipper.Skip(testCase) {
continue
}
+61 -114
View File
@@ -35,7 +35,6 @@ import (
)
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`.
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)
type gasChargingBlocks struct {
chargeGas func(GasCharge)
chargeGas func(int64)
pricelist Pricelist
under cbor.IpldBlockstore
}
func (bs *gasChargingBlocks) Get(c cid.Cid) (block.Block, error) {
bs.chargeGas(newGasCharge("OnIpldGetStart", 0, 0))
blk, err := bs.under.Get(c)
if err != nil {
return nil, aerrors.Escalate(err, "failed to get block from blockstore")
}
bs.chargeGas(bs.pricelist.OnIpldGet(len(blk.RawData())))
bs.chargeGas(gasOnActorExec)
return blk, nil
}
@@ -86,7 +83,6 @@ func (bs *gasChargingBlocks) Put(blk block.Block) error {
if err := bs.under.Put(blk); err != nil {
return aerrors.Escalate(err, "failed to write data to disk")
}
bs.chargeGas(gasOnActorExec)
return nil
}
@@ -106,16 +102,15 @@ func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, origin addres
pricelist: PricelistByEpoch(vm.blockHeight),
allowInternal: true,
callerValidated: false,
executionTrace: types.ExecutionTrace{Msg: msg},
}
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,
}
rt.sys = pricedSyscalls{
under: vm.Syscalls,
chargeGas: rt.chargeGasFunc(1),
chargeGas: rt.ChargeGas,
pl: rt.pricelist,
}
@@ -136,7 +131,7 @@ type VM struct {
cst *cbor.BasicIpldStore
buf *bufbstore.BufferedBS
blockHeight abi.ChainEpoch
inv *Invoker
inv *invoker
rand Rand
Syscalls runtime.Syscalls
@@ -168,93 +163,63 @@ type Rand interface {
type ApplyRet struct {
types.MessageReceipt
ActorErr aerrors.ActorError
Penalty types.BigInt
ExecutionTrace types.ExecutionTrace
Duration time.Duration
ActorErr aerrors.ActorError
Penalty types.BigInt
InternalExecutions []*types.ExecutionResult
Duration time.Duration
}
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
gasUsed := gasCharge
origin := msg.From
on := msg.Nonce
var nac uint64 = 0
var gasUsed int64
if parent != nil {
gasUsed = parent.gasUsed
gasUsed = parent.gasUsed + gasUsed
origin = parent.origin
on = parent.originNonce
nac = parent.numActorsCreated
}
rt := vm.makeRuntime(ctx, msg, origin, on, gasUsed, nac)
rt.lastGasChargeTime = start
if parent != nil {
rt.lastGasChargeTime = parent.lastGasChargeTime
rt.lastGasCharge = parent.lastGasCharge
defer func() {
parent.gasUsed = rt.gasUsed
parent.lastGasChargeTime = rt.lastGasChargeTime
parent.lastGasCharge = rt.lastGasCharge
}()
}
if gasCharge != nil {
if err := rt.chargeGasSafe(*gasCharge); err != nil {
// this should never happen
return nil, aerrors.Wrap(err, "not enough gas for initial message charge, this should not happen"), rt
}
if aerr := rt.chargeGasSafe(rt.Pricelist().OnMethodInvocation(msg.Value, msg.Method)); aerr != nil {
return nil, aerrors.Wrap(aerr, "not enough gas for method invocation"), rt
}
ret, err := func() ([]byte, aerrors.ActorError) {
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)
toActor, err := st.GetActor(msg.To)
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.Absorb(err, 1, "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 {
@@ -278,18 +243,17 @@ func checkMessage(msg *types.Message) error {
func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*ApplyRet, error) {
start := time.Now()
ret, actorErr, rt := vm.send(ctx, msg, nil, nil, start)
rt.finilizeGasTracing()
ret, actorErr, rt := vm.send(ctx, msg, nil, 0)
return &ApplyRet{
MessageReceipt: types.MessageReceipt{
ExitCode: aerrors.RetCode(actorErr),
ExitCode: exitcode.ExitCode(aerrors.RetCode(actorErr)),
Return: ret,
GasUsed: 0,
},
ActorErr: actorErr,
ExecutionTrace: rt.executionTrace,
Penalty: types.NewInt(0),
Duration: time.Since(start),
ActorErr: actorErr,
InternalExecutions: rt.internalExecutions,
Penalty: types.NewInt(0),
Duration: time.Since(start),
}, actorErr
}
@@ -312,8 +276,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
pl := PricelistByEpoch(vm.blockHeight)
msgGas := pl.OnChainMessage(cmsg.ChainLength())
msgGasCost := msgGas.Total()
msgGasCost := pl.OnChainMessage(cmsg.ChainLength())
// this should never happen, but is currently still exercised by some tests
if msgGasCost > msg.GasLimit {
return &ApplyRet{
@@ -396,7 +359,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
}
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) {
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")
}
rt.finilizeGasTracing()
return &ApplyRet{
MessageReceipt: types.MessageReceipt{
ExitCode: errcode,
ExitCode: exitcode.ExitCode(errcode),
Return: ret,
GasUsed: gasUsed,
},
ActorErr: actorErr,
ExecutionTrace: rt.executionTrace,
Penalty: types.NewInt(0),
Duration: time.Since(start),
ActorErr: actorErr,
InternalExecutions: rt.internalExecutions,
Penalty: types.NewInt(0),
Duration: time.Since(start),
}, nil
}
@@ -493,7 +454,7 @@ func (vm *VM) Flush(ctx context.Context) (cid.Cid, error) {
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 {
act, err := vm.cstate.GetActor(addr)
if err != nil {
@@ -630,7 +591,7 @@ func (vm *VM) Invoke(act *types.Actor, rt *Runtime, method abi.MethodNum, params
return ret, nil
}
func (vm *VM) SetInvoker(i *Invoker) {
func (vm *VM) SetInvoker(i *invoker) {
vm.inv = i
}
@@ -641,50 +602,36 @@ func (vm *VM) incrementNonce(addr address.Address) error {
})
}
func (vm *VM) transfer(from, to address.Address, amt types.BigInt) aerrors.ActorError {
func (vm *VM) transfer(from, to address.Address, amt types.BigInt) error {
if from == to {
return nil
}
fromID, err := vm.cstate.LookupID(from)
if err != nil {
return aerrors.Fatalf("transfer failed when resolving sender address: %s", err)
}
toID, err := vm.cstate.LookupID(to)
if err != nil {
return aerrors.Fatalf("transfer failed when resolving receiver address: %s", err)
}
if fromID == toID {
return nil
}
if amt.LessThan(types.NewInt(0)) {
return aerrors.Newf(exitcode.SysErrForbidden, "attempted to transfer negative value: %s", amt)
return xerrors.Errorf("attempted to transfer negative value")
}
f, err := vm.cstate.GetActor(fromID)
f, err := vm.cstate.GetActor(from)
if err != nil {
return aerrors.Fatalf("transfer failed when retrieving sender actor: %s", err)
return xerrors.Errorf("transfer failed when retrieving sender actor")
}
t, err := vm.cstate.GetActor(toID)
t, err := vm.cstate.GetActor(to)
if err != nil {
return aerrors.Fatalf("transfer failed when retrieving receiver actor: %s", err)
return xerrors.Errorf("transfer failed when retrieving receiver actor")
}
if err := deductFunds(f, amt); err != nil {
return aerrors.Newf(exitcode.SysErrInsufficientFunds, "transfer failed when deducting funds: %s", err)
return err
}
depositFunds(t, amt)
if err := vm.cstate.SetActor(fromID, f); err != nil {
return aerrors.Fatalf("transfer failed when setting receiver actor: %s", err)
if err := vm.cstate.SetActor(from, f); err != nil {
return err
}
if err := vm.cstate.SetActor(toID, t); err != nil {
return aerrors.Fatalf("transfer failed when setting sender actor: %s", err)
if err := vm.cstate.SetActor(to, t); err != nil {
return err
}
return nil
+6 -24
View File
@@ -12,8 +12,8 @@ import (
"github.com/filecoin-project/go-address"
_ "github.com/filecoin-project/lotus/lib/sigs/bls" // enable bls signatures
_ "github.com/filecoin-project/lotus/lib/sigs/secp" // enable secp signatures
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/sigs"
@@ -22,11 +22,10 @@ import (
var log = logging.Logger("wallet")
const (
KNamePrefix = "wallet-"
KTrashPrefix = "trash-"
KDefault = "default"
KTBLS = "bls"
KTSecp256k1 = "secp256k1"
KNamePrefix = "wallet-"
KDefault = "default"
KTBLS = "bls"
KTSecp256k1 = "secp256k1"
)
type Wallet struct {
@@ -231,23 +230,6 @@ func (w *Wallet) HasKey(addr address.Address) (bool, error) {
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 {
types.KeyInfo
+3 -5
View File
@@ -3,10 +3,8 @@ package cli
import (
"fmt"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-jsonrpc/auth"
"gopkg.in/urfave/cli.v2"
"github.com/filecoin-project/lotus/api/apistruct"
"github.com/filecoin-project/lotus/node/repo"
@@ -47,7 +45,7 @@ var authCreateAdminToken = &cli.Command{
perm := cctx.String("perm")
idx := 0
for i, p := range apistruct.AllPermissions {
if auth.Permission(perm) == p {
if perm == p {
idx = i + 1
}
}
@@ -95,7 +93,7 @@ var authApiInfoToken = &cli.Command{
perm := cctx.String("perm")
idx := 0
for i, p := range apistruct.AllPermissions {
if auth.Permission(perm) == p {
if perm == p {
idx = i + 1
}
}
+8 -51
View File
@@ -12,19 +12,19 @@ import (
"strings"
"time"
"github.com/docker/go-units"
"github.com/filecoin-project/go-address"
cborutil "github.com/filecoin-project/go-cbor-util"
"github.com/filecoin-project/specs-actors/actors/abi"
"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/market"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/builtin/power"
"github.com/filecoin-project/specs-actors/actors/util/adt"
cid "github.com/ipfs/go-cid"
"github.com/urfave/cli/v2"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
"gopkg.in/urfave/cli.v2"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors"
@@ -221,9 +221,6 @@ var chainStatObjCmd = &cli.Command{
base := cid.Undef
if cctx.IsSet("base") {
base, err = cid.Decode(cctx.String("base"))
if err != nil {
return err
}
}
stats, err := api.ChainStatObj(ctx, obj, base)
@@ -232,7 +229,7 @@ var chainStatObjCmd = &cli.Command{
}
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
},
}
@@ -444,8 +441,7 @@ var chainGetCmd = &cli.Command{
- /ipfs/[cid]/@Hi:123 - get varint 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]/@A:10 - get 10th amt element
- .../@Ha:t01/@state - get pretty map-based actor state
- /ipfs/[cid]/@A:10 - get 10th amt element
List of --as-type types:
- raw
@@ -525,12 +521,6 @@ var chainGetCmd = &cli.Command{
cbu = new(power.CronEvent)
case "account-state":
cbu = new(account.State)
case "miner-state":
cbu = new(miner.State)
case "power-state":
cbu = new(power.State)
case "market-state":
cbu = new(market.State)
default:
return fmt.Errorf("unknown type: %q", t)
}
@@ -807,12 +797,7 @@ var chainExportCmd = &cli.Command{
if err != nil {
return err
}
defer func() {
err := fi.Close()
if err != nil {
fmt.Printf("error closing output file: %+v", err)
}
}()
defer fi.Close()
ts, err := LoadTipSet(ctx, cctx, api)
if err != nil {
@@ -844,10 +829,6 @@ var slashConsensusFault = &cli.Command{
Name: "miner",
Usage: "Miner address",
},
&cli.StringFlag{
Name: "extra",
Usage: "Extra block cid",
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
@@ -892,34 +873,10 @@ var slashConsensusFault = &cli.Command{
return err
}
params := miner.ReportConsensusFaultParams{
params, err := actors.SerializeParams(&miner.ReportConsensusFaultParams{
BlockHeader1: bh1,
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") == "" {
return xerrors.Errorf("--miner flag is required")
@@ -937,7 +894,7 @@ var slashConsensusFault = &cli.Command{
GasPrice: types.NewInt(1),
GasLimit: 10000000,
Method: builtin.MethodsMiner.ReportConsensusFault,
Params: enc,
Params: params,
}
smsg, err := api.MpoolPushMessage(ctx, msg)
+35 -127
View File
@@ -8,48 +8,19 @@ import (
"text/tabwriter"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-cidutil/cidenc"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/multiformats/go-multibase"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"gopkg.in/urfave/cli.v2"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-fil-markets/storagemarket"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin/market"
"github.com/filecoin-project/lotus/api"
lapi "github.com/filecoin-project/lotus/api"
"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{
Name: "client",
Usage: "Make deals, store data, retrieve data",
@@ -75,7 +46,6 @@ var clientImportCmd = &cli.Command{
Name: "car",
Usage: "import from a car file instead of a regular file",
},
&CidBaseFlag,
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
@@ -97,14 +67,7 @@ var clientImportCmd = &cli.Command{
if err != nil {
return err
}
encoder, err := GetCidEncoder(cctx)
if err != nil {
return err
}
fmt.Println(encoder.Encode(c))
fmt.Println(c.String())
return nil
},
}
@@ -113,9 +76,6 @@ var clientCommPCmd = &cli.Command{
Name: "commP",
Usage: "calculate the piece-cid (commP) of a CAR file",
ArgsUsage: "[inputFile minerAddress]",
Flags: []cli.Flag{
&CidBaseFlag,
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
@@ -134,17 +94,12 @@ var clientCommPCmd = &cli.Command{
}
ret, err := api.ClientCalcCommP(ctx, cctx.Args().Get(0), miner)
if err != nil {
return err
}
encoder, err := GetCidEncoder(cctx)
if err != nil {
return err
}
fmt.Println("CID: ", encoder.Encode(ret.Root))
fmt.Println("Piece size: ", types.SizeStr(types.NewInt(uint64(ret.Size))))
fmt.Println("CID: ", ret.Root)
fmt.Println("Piece size: ", ret.Size)
return nil
},
}
@@ -182,9 +137,6 @@ var clientCarGenCmd = &cli.Command{
var clientLocalCmd = &cli.Command{
Name: "local",
Usage: "List locally imported data",
Flags: []cli.Flag{
&CidBaseFlag,
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
@@ -197,14 +149,8 @@ var clientLocalCmd = &cli.Command{
if err != nil {
return err
}
encoder, err := GetCidEncoder(cctx)
if err != nil {
return err
}
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
},
@@ -232,7 +178,6 @@ var clientDealCmd = &cli.Command{
Usage: "specify the epoch that the deal should start at",
Value: -1,
},
&CidBaseFlag,
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
@@ -318,13 +263,7 @@ var clientDealCmd = &cli.Command{
return err
}
encoder, err := GetCidEncoder(cctx)
if err != nil {
return err
}
fmt.Println(encoder.Encode(*proposal))
fmt.Println(proposal)
return nil
},
}
@@ -372,7 +311,7 @@ var clientFindCmd = &cli.Command{
fmt.Printf("ERR %s@%s: %s\n", offer.Miner, offer.MinerPeerID, offer.Err)
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
@@ -392,10 +331,6 @@ var clientRetrieveCmd = &cli.Command{
Name: "car",
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 {
if cctx.NArg() != 2 {
@@ -403,7 +338,7 @@ var clientRetrieveCmd = &cli.Command{
return nil
}
fapi, closer, err := GetFullNodeAPI(cctx)
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
@@ -414,7 +349,7 @@ var clientRetrieveCmd = &cli.Command{
if cctx.String("address") != "" {
payer, err = address.NewFromString(cctx.String("address"))
} else {
payer, err = fapi.WalletDefaultAddress(ctx)
payer, err = api.WalletDefaultAddress(ctx)
}
if err != nil {
return err
@@ -437,39 +372,23 @@ var clientRetrieveCmd = &cli.Command{
return nil
}*/ // TODO: fix
var offer api.QueryOffer
minerStrAddr := cctx.String("miner")
if minerStrAddr == "" { // Local discovery
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)
offers, err := api.ClientFindData(ctx, file)
if err != nil {
return err
}
ref := &lapi.FileRef{
// 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{
Path: cctx.Args().Get(1),
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)
}
@@ -527,11 +446,11 @@ var clientQueryAskCmd = &cli.Command{
return xerrors.Errorf("failed to get peerID for miner: %w", err)
}
if peer.ID(mi.PeerId) == peer.ID("SETME") {
if mi.PeerId == peer.ID("SETME") {
return fmt.Errorf("the miner hasn't initialized yet")
}
pid = peer.ID(mi.PeerId)
pid = mi.PeerId
}
ask, err := api.ClientQueryAsk(ctx, pid, maddr)
@@ -541,7 +460,7 @@ var clientQueryAskCmd = &cli.Command{
fmt.Printf("Ask: %s\n", maddr)
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")
if size == 0 {
@@ -582,27 +501,16 @@ var clientListDeals = &cli.Command{
}
var deals []deal
for _, v := range localDeals {
if v.DealID == 0 {
deals = append(deals, deal{
LocalDeal: v,
OnChainDealState: market.DealState{
SectorStartEpoch: -1,
LastUpdatedEpoch: -1,
SlashEpoch: -1,
},
})
} else {
onChain, err := api.StateMarketStorageDeal(ctx, v.DealID, head.Key())
if err != nil {
return err
}
deals = append(deals, deal{
LocalDeal: v,
OnChainDealState: onChain.State,
})
for idx := range localDeals {
onChain, err := api.StateMarketStorageDeal(ctx, localDeals[idx].DealID, head.Key())
if err != nil {
return err
}
deals = append(deals, deal{
LocalDeal: localDeals[idx],
OnChainDealState: onChain.State,
})
}
w := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0)
@@ -618,7 +526,7 @@ var clientListDeals = &cli.Command{
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()
},
+19 -25
View File
@@ -13,13 +13,12 @@ import (
"github.com/mitchellh/go-homedir"
"github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr-net"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-jsonrpc"
"gopkg.in/urfave/cli.v2"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/client"
"github.com/filecoin-project/lotus/lib/jsonrpc"
"github.com/filecoin-project/lotus/node/repo"
)
@@ -211,33 +210,28 @@ func ReqContext(cctx *cli.Context) context.Context {
}
var CommonCommands = []*cli.Command{
netCmd,
authCmd,
fetchParamCmd,
netCmd,
versionCmd,
logCmd,
waitApiCmd,
fetchParamCmd,
versionCmd,
}
var Commands = []*cli.Command{
withCategory("basic", sendCmd),
withCategory("basic", walletCmd),
withCategory("basic", clientCmd),
withCategory("basic", multisigCmd),
withCategory("basic", paychCmd),
withCategory("developer", authCmd),
withCategory("developer", mpoolCmd),
withCategory("developer", stateCmd),
withCategory("developer", chainCmd),
withCategory("developer", logCmd),
withCategory("developer", waitApiCmd),
withCategory("developer", fetchParamCmd),
withCategory("network", netCmd),
withCategory("network", syncCmd),
authCmd,
chainCmd,
clientCmd,
fetchParamCmd,
mpoolCmd,
multisigCmd,
netCmd,
paychCmd,
sendCmd,
stateCmd,
syncCmd,
versionCmd,
}
func withCategory(cat string, cmd *cli.Command) *cli.Command {
cmd.Category = cat
return cmd
walletCmd,
logCmd,
waitApiCmd,
}
+1 -1
View File
@@ -3,8 +3,8 @@ package cli
import (
"fmt"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"gopkg.in/urfave/cli.v2"
)
var logCmd = &cli.Command{

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