Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4121063ca4 | ||
|
|
aa081dbc6d | ||
|
|
984eee8cd6 | ||
|
|
26bbd9fb9d | ||
|
|
57c1eac37a | ||
|
|
8419dda84b | ||
|
|
dcc5643473 | ||
|
|
1a101e53a6 | ||
|
|
a894c1e8e6 | ||
|
|
b85b50afbc | ||
|
|
97064f1d15 | ||
|
|
f56602c588 | ||
|
|
c66ebc50c1 | ||
|
|
2aef7f7c07 | ||
|
|
665d23cb8e | ||
|
|
3b00c6838a | ||
|
|
a6b7791d32 | ||
|
|
34d31d8124 | ||
|
|
6656e5a6c8 | ||
|
|
487765548e | ||
|
|
ecd115c002 | ||
|
|
5a8ee0dd2a | ||
|
|
4fbb322fa2 | ||
|
|
56f223bfc3 | ||
|
|
0ff5a71114 | ||
|
|
b0677ab38e | ||
|
|
f4f80b25d1 | ||
|
|
3f67c4524e | ||
|
|
b4115021c5 | ||
|
|
b78ffd18c6 | ||
|
|
c9a8f3b8a0 | ||
|
|
d870c74a5e | ||
|
|
3d61a37fcf | ||
|
|
0c41522ebf | ||
|
|
362fc180ec | ||
|
|
2db7b8c998 | ||
|
|
e04331b07c | ||
|
|
808051d34e | ||
|
|
e2cf0c4d4c | ||
|
|
5c69249ba3 | ||
|
|
fa9be9a627 | ||
|
|
937ff4e9ae | ||
|
|
952f2c2f1e | ||
|
|
ed4caac9bf | ||
|
|
0c1c19c6ef | ||
|
|
24756ac056 | ||
|
|
d4a7732d0a | ||
|
|
ae326ce65d | ||
|
|
531b7bf92d | ||
|
|
84fa22110f | ||
|
|
e22aa74865 | ||
|
|
285fc69f6a | ||
|
|
72216fe917 | ||
|
|
692027f625 | ||
|
|
801e01bca0 | ||
|
|
6665a9ca69 | ||
|
|
1c02a417db | ||
|
|
9ec26e776d | ||
|
|
cf82483420 | ||
|
|
db998e9c0f | ||
|
|
f0f15f899c | ||
|
|
7dc091052a | ||
|
|
17e44af542 | ||
|
|
ac8ef29d35 | ||
|
|
48e47ddc23 | ||
|
|
6acd3d6028 | ||
|
|
7fd5c81674 | ||
|
|
f9ea3935ff | ||
|
|
9804310cc8 | ||
|
|
07e574db44 | ||
|
|
dd841f32db | ||
|
|
665f93bbb7 | ||
|
|
32eeb96ce7 | ||
|
|
172bfacae0 | ||
|
|
0a5494dd79 | ||
|
|
044202b37f | ||
|
|
d68ec37942 | ||
|
|
0edcae9e04 | ||
|
|
d1850ea27d | ||
|
|
60a031a713 | ||
|
|
8a05fe86d6 | ||
|
|
8a21198f56 | ||
|
|
b212368a70 | ||
|
|
954ff32503 | ||
|
|
7c13fa95d1 | ||
|
|
09e9d6d778 | ||
|
|
86607452d7 | ||
|
|
05aa5f2d38 | ||
|
|
6d29d75724 | ||
|
|
3a34856dfe | ||
|
|
973738d30f | ||
|
|
747b34c2c8 | ||
|
|
dcae513487 | ||
|
|
18c025f10e | ||
|
|
e45a7749b0 | ||
|
|
b7ea145f38 | ||
|
|
6c61ff0e9e | ||
|
|
45a5eaf913 | ||
|
|
3401cb349b | ||
|
|
8b9a3ea6c3 | ||
|
|
d5aef296ea | ||
|
|
aa83a4c1f5 | ||
|
|
b83463ca76 | ||
|
|
c1ca24e8bc | ||
|
|
b78fe0b898 | ||
|
|
bf1036c78f | ||
|
|
2e3ff9e401 | ||
|
|
eabdf74946 | ||
|
|
cf9820137c | ||
|
|
c017d0fbaf | ||
|
|
16f7d5801b | ||
|
|
62b2963781 | ||
|
|
cd9858420f | ||
|
|
4410da98be | ||
|
|
b89aa02d77 | ||
|
|
3dfb3e641b | ||
|
|
a3f228d05a | ||
|
|
eaf9ebc2ca | ||
|
|
55e4183825 | ||
|
|
aeb3437a9f | ||
|
|
6e7de3c8d9 | ||
|
|
d0175392c0 | ||
|
|
c4b3970c70 | ||
|
|
72eb17d314 | ||
|
|
0efe5ee7d5 | ||
|
|
0e3dd3cb3b | ||
|
|
56b237e7b8 | ||
|
|
2865a0367b | ||
|
|
232cc320bd | ||
|
|
e7edc46daf | ||
|
|
6813ab4e65 | ||
|
|
fd714cbceb | ||
|
|
db6bd890d9 | ||
|
|
7a46c5ff31 | ||
|
|
98a9042c07 | ||
|
|
4170e18dea | ||
|
|
230ef2484d | ||
|
|
beba92aed4 | ||
|
|
cbb693e99e | ||
|
|
774e068436 | ||
|
|
86ba21029d | ||
|
|
316ac61875 | ||
|
|
d5d264d13b | ||
|
|
c71e1adc93 | ||
|
|
564d0ae974 | ||
|
|
9a48ec194e | ||
|
|
bb0a7f91cc | ||
|
|
73e54352cd | ||
|
|
64fa6fd9e5 | ||
|
|
2d3f92aeed | ||
|
|
df5750a21c | ||
|
|
e996a5246b | ||
|
|
bbac86f745 | ||
|
|
22556fb24c | ||
|
|
2374cb1bc5 | ||
|
|
c7b0241a48 | ||
|
|
dc85a276cd | ||
|
|
9e9856bb45 | ||
|
|
890e6280df | ||
|
|
c94ff3430c | ||
|
|
da7e4b3a09 | ||
|
|
a214069586 | ||
|
|
d4b185be5e | ||
|
|
747a7de168 | ||
|
|
bfa47b3663 | ||
|
|
0e7f14159a | ||
|
|
b755ce9528 | ||
|
|
f3cae55bd4 | ||
|
|
f64bd55bc6 | ||
|
|
4c8bb846ea | ||
|
|
bd14fb90fc | ||
|
|
9e5bce90f4 | ||
|
|
72c7d4c886 | ||
|
|
558b637b07 | ||
|
|
767341b279 | ||
|
|
5e7737f55d | ||
|
|
c73916b4e7 | ||
|
|
0361ca1c39 | ||
|
|
cd4cd22928 | ||
|
|
e1a0cf6ca5 | ||
|
|
73bb9d5afb | ||
|
|
183df4c135 | ||
|
|
f2b238f50a | ||
|
|
09194aa613 | ||
|
|
e58327d4ed | ||
|
|
8414aa6e4b | ||
|
|
7d1d690eb7 | ||
|
|
47ad7ccb5f | ||
|
|
679c4183e7 | ||
|
|
8807c75c51 | ||
|
|
be9d8f7ce3 | ||
|
|
a7a43a1124 | ||
|
|
7a6ceebb34 | ||
|
|
38863d3025 | ||
|
|
88c04ce959 | ||
|
|
5ead23a8d4 | ||
|
|
d0ccb54aba | ||
|
|
aaad01105e | ||
|
|
35a8f7ebca | ||
|
|
0a4c473a7c | ||
|
|
1ec534d607 | ||
|
|
905168e72e | ||
|
|
d46f684bb8 | ||
|
|
97ff90f8fa | ||
|
|
4554c4bda9 | ||
|
|
3206f92063 | ||
|
|
fd04a19544 | ||
|
|
f046af337a | ||
|
|
ac152abc75 | ||
|
|
0b6a182a44 | ||
|
|
cb8e105a94 | ||
|
|
efdfd3ee3e | ||
|
|
4e1ef09751 | ||
|
|
cc859d3948 | ||
|
|
200b0f72cc | ||
|
|
8f19fff1ec | ||
|
|
b534ab9d3c | ||
|
|
2ea5abdfb5 | ||
|
|
d53c6f2599 | ||
|
|
5e2c28d7e9 | ||
|
|
bca516b028 | ||
|
|
92598237c3 | ||
|
|
5074ce5a38 | ||
|
|
b8475114ba | ||
|
|
443473f833 | ||
|
|
4e82cf369c | ||
|
|
d547c2588c | ||
|
|
cb8e209f78 | ||
|
|
3bd9d55a15 | ||
|
|
d6e6eedd58 | ||
|
|
7459ec6bba | ||
|
|
226786c1da | ||
|
|
4d2d8b2d11 | ||
|
|
becbff0b13 | ||
|
|
4bcf01938c | ||
|
|
bef7d64e66 | ||
|
|
695f6cfe45 |
+24
-3
@@ -231,11 +231,11 @@ jobs:
|
||||
- run:
|
||||
name: install statediff globally
|
||||
command: |
|
||||
## statediff is optional; we succeed even if compilation fails.
|
||||
mkdir -p /tmp/statediff
|
||||
git clone https://github.com/filecoin-project/statediff.git /tmp/statediff
|
||||
cd /tmp/statediff
|
||||
go generate ./...
|
||||
go install ./cmd/statediff
|
||||
go install ./cmd/statediff || exit 0
|
||||
- run:
|
||||
name: go test
|
||||
environment:
|
||||
@@ -254,6 +254,25 @@ jobs:
|
||||
path: /tmp/test-reports
|
||||
- store_artifacts:
|
||||
path: /tmp/test-artifacts/conformance-coverage.html
|
||||
build-lotus-soup:
|
||||
description: |
|
||||
Compile `lotus-soup` Testground test plan using the current version of Lotus.
|
||||
parameters:
|
||||
<<: *test-params
|
||||
executor: << parameters.executor >>
|
||||
steps:
|
||||
- install-deps
|
||||
- prepare
|
||||
- run: cd extern/oni && git submodule sync
|
||||
- run: cd extern/oni && git submodule update --init
|
||||
- run: cd extern/filecoin-ffi && make
|
||||
- run:
|
||||
name: "replace lotus, filecoin-ffi, blst and fil-blst deps"
|
||||
command: cd extern/oni/lotus-soup && go mod edit -replace github.com/filecoin-project/lotus=../../../ && go mod edit -replace github.com/filecoin-project/filecoin-ffi=../../filecoin-ffi && go mod edit -replace github.com/supranational/blst=../../fil-blst/blst && go mod edit -replace github.com/filecoin-project/fil-blst=../../fil-blst
|
||||
- run:
|
||||
name: "build lotus-soup testplan"
|
||||
command: pushd extern/oni/lotus-soup && go build -tags=testground .
|
||||
|
||||
|
||||
build-macos:
|
||||
description: build darwin lotus binary
|
||||
@@ -400,7 +419,8 @@ workflows:
|
||||
version: 2.1
|
||||
ci:
|
||||
jobs:
|
||||
- lint-all
|
||||
- lint-all:
|
||||
concurrency: "16" # expend all docker 2xlarge CPUs.
|
||||
- mod-tidy-check
|
||||
- gofmt
|
||||
- cbor-gen-check
|
||||
@@ -427,6 +447,7 @@ workflows:
|
||||
test-suite-name: conformance-bleeding-edge
|
||||
packages: "./conformance"
|
||||
vectors-branch: master
|
||||
- build-lotus-soup
|
||||
- build-debug
|
||||
- build-all:
|
||||
requires:
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
/lotus-fountain
|
||||
/lotus-stats
|
||||
/lotus-bench
|
||||
/lotus-gateway
|
||||
/lotus-pcr
|
||||
/bench.json
|
||||
/lotuspond/front/node_modules
|
||||
/lotuspond/front/build
|
||||
|
||||
@@ -8,3 +8,9 @@
|
||||
[submodule "extern/test-vectors"]
|
||||
path = extern/test-vectors
|
||||
url = https://github.com/filecoin-project/test-vectors.git
|
||||
[submodule "extern/fil-blst"]
|
||||
path = extern/fil-blst
|
||||
url = https://github.com/filecoin-project/fil-blst.git
|
||||
[submodule "extern/oni"]
|
||||
path = extern/oni
|
||||
url = https://github.com/filecoin-project/oni
|
||||
|
||||
+79
-1
@@ -1,5 +1,84 @@
|
||||
# Lotus changelog
|
||||
|
||||
# 0.7.1 / 2020-09-17
|
||||
|
||||
This optional release of Lotus introduces some critical fixes to the window PoSt process. It also upgrades some core dependencies, and introduces many improvements to the mining process, deal-making cycle, and overall User Experience.
|
||||
|
||||
## Changes
|
||||
|
||||
#### Some notable improvements:
|
||||
|
||||
- Correctly construct params for `SubmitWindowedPoSt` messages (https://github.com/filecoin-project/lotus/pull/3909)
|
||||
- Skip sectors correctly for Window PoSt (https://github.com/filecoin-project/lotus/pull/3839)
|
||||
- Split window PoST submission into multiple messages (https://github.com/filecoin-project/lotus/pull/3689)
|
||||
- Improve journal coverage (https://github.com/filecoin-project/lotus/pull/2455)
|
||||
- Allow retrievals while sealing (https://github.com/filecoin-project/lotus/pull/3778)
|
||||
- Don't prune locally published messages (https://github.com/filecoin-project/lotus/pull/3772)
|
||||
- Add get-ask, set-ask retrieval commands (https://github.com/filecoin-project/lotus/pull/3886)
|
||||
- Consistently name winning and window post in logs (https://github.com/filecoin-project/lotus/pull/3873))
|
||||
- Add auto flag to mpool replace (https://github.com/filecoin-project/lotus/pull/3752))
|
||||
|
||||
#### Dependencies
|
||||
|
||||
- Upgrade markets to `v0.6.1` (https://github.com/filecoin-project/lotus/pull/3906)
|
||||
- Upgrade specs-actors to `v0.9.10` (https://github.com/filecoin-project/lotus/pull/3846)
|
||||
- Upgrade badger (https://github.com/filecoin-project/lotus/pull/3739)
|
||||
|
||||
# 0.7.0 / 2020-09-10
|
||||
|
||||
This consensus-breaking release of Lotus is designed to test a network upgrade on the space race testnet. The changes that break consensus are:
|
||||
|
||||
- Upgrading the Drand network used from the test Drand network to the League of Entropy main drand network. This is the same Drand network that will be used in the Filecoin mainnet.
|
||||
- Upgrading to specs-actors v0.9.8, which adds a new method to the Multisig actor.
|
||||
|
||||
## Changes
|
||||
|
||||
#### Core Lotus
|
||||
|
||||
- Fix IsAncestorOf (https://github.com/filecoin-project/lotus/pull/3717)
|
||||
- Update to specs-actors v0.9.8 (https://github.com/filecoin-project/lotus/pull/3725)
|
||||
- Increase chain throughput by 20% (https://github.com/filecoin-project/lotus/pull/3732)
|
||||
- Updare to go-libp2p-pubsub `master` (https://github.com/filecoin-project/lotus/pull/3735)
|
||||
- Drand upgrade (https://github.com/filecoin-project/lotus/pull/3670)
|
||||
- Multisig API additions (https://github.com/filecoin-project/lotus/pull/3590)
|
||||
|
||||
#### Storage Miner
|
||||
|
||||
- Increase the number of times precommit2 is attempted before moving back to precommit1 (https://github.com/filecoin-project/lotus/pull/3720)
|
||||
|
||||
#### Message pool
|
||||
|
||||
- Relax mpool add strictness checks for local pushes (https://github.com/filecoin-project/lotus/pull/3724)
|
||||
|
||||
|
||||
#### Maintenance
|
||||
|
||||
- Fix devnets (https://github.com/filecoin-project/lotus/pull/3712)
|
||||
- Fix(chainwatch): compare prev miner with cur miner (https://github.com/filecoin-project/lotus/pull/3715)
|
||||
- CI: fix statediff build; make optional (https://github.com/filecoin-project/lotus/pull/3729)
|
||||
- Feat: Chaos abort (https://github.com/filecoin-project/lotus/pull/3733)
|
||||
|
||||
## Contributors
|
||||
|
||||
The following contributors had commits go into this release.
|
||||
We are grateful for every contribution!
|
||||
|
||||
| Contributor | Commits | Lines ± |
|
||||
|--------------------|---------|---------------|
|
||||
| arajasek | 28 | +1144/-239 |
|
||||
| Kubuxu | 19 | +452/-261 |
|
||||
| whyrusleeping | 13 | +456/-87 |
|
||||
| vyzo | 11 | +318/-20 |
|
||||
| raulk | 10 | +1289/-350 |
|
||||
| magik6k | 6 | +188/-55 |
|
||||
| dirkmc | 3 | +31/-8 |
|
||||
| alanshaw | 3 | +176/-37 |
|
||||
| Stebalien | 2 | +9/-12 |
|
||||
| lanzafame | 1 | +1/-1 |
|
||||
| frrist | 1 | +1/-1 |
|
||||
| mishmosh | 1 | +1/-1 |
|
||||
| nonsense | 1 | +1/-0 |
|
||||
|
||||
# 0.6.2 / 2020-09-09
|
||||
|
||||
This release introduces some critical fixes to message selection and gas estimation logic. It also adds the ability for nodes to mark a certain tipset as checkpointed, as well as various minor improvements and bugfixes.
|
||||
@@ -38,7 +117,6 @@ This release introduces some critical fixes to message selection and gas estimat
|
||||
- Paych: add docs on how to use paych status (https://github.com/filecoin-project/lotus/pull/3690)
|
||||
- Initial CODEOWNERS (https://github.com/filecoin-project/lotus/pull/3691)
|
||||
|
||||
|
||||
# 0.6.1 / 2020-09-08
|
||||
|
||||
This optional release introduces a minor improvement to the sync process, ensuring nodes don't fall behind and then resync.
|
||||
|
||||
@@ -92,6 +92,12 @@ lotus-shed: $(BUILD_DEPS)
|
||||
.PHONY: lotus-shed
|
||||
BINS+=lotus-shed
|
||||
|
||||
lotus-gateway: $(BUILD_DEPS)
|
||||
rm -f lotus-gateway
|
||||
go build $(GOFLAGS) -o lotus-gateway ./cmd/lotus-gateway
|
||||
.PHONY: lotus-gateway
|
||||
BINS+=lotus-gateway
|
||||
|
||||
build: lotus lotus-miner lotus-worker
|
||||
@[[ $$(type -P "lotus") ]] && echo "Caution: you have \
|
||||
an existing lotus binary in your PATH. This may cause problems if you don't run 'sudo make install'" || true
|
||||
|
||||
+38
-7
@@ -5,6 +5,8 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/dline"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
@@ -116,7 +118,8 @@ type FullNode interface {
|
||||
// The exported chain data includes the header chain from the given tipset
|
||||
// back to genesis, the entire genesis state, and the most recent 'nroots'
|
||||
// state trees.
|
||||
ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk types.TipSetKey) (<-chan []byte, error)
|
||||
// If oldmsgskip is set, messages from before the requested roots are also not included.
|
||||
ChainExport(ctx context.Context, nroots abi.ChainEpoch, oldmsgskip bool, tsk types.TipSetKey) (<-chan []byte, error)
|
||||
|
||||
// MethodGroup: Beacon
|
||||
// The Beacon method group contains methods for interacting with the random beacon (DRAND)
|
||||
@@ -318,7 +321,7 @@ type FullNode interface {
|
||||
StateMinerActiveSectors(context.Context, address.Address, types.TipSetKey) ([]*ChainSectorInfo, error)
|
||||
// StateMinerProvingDeadline calculates the deadline at some epoch for a proving period
|
||||
// and returns the deadline-related calculations.
|
||||
StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error)
|
||||
StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*dline.Info, error)
|
||||
// StateMinerPower returns the power of the indicated miner
|
||||
StateMinerPower(context.Context, address.Address, types.TipSetKey) (*MinerPower, error)
|
||||
// StateMinerInfo returns info about the indicated miner
|
||||
@@ -351,6 +354,8 @@ type FullNode interface {
|
||||
StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*SectorLocation, error)
|
||||
// StateSearchMsg searches for a message in the chain, and returns its receipt and the tipset where it was executed
|
||||
StateSearchMsg(context.Context, cid.Cid) (*MsgLookup, error)
|
||||
// StateMsgGasCost searches for a message in the chain, and returns details of the messages gas costs, including the penalty and miner tip
|
||||
StateMsgGasCost(context.Context, cid.Cid, types.TipSetKey) (*MsgGasCost, error)
|
||||
// StateWaitMsg looks back in the chain for a message. If not found, it blocks until the
|
||||
// message arrives on chain, and gets to the indicated confidence depth.
|
||||
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*MsgLookup, error)
|
||||
@@ -397,6 +402,9 @@ type FullNode interface {
|
||||
|
||||
// MsigGetAvailableBalance returns the portion of a multisig's balance that can be withdrawn or spent
|
||||
MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
|
||||
// MsigGetVested returns the amount of FIL that vested in a multisig in a certain period.
|
||||
// It takes the following params: <multisig address>, <start epoch>, <end epoch>
|
||||
MsigGetVested(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error)
|
||||
// MsigCreate creates a multisig wallet
|
||||
// It takes the following params: <required number of senders>, <approving addresses>, <unlock duration>
|
||||
//<initial balance>, <sender address of the create msg>, <gas price>
|
||||
@@ -413,17 +421,29 @@ type FullNode interface {
|
||||
// It takes the following params: <multisig address>, <proposed message ID>, <recipient address>, <value to transfer>,
|
||||
// <sender address of the cancel msg>, <method to call in the proposed message>, <params to include in the proposed message>
|
||||
MsigCancel(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
|
||||
// MsigAddPropose proposes adding a signer in the multisig
|
||||
// It takes the following params: <multisig address>, <sender address of the propose msg>,
|
||||
// <new signer>, <whether the number of required signers should be increased>
|
||||
MsigAddPropose(context.Context, address.Address, address.Address, address.Address, bool) (cid.Cid, error)
|
||||
// MsigAddApprove approves a previously proposed AddSigner message
|
||||
// It takes the following params: <multisig address>, <sender address of the approve msg>, <proposed message ID>,
|
||||
// <proposer address>, <new signer>, <whether the number of required signers should be increased>
|
||||
MsigAddApprove(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, bool) (cid.Cid, error)
|
||||
// MsigAddCancel cancels a previously proposed AddSigner message
|
||||
// It takes the following params: <multisig address>, <sender address of the cancel msg>, <proposed message ID>,
|
||||
// <new signer>, <whether the number of required signers should be increased>
|
||||
MsigAddCancel(context.Context, address.Address, address.Address, uint64, address.Address, bool) (cid.Cid, error)
|
||||
// MsigSwapPropose proposes swapping 2 signers in the multisig
|
||||
// It takes the following params: <multisig address>, <sender address of the propose msg>,
|
||||
// <old signer> <new signer>
|
||||
// <old signer>, <new signer>
|
||||
MsigSwapPropose(context.Context, address.Address, address.Address, address.Address, address.Address) (cid.Cid, error)
|
||||
// MsigSwapApprove approves a previously proposed SwapSigner
|
||||
// It takes the following params: <multisig address>, <sender address of the approve msg>, <proposed message ID>,
|
||||
// <proposer address>, <old signer> <new signer>
|
||||
// <proposer address>, <old signer>, <new signer>
|
||||
MsigSwapApprove(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, address.Address) (cid.Cid, error)
|
||||
// MsigSwapCancel cancels a previously proposed SwapSigner message
|
||||
// It takes the following params: <multisig address>, <sender address of the cancel msg>, <proposed message ID>,
|
||||
// <old signer> <new signer>
|
||||
// <old signer>, <new signer>
|
||||
MsigSwapCancel(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error)
|
||||
|
||||
MarketEnsureAvailable(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error)
|
||||
@@ -434,8 +454,8 @@ type FullNode interface {
|
||||
|
||||
PaychGet(ctx context.Context, from, to address.Address, amt types.BigInt) (*ChannelInfo, error)
|
||||
PaychGetWaitReady(context.Context, cid.Cid) (address.Address, error)
|
||||
PaychAvailableFunds(ch address.Address) (*ChannelAvailableFunds, error)
|
||||
PaychAvailableFundsByFromTo(from, to address.Address) (*ChannelAvailableFunds, error)
|
||||
PaychAvailableFunds(ctx context.Context, ch address.Address) (*ChannelAvailableFunds, error)
|
||||
PaychAvailableFundsByFromTo(ctx context.Context, from, to address.Address) (*ChannelAvailableFunds, error)
|
||||
PaychList(context.Context) ([]address.Address, error)
|
||||
PaychStatus(context.Context, address.Address) (*PaychStatus, error)
|
||||
PaychSettle(context.Context, address.Address) (cid.Cid, error)
|
||||
@@ -513,6 +533,17 @@ type MsgLookup struct {
|
||||
Height abi.ChainEpoch
|
||||
}
|
||||
|
||||
type MsgGasCost struct {
|
||||
Message cid.Cid // Can be different than requested, in case it was replaced, but only gas values changed
|
||||
GasUsed abi.TokenAmount
|
||||
BaseFeeBurn abi.TokenAmount
|
||||
OverEstimationBurn abi.TokenAmount
|
||||
MinerPenalty abi.TokenAmount
|
||||
MinerTip abi.TokenAmount
|
||||
Refund abi.TokenAmount
|
||||
TotalCost abi.TokenAmount
|
||||
}
|
||||
|
||||
type BlockMessages struct {
|
||||
BlsMessages []*types.Message
|
||||
SecpkMessages []*types.SignedMessage
|
||||
|
||||
+38
-11
@@ -5,6 +5,8 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/dline"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
metrics "github.com/libp2p/go-libp2p-core/metrics"
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
@@ -93,7 +95,7 @@ type FullNodeStruct struct {
|
||||
ChainGetNode func(ctx context.Context, p string) (*api.IpldObject, error) `perm:"read"`
|
||||
ChainGetMessage func(context.Context, cid.Cid) (*types.Message, error) `perm:"read"`
|
||||
ChainGetPath func(context.Context, types.TipSetKey, types.TipSetKey) ([]*api.HeadChange, error) `perm:"read"`
|
||||
ChainExport func(context.Context, abi.ChainEpoch, types.TipSetKey) (<-chan []byte, error) `perm:"read"`
|
||||
ChainExport func(context.Context, abi.ChainEpoch, bool, types.TipSetKey) (<-chan []byte, error) `perm:"read"`
|
||||
|
||||
BeaconGetEntry func(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) `perm:"read"`
|
||||
|
||||
@@ -162,7 +164,7 @@ type FullNodeStruct struct {
|
||||
StateNetworkName func(context.Context) (dtypes.NetworkName, error) `perm:"read"`
|
||||
StateMinerSectors func(context.Context, address.Address, *bitfield.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"`
|
||||
StateMinerActiveSectors func(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"`
|
||||
StateMinerProvingDeadline func(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error) `perm:"read"`
|
||||
StateMinerProvingDeadline func(context.Context, address.Address, types.TipSetKey) (*dline.Info, error) `perm:"read"`
|
||||
StateMinerPower func(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error) `perm:"read"`
|
||||
StateMinerInfo func(context.Context, address.Address, types.TipSetKey) (api.MinerInfo, error) `perm:"read"`
|
||||
StateMinerDeadlines func(context.Context, address.Address, types.TipSetKey) ([]*miner.Deadline, error) `perm:"read"`
|
||||
@@ -181,6 +183,7 @@ type FullNodeStruct struct {
|
||||
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"`
|
||||
StateMsgGasCost func(context.Context, cid.Cid, types.TipSetKey) (*api.MsgGasCost, error) `perm:"read"`
|
||||
StateWaitMsg func(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) `perm:"read"`
|
||||
StateSearchMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"`
|
||||
StateListMiners func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
|
||||
@@ -201,10 +204,14 @@ type FullNodeStruct struct {
|
||||
StateCirculatingSupply func(context.Context, types.TipSetKey) (api.CirculatingSupply, error) `perm:"read"`
|
||||
|
||||
MsigGetAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
MsigGetVested func(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
MsigCreate func(context.Context, uint64, []address.Address, abi.ChainEpoch, types.BigInt, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"`
|
||||
MsigPropose func(context.Context, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
||||
MsigApprove func(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
||||
MsigCancel func(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
||||
MsigAddPropose func(context.Context, address.Address, address.Address, address.Address, bool) (cid.Cid, error) `perm:"sign"`
|
||||
MsigAddApprove func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, bool) (cid.Cid, error) `perm:"sign"`
|
||||
MsigAddCancel func(context.Context, address.Address, address.Address, uint64, address.Address, bool) (cid.Cid, error) `perm:"sign"`
|
||||
MsigSwapPropose func(context.Context, address.Address, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||
MsigSwapApprove func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||
MsigSwapCancel func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||
@@ -213,8 +220,8 @@ type FullNodeStruct struct {
|
||||
|
||||
PaychGet func(ctx context.Context, from, to address.Address, amt types.BigInt) (*api.ChannelInfo, error) `perm:"sign"`
|
||||
PaychGetWaitReady func(context.Context, cid.Cid) (address.Address, error) `perm:"sign"`
|
||||
PaychAvailableFunds func(address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"`
|
||||
PaychAvailableFundsByFromTo func(address.Address, address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"`
|
||||
PaychAvailableFunds func(context.Context, address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"`
|
||||
PaychAvailableFundsByFromTo func(context.Context, address.Address, address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"`
|
||||
PaychList func(context.Context) ([]address.Address, error) `perm:"read"`
|
||||
PaychStatus func(context.Context, address.Address) (*api.PaychStatus, error) `perm:"read"`
|
||||
PaychSettle func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||
@@ -686,8 +693,8 @@ func (c *FullNodeStruct) ChainGetPath(ctx context.Context, from types.TipSetKey,
|
||||
return c.Internal.ChainGetPath(ctx, from, to)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk types.TipSetKey) (<-chan []byte, error) {
|
||||
return c.Internal.ChainExport(ctx, nroots, tsk)
|
||||
func (c *FullNodeStruct) ChainExport(ctx context.Context, nroots abi.ChainEpoch, iom bool, tsk types.TipSetKey) (<-chan []byte, error) {
|
||||
return c.Internal.ChainExport(ctx, nroots, iom, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) BeaconGetEntry(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) {
|
||||
@@ -734,7 +741,7 @@ func (c *FullNodeStruct) StateMinerActiveSectors(ctx context.Context, addr addre
|
||||
return c.Internal.StateMinerActiveSectors(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*miner.DeadlineInfo, error) {
|
||||
func (c *FullNodeStruct) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*dline.Info, error) {
|
||||
return c.Internal.StateMinerProvingDeadline(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
@@ -810,6 +817,10 @@ func (c *FullNodeStruct) StateReadState(ctx context.Context, addr address.Addres
|
||||
return c.Internal.StateReadState(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMsgGasCost(ctx context.Context, msgc cid.Cid, tsk types.TipSetKey) (*api.MsgGasCost, error) {
|
||||
return c.Internal.StateMsgGasCost(ctx, msgc, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid, confidence uint64) (*api.MsgLookup, error) {
|
||||
return c.Internal.StateWaitMsg(ctx, msgc, confidence)
|
||||
}
|
||||
@@ -882,6 +893,10 @@ func (c *FullNodeStruct) MsigGetAvailableBalance(ctx context.Context, a address.
|
||||
return c.Internal.MsigGetAvailableBalance(ctx, a, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigGetVested(ctx context.Context, a address.Address, sTsk types.TipSetKey, eTsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.MsigGetVested(ctx, a, sTsk, eTsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigCreate(ctx context.Context, req uint64, addrs []address.Address, duration abi.ChainEpoch, val types.BigInt, src address.Address, gp types.BigInt) (cid.Cid, error) {
|
||||
return c.Internal.MsigCreate(ctx, req, addrs, duration, val, src, gp)
|
||||
}
|
||||
@@ -898,6 +913,18 @@ func (c *FullNodeStruct) MsigCancel(ctx context.Context, msig address.Address, t
|
||||
return c.Internal.MsigCancel(ctx, msig, txID, to, amt, src, method, params)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigAddPropose(ctx context.Context, msig address.Address, src address.Address, newAdd address.Address, inc bool) (cid.Cid, error) {
|
||||
return c.Internal.MsigAddPropose(ctx, msig, src, newAdd, inc)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigAddApprove(ctx context.Context, msig address.Address, src address.Address, txID uint64, proposer address.Address, newAdd address.Address, inc bool) (cid.Cid, error) {
|
||||
return c.Internal.MsigAddApprove(ctx, msig, src, txID, proposer, newAdd, inc)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigAddCancel(ctx context.Context, msig address.Address, src address.Address, txID uint64, newAdd address.Address, inc bool) (cid.Cid, error) {
|
||||
return c.Internal.MsigAddCancel(ctx, msig, src, txID, newAdd, inc)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigSwapPropose(ctx context.Context, msig address.Address, src address.Address, oldAdd address.Address, newAdd address.Address) (cid.Cid, error) {
|
||||
return c.Internal.MsigSwapPropose(ctx, msig, src, oldAdd, newAdd)
|
||||
}
|
||||
@@ -922,12 +949,12 @@ func (c *FullNodeStruct) PaychGetWaitReady(ctx context.Context, sentinel cid.Cid
|
||||
return c.Internal.PaychGetWaitReady(ctx, sentinel)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) PaychAvailableFunds(ch address.Address) (*api.ChannelAvailableFunds, error) {
|
||||
return c.Internal.PaychAvailableFunds(ch)
|
||||
func (c *FullNodeStruct) PaychAvailableFunds(ctx context.Context, ch address.Address) (*api.ChannelAvailableFunds, error) {
|
||||
return c.Internal.PaychAvailableFunds(ctx, ch)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) PaychAvailableFundsByFromTo(from, to address.Address) (*api.ChannelAvailableFunds, error) {
|
||||
return c.Internal.PaychAvailableFundsByFromTo(from, to)
|
||||
func (c *FullNodeStruct) PaychAvailableFundsByFromTo(ctx context.Context, from, to address.Address) (*api.ChannelAvailableFunds, error) {
|
||||
return c.Internal.PaychAvailableFundsByFromTo(ctx, from, to)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) PaychList(ctx context.Context) ([]address.Address, error) {
|
||||
|
||||
@@ -105,7 +105,7 @@ func init() {
|
||||
addExample(network.Connected)
|
||||
addExample(dtypes.NetworkName("lotus"))
|
||||
addExample(api.SyncStateStage(1))
|
||||
addExample(build.APIVersion)
|
||||
addExample(build.FullAPIVersion)
|
||||
addExample(api.PCHInbound)
|
||||
addExample(time.Minute)
|
||||
addExample(datatransfer.TransferID(3))
|
||||
|
||||
@@ -65,6 +65,8 @@ func TestApis(t *testing.T, b APIBuilder) {
|
||||
var OneMiner = []StorageMiner{{Full: 0, Preseal: PresealGenesis}}
|
||||
|
||||
func (ts *testSuite) testVersion(t *testing.T) {
|
||||
build.RunningNodeType = build.NodeFull
|
||||
|
||||
ctx := context.Background()
|
||||
apis, _ := ts.makeNodes(t, 1, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
@@ -192,7 +192,7 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
||||
|
||||
// Drop the partition
|
||||
err = parts[0].Sectors.ForEach(func(sid uint64) error {
|
||||
return miner.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).MarkFailed(abi.SectorID{
|
||||
return miner.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).MarkCorrupted(abi.SectorID{
|
||||
Miner: abi.ActorID(mid),
|
||||
Number: abi.SectorNumber(sid),
|
||||
}, true)
|
||||
|
||||
+17
-6
@@ -1,15 +1,26 @@
|
||||
package build
|
||||
|
||||
import "github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
import (
|
||||
"sort"
|
||||
|
||||
var DrandNetwork = DrandIncentinet
|
||||
|
||||
func DrandConfig() dtypes.DrandConfig {
|
||||
return DrandConfigs[DrandNetwork]
|
||||
}
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
)
|
||||
|
||||
type DrandEnum int
|
||||
|
||||
func DrandConfigSchedule() dtypes.DrandSchedule {
|
||||
out := dtypes.DrandSchedule{}
|
||||
for start, config := range DrandSchedule {
|
||||
out = append(out, dtypes.DrandPoint{Start: start, Config: DrandConfigs[config]})
|
||||
}
|
||||
|
||||
sort.Slice(out, func(i, j int) bool {
|
||||
return out[i].Start < out[j].Start
|
||||
})
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
const (
|
||||
DrandMainnet DrandEnum = iota + 1
|
||||
DrandTestnet
|
||||
|
||||
+7
-1
@@ -10,9 +10,15 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
)
|
||||
|
||||
const UpgradeBreezeHeight = 0
|
||||
const UpgradeBreezeHeight = -1
|
||||
const BreezeGasTampingDuration = 0
|
||||
|
||||
const UpgradeSmokeHeight = -1
|
||||
|
||||
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandMainnet,
|
||||
}
|
||||
|
||||
func init() {
|
||||
power.ConsensusMinerMinPower = big.NewInt(2048)
|
||||
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
|
||||
@@ -36,3 +36,11 @@ func MessagesTopic(netName dtypes.NetworkName) string { return "/fil/msgs/" + st
|
||||
func DhtProtocolName(netName dtypes.NetworkName) protocol.ID {
|
||||
return protocol.ID("/fil/kad/" + string(netName))
|
||||
}
|
||||
|
||||
func UseNewestNetwork() bool {
|
||||
// TODO: Put these in a container we can iterate over
|
||||
if UpgradeBreezeHeight <= 0 && UpgradeSmokeHeight <= 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ package build
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
@@ -20,6 +22,7 @@ const UnixfsLinksPerLevel = 1024
|
||||
// Consensus / Network
|
||||
|
||||
const AllowableClockDriftSecs = uint64(1)
|
||||
const NewestNetworkVersion = network.Version2
|
||||
|
||||
// Epochs
|
||||
const ForkLengthThreshold = Finality
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"math/big"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
)
|
||||
@@ -70,6 +71,14 @@ var (
|
||||
PackingEfficiencyNum int64 = 4
|
||||
PackingEfficiencyDenom int64 = 5
|
||||
|
||||
UpgradeBreezeHeight abi.ChainEpoch = 0
|
||||
UpgradeBreezeHeight abi.ChainEpoch = -1
|
||||
BreezeGasTampingDuration abi.ChainEpoch = 0
|
||||
|
||||
UpgradeSmokeHeight abi.ChainEpoch = -1
|
||||
|
||||
DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandMainnet,
|
||||
}
|
||||
|
||||
NewestNetworkVersion = network.Version2
|
||||
)
|
||||
|
||||
@@ -12,9 +12,16 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
)
|
||||
|
||||
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandIncentinet,
|
||||
UpgradeSmokeHeight: DrandMainnet,
|
||||
}
|
||||
|
||||
const UpgradeBreezeHeight = 41280
|
||||
const BreezeGasTampingDuration = 120
|
||||
|
||||
const UpgradeSmokeHeight = 51000
|
||||
|
||||
func init() {
|
||||
power.ConsensusMinerMinPower = big.NewInt(10 << 40)
|
||||
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
|
||||
+37
-4
@@ -1,6 +1,10 @@
|
||||
package build
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
var CurrentCommit string
|
||||
var BuildType int
|
||||
@@ -25,7 +29,7 @@ func buildType() string {
|
||||
}
|
||||
|
||||
// BuildVersion is the local build version, set by build system
|
||||
const BuildVersion = "0.6.2"
|
||||
const BuildVersion = "0.7.1"
|
||||
|
||||
func UserVersion() string {
|
||||
return BuildVersion + buildType() + CurrentCommit
|
||||
@@ -52,8 +56,37 @@ func (ve Version) EqMajorMinor(v2 Version) bool {
|
||||
return ve&minorMask == v2&minorMask
|
||||
}
|
||||
|
||||
// APIVersion is a semver version of the rpc api exposed
|
||||
var APIVersion Version = newVer(0, 14, 0)
|
||||
type NodeType int
|
||||
|
||||
const (
|
||||
NodeUnknown NodeType = iota
|
||||
|
||||
NodeFull
|
||||
NodeMiner
|
||||
NodeWorker
|
||||
)
|
||||
|
||||
var RunningNodeType NodeType
|
||||
|
||||
func VersionForType(nodeType NodeType) (Version, error) {
|
||||
switch nodeType {
|
||||
case NodeFull:
|
||||
return FullAPIVersion, nil
|
||||
case NodeMiner:
|
||||
return MinerAPIVersion, nil
|
||||
case NodeWorker:
|
||||
return WorkerAPIVersion, nil
|
||||
default:
|
||||
return Version(0), xerrors.Errorf("unknown node type %d", nodeType)
|
||||
}
|
||||
}
|
||||
|
||||
// semver versions of the rpc api exposed
|
||||
var (
|
||||
FullAPIVersion = newVer(0, 15, 0)
|
||||
MinerAPIVersion = newVer(0, 14, 0)
|
||||
WorkerAPIVersion = newVer(0, 14, 0)
|
||||
)
|
||||
|
||||
//nolint:varcheck,deadcode
|
||||
const (
|
||||
|
||||
+67
-6
@@ -18,6 +18,23 @@ type Response struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
type Schedule []BeaconPoint
|
||||
|
||||
func (bs Schedule) BeaconForEpoch(e abi.ChainEpoch) RandomBeacon {
|
||||
for i := len(bs) - 1; i >= 0; i-- {
|
||||
bp := bs[i]
|
||||
if e >= bp.Start {
|
||||
return bp.Beacon
|
||||
}
|
||||
}
|
||||
return bs[0].Beacon
|
||||
}
|
||||
|
||||
type BeaconPoint struct {
|
||||
Start abi.ChainEpoch
|
||||
Beacon RandomBeacon
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -25,11 +42,30 @@ type Response struct {
|
||||
type RandomBeacon interface {
|
||||
Entry(context.Context, uint64) <-chan Response
|
||||
VerifyEntry(types.BeaconEntry, types.BeaconEntry) error
|
||||
MaxBeaconRoundForEpoch(abi.ChainEpoch, types.BeaconEntry) uint64
|
||||
MaxBeaconRoundForEpoch(abi.ChainEpoch) uint64
|
||||
}
|
||||
|
||||
func ValidateBlockValues(b RandomBeacon, h *types.BlockHeader, prevEntry types.BeaconEntry) error {
|
||||
maxRound := b.MaxBeaconRoundForEpoch(h.Height, prevEntry)
|
||||
func ValidateBlockValues(bSchedule Schedule, h *types.BlockHeader, parentEpoch abi.ChainEpoch,
|
||||
prevEntry types.BeaconEntry) error {
|
||||
{
|
||||
parentBeacon := bSchedule.BeaconForEpoch(parentEpoch)
|
||||
currBeacon := bSchedule.BeaconForEpoch(h.Height)
|
||||
if parentBeacon != currBeacon {
|
||||
if len(h.BeaconEntries) != 2 {
|
||||
return xerrors.Errorf("expected two beacon entries at beacon fork, got %d", len(h.BeaconEntries))
|
||||
}
|
||||
err := currBeacon.VerifyEntry(h.BeaconEntries[1], h.BeaconEntries[0])
|
||||
if err != nil {
|
||||
return xerrors.Errorf("beacon at fork point invalid: (%v, %v): %w",
|
||||
h.BeaconEntries[1], h.BeaconEntries[0], err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: fork logic
|
||||
b := bSchedule.BeaconForEpoch(h.Height)
|
||||
maxRound := b.MaxBeaconRoundForEpoch(h.Height)
|
||||
if maxRound == prevEntry.Round {
|
||||
if len(h.BeaconEntries) != 0 {
|
||||
return xerrors.Errorf("expected not to have any beacon entries in this block, got %d", len(h.BeaconEntries))
|
||||
@@ -56,10 +92,35 @@ func ValidateBlockValues(b RandomBeacon, h *types.BlockHeader, prevEntry types.B
|
||||
return nil
|
||||
}
|
||||
|
||||
func BeaconEntriesForBlock(ctx context.Context, beacon RandomBeacon, round abi.ChainEpoch, prev types.BeaconEntry) ([]types.BeaconEntry, error) {
|
||||
func BeaconEntriesForBlock(ctx context.Context, bSchedule Schedule, epoch abi.ChainEpoch, parentEpoch abi.ChainEpoch, prev types.BeaconEntry) ([]types.BeaconEntry, error) {
|
||||
{
|
||||
parentBeacon := bSchedule.BeaconForEpoch(parentEpoch)
|
||||
currBeacon := bSchedule.BeaconForEpoch(epoch)
|
||||
if parentBeacon != currBeacon {
|
||||
// Fork logic
|
||||
round := currBeacon.MaxBeaconRoundForEpoch(epoch)
|
||||
out := make([]types.BeaconEntry, 2)
|
||||
rch := currBeacon.Entry(ctx, round-1)
|
||||
res := <-rch
|
||||
if res.Err != nil {
|
||||
return nil, xerrors.Errorf("getting entry %d returned error: %w", round-1, res.Err)
|
||||
}
|
||||
out[0] = res.Entry
|
||||
rch = currBeacon.Entry(ctx, round)
|
||||
res = <-rch
|
||||
if res.Err != nil {
|
||||
return nil, xerrors.Errorf("getting entry %d returned error: %w", round, res.Err)
|
||||
}
|
||||
out[1] = res.Entry
|
||||
return out, nil
|
||||
}
|
||||
}
|
||||
|
||||
beacon := bSchedule.BeaconForEpoch(epoch)
|
||||
|
||||
start := build.Clock.Now()
|
||||
|
||||
maxRound := beacon.MaxBeaconRoundForEpoch(round, prev)
|
||||
maxRound := beacon.MaxBeaconRoundForEpoch(epoch)
|
||||
if maxRound == prev.Round {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -82,7 +143,7 @@ func BeaconEntriesForBlock(ctx context.Context, beacon RandomBeacon, round abi.C
|
||||
out = append(out, resp.Entry)
|
||||
cur = resp.Entry.Round - 1
|
||||
case <-ctx.Done():
|
||||
return nil, xerrors.Errorf("context timed out waiting on beacon entry to come back for round %d: %w", round, ctx.Err())
|
||||
return nil, xerrors.Errorf("context timed out waiting on beacon entry to come back for epoch %d: %w", epoch, ctx.Err())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -187,7 +187,7 @@ func (db *DrandBeacon) VerifyEntry(curr types.BeaconEntry, prev types.BeaconEntr
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DrandBeacon) MaxBeaconRoundForEpoch(filEpoch abi.ChainEpoch, prevEntry types.BeaconEntry) uint64 {
|
||||
func (db *DrandBeacon) MaxBeaconRoundForEpoch(filEpoch abi.ChainEpoch) uint64 {
|
||||
// TODO: sometimes the genesis time for filecoin is zero and this goes negative
|
||||
latestTs := ((uint64(filEpoch) * db.filRoundTime) + db.filGenTime) - db.filRoundTime
|
||||
dround := (latestTs - db.drandGenTime) / uint64(db.interval.Seconds())
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
func TestPrintGroupInfo(t *testing.T) {
|
||||
server := build.DrandConfig().Servers[0]
|
||||
server := build.DrandConfigs[build.DrandIncentinet].Servers[0]
|
||||
c, err := hclient.New(server, nil, nil)
|
||||
assert.NoError(t, err)
|
||||
cg := c.(interface {
|
||||
|
||||
@@ -53,11 +53,7 @@ func (mb *mockBeacon) VerifyEntry(from types.BeaconEntry, to types.BeaconEntry)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mb *mockBeacon) IsEntryForEpoch(e types.BeaconEntry, epoch abi.ChainEpoch, nulls int) (bool, error) {
|
||||
return int64(e.Round) <= int64(epoch) && int64(epoch)-int64(nulls) >= int64(e.Round), nil
|
||||
}
|
||||
|
||||
func (mb *mockBeacon) MaxBeaconRoundForEpoch(epoch abi.ChainEpoch, prevEntry types.BeaconEntry) uint64 {
|
||||
func (mb *mockBeacon) MaxBeaconRoundForEpoch(epoch abi.ChainEpoch) uint64 {
|
||||
return uint64(epoch)
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ type heightEvents struct {
|
||||
}
|
||||
|
||||
func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error {
|
||||
|
||||
ctx, span := trace.StartSpan(e.ctx, "events.HeightHeadChange")
|
||||
defer span.End()
|
||||
span.AddAttributes(trace.Int64Attribute("endHeight", int64(app[0].Height())))
|
||||
@@ -145,12 +144,11 @@ func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error {
|
||||
}
|
||||
|
||||
// ChainAt invokes the specified `HeightHandler` when the chain reaches the
|
||||
// specified height+confidence threshold. If the chain is rolled-back under the
|
||||
// specified height, `RevertHandler` will be called.
|
||||
// specified height+confidence threshold. If the chain is rolled-back under the
|
||||
// specified height, `RevertHandler` will be called.
|
||||
//
|
||||
// ts passed to handlers is the tipset at the specified, or above, if lower tipsets were null
|
||||
func (e *heightEvents) ChainAt(hnd HeightHandler, rev RevertHandler, confidence int, h abi.ChainEpoch) error {
|
||||
|
||||
e.lk.Lock() // Tricky locking, check your locks if you modify this function!
|
||||
|
||||
best, err := e.tsc.best()
|
||||
|
||||
@@ -3,6 +3,7 @@ package state
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
typegen "github.com/whyrusleeping/cbor-gen"
|
||||
)
|
||||
@@ -69,7 +70,7 @@ func DiffAdtArray(preArr, curArr *adt.Array, out AdtArrayDiff) error {
|
||||
// Modify should be called when a value is modified in the map
|
||||
// Remove should be called when a value is removed from the map
|
||||
type AdtMapDiff interface {
|
||||
AsKey(key string) (adt.Keyer, error)
|
||||
AsKey(key string) (abi.Keyer, error)
|
||||
Add(key string, val *typegen.Deferred) error
|
||||
Modify(key string, from, to *typegen.Deferred) error
|
||||
Remove(key string, val *typegen.Deferred) error
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
cbornode "github.com/ipfs/go-ipld-cbor"
|
||||
typegen "github.com/whyrusleeping/cbor-gen"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
@@ -78,21 +79,21 @@ func TestDiffAdtMap(t *testing.T) {
|
||||
mapA := adt.MakeEmptyMap(ctxstoreA)
|
||||
mapB := adt.MakeEmptyMap(ctxstoreB)
|
||||
|
||||
require.NoError(t, mapA.Put(adt.UIntKey(0), runtime.CBORBytes([]byte{0}))) // delete
|
||||
require.NoError(t, mapA.Put(abi.UIntKey(0), runtime.CBORBytes([]byte{0}))) // delete
|
||||
|
||||
require.NoError(t, mapA.Put(adt.UIntKey(1), runtime.CBORBytes([]byte{0}))) // modify
|
||||
require.NoError(t, mapB.Put(adt.UIntKey(1), runtime.CBORBytes([]byte{1})))
|
||||
require.NoError(t, mapA.Put(abi.UIntKey(1), runtime.CBORBytes([]byte{0}))) // modify
|
||||
require.NoError(t, mapB.Put(abi.UIntKey(1), runtime.CBORBytes([]byte{1})))
|
||||
|
||||
require.NoError(t, mapA.Put(adt.UIntKey(2), runtime.CBORBytes([]byte{1}))) // delete
|
||||
require.NoError(t, mapA.Put(abi.UIntKey(2), runtime.CBORBytes([]byte{1}))) // delete
|
||||
|
||||
require.NoError(t, mapA.Put(adt.UIntKey(3), runtime.CBORBytes([]byte{0}))) // noop
|
||||
require.NoError(t, mapB.Put(adt.UIntKey(3), runtime.CBORBytes([]byte{0})))
|
||||
require.NoError(t, mapA.Put(abi.UIntKey(3), runtime.CBORBytes([]byte{0}))) // noop
|
||||
require.NoError(t, mapB.Put(abi.UIntKey(3), runtime.CBORBytes([]byte{0})))
|
||||
|
||||
require.NoError(t, mapA.Put(adt.UIntKey(4), runtime.CBORBytes([]byte{0}))) // modify
|
||||
require.NoError(t, mapB.Put(adt.UIntKey(4), runtime.CBORBytes([]byte{6})))
|
||||
require.NoError(t, mapA.Put(abi.UIntKey(4), runtime.CBORBytes([]byte{0}))) // modify
|
||||
require.NoError(t, mapB.Put(abi.UIntKey(4), runtime.CBORBytes([]byte{6})))
|
||||
|
||||
require.NoError(t, mapB.Put(adt.UIntKey(5), runtime.CBORBytes{8})) // add
|
||||
require.NoError(t, mapB.Put(adt.UIntKey(6), runtime.CBORBytes{9})) // add
|
||||
require.NoError(t, mapB.Put(abi.UIntKey(5), runtime.CBORBytes{8})) // add
|
||||
require.NoError(t, mapB.Put(abi.UIntKey(6), runtime.CBORBytes{9})) // add
|
||||
|
||||
changes := new(TestDiffMap)
|
||||
|
||||
@@ -134,12 +135,12 @@ type TestDiffMap struct {
|
||||
|
||||
var _ AdtMapDiff = &TestDiffMap{}
|
||||
|
||||
func (t *TestDiffMap) AsKey(key string) (adt.Keyer, error) {
|
||||
k, err := adt.ParseUIntKey(key)
|
||||
func (t *TestDiffMap) AsKey(key string) (abi.Keyer, error) {
|
||||
k, err := abi.ParseUIntKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return adt.UIntKey(k), nil
|
||||
return abi.UIntKey(k), nil
|
||||
}
|
||||
|
||||
func (t *TestDiffMap) Add(key string, val *typegen.Deferred) error {
|
||||
@@ -148,7 +149,7 @@ func (t *TestDiffMap) Add(key string, val *typegen.Deferred) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
k, err := adt.ParseUIntKey(key)
|
||||
k, err := abi.ParseUIntKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -172,7 +173,7 @@ func (t *TestDiffMap) Modify(key string, from, to *typegen.Deferred) error {
|
||||
return err
|
||||
}
|
||||
|
||||
k, err := adt.ParseUIntKey(key)
|
||||
k, err := abi.ParseUIntKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -198,7 +199,7 @@ func (t *TestDiffMap) Remove(key string, val *typegen.Deferred) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
k, err := adt.ParseUIntKey(key)
|
||||
k, err := abi.ParseUIntKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -537,8 +537,8 @@ type MinerPreCommitChanges struct {
|
||||
Removed []miner.SectorPreCommitOnChainInfo
|
||||
}
|
||||
|
||||
func (m *MinerPreCommitChanges) AsKey(key string) (adt.Keyer, error) {
|
||||
sector, err := adt.ParseUIntKey(key)
|
||||
func (m *MinerPreCommitChanges) AsKey(key string) (abi.Keyer, error) {
|
||||
sector, err := abi.ParseUIntKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -662,12 +662,12 @@ type AddressChange struct {
|
||||
|
||||
type DiffInitActorStateFunc func(ctx context.Context, oldState *init_.State, newState *init_.State) (changed bool, user UserData, err error)
|
||||
|
||||
func (i *InitActorAddressChanges) AsKey(key string) (adt.Keyer, error) {
|
||||
func (i *InitActorAddressChanges) AsKey(key string) (abi.Keyer, error) {
|
||||
addr, err := address.NewFromBytes([]byte(key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return adt.AddrKey(addr), nil
|
||||
return abi.AddrKey(addr), nil
|
||||
}
|
||||
|
||||
func (i *InitActorAddressChanges) Add(key string, val *typegen.Deferred) error {
|
||||
|
||||
+5
-5
@@ -59,7 +59,7 @@ type ChainGen struct {
|
||||
|
||||
cs *store.ChainStore
|
||||
|
||||
beacon beacon.RandomBeacon
|
||||
beacon beacon.Schedule
|
||||
|
||||
sm *stmgr.StateManager
|
||||
|
||||
@@ -252,7 +252,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
|
||||
miners := []address.Address{maddr1, maddr2}
|
||||
|
||||
beac := beacon.NewMockBeacon(time.Second)
|
||||
beac := beacon.Schedule{{Start: 0, Beacon: beacon.NewMockBeacon(time.Second)}}
|
||||
//beac, err := drand.NewDrandBeacon(tpl.Timestamp, build.BlockDelaySecs)
|
||||
//if err != nil {
|
||||
//return nil, xerrors.Errorf("creating drand beacon: %w", err)
|
||||
@@ -338,7 +338,7 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add
|
||||
|
||||
prev := mbi.PrevBeaconEntry
|
||||
|
||||
entries, err := beacon.BeaconEntriesForBlock(ctx, cg.beacon, round, prev)
|
||||
entries, err := beacon.BeaconEntriesForBlock(ctx, cg.beacon, round, pts.Height(), prev)
|
||||
if err != nil {
|
||||
return nil, nil, nil, xerrors.Errorf("get beacon entries for block: %w", err)
|
||||
}
|
||||
@@ -358,7 +358,7 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add
|
||||
return nil, nil, nil, xerrors.Errorf("failed to cbor marshal address: %w", err)
|
||||
}
|
||||
|
||||
if len(entries) == 0 {
|
||||
if round > build.UpgradeSmokeHeight {
|
||||
buf.Write(pts.MinTicket().VRFProof)
|
||||
}
|
||||
|
||||
@@ -559,7 +559,7 @@ type mca struct {
|
||||
w *wallet.Wallet
|
||||
sm *stmgr.StateManager
|
||||
pv ffiwrapper.Verifier
|
||||
bcn beacon.RandomBeacon
|
||||
bcn beacon.Schedule
|
||||
}
|
||||
|
||||
func (mca mca) ChainGetRandomnessFromTickets(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) {
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
@@ -406,8 +406,8 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci
|
||||
verifNeeds := make(map[address.Address]abi.PaddedPieceSize)
|
||||
var sum abi.PaddedPieceSize
|
||||
|
||||
nwv := func(context.Context, abi.ChainEpoch) runtime.NetworkVersion {
|
||||
return runtime.NetworkVersion1
|
||||
nwv := func(context.Context, abi.ChainEpoch) network.Version {
|
||||
return build.NewestNetworkVersion
|
||||
}
|
||||
|
||||
vmopt := vm.VMOpts{
|
||||
|
||||
@@ -6,6 +6,10 @@ import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
@@ -61,8 +65,8 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
return big.Zero(), nil
|
||||
}
|
||||
|
||||
nwv := func(context.Context, abi.ChainEpoch) runtime.NetworkVersion {
|
||||
return runtime.NetworkVersion1
|
||||
nwv := func(context.Context, abi.ChainEpoch) network.Version {
|
||||
return build.NewestNetworkVersion
|
||||
}
|
||||
|
||||
vmopt := &vm.VMOpts{
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
@@ -50,7 +51,7 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi
|
||||
fmt.Printf("init set %s t0%d\n", e, counter)
|
||||
|
||||
value := cbg.CborInt(counter)
|
||||
if err := amap.Put(adt.AddrKey(e), &value); err != nil {
|
||||
if err := amap.Put(abi.AddrKey(e), &value); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
counter = counter + 1
|
||||
@@ -77,7 +78,7 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi
|
||||
fmt.Printf("init set %s t0%d\n", ainfo.Owner, counter)
|
||||
|
||||
value := cbg.CborInt(counter)
|
||||
if err := amap.Put(adt.AddrKey(ainfo.Owner), &value); err != nil {
|
||||
if err := amap.Put(abi.AddrKey(ainfo.Owner), &value); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
counter = counter + 1
|
||||
@@ -95,7 +96,7 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi
|
||||
return 0, nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err)
|
||||
}
|
||||
value := cbg.CborInt(80)
|
||||
if err := amap.Put(adt.AddrKey(ainfo.Owner), &value); err != nil {
|
||||
if err := amap.Put(abi.AddrKey(ainfo.Owner), &value); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
} else if rootVerifier.Type == genesis.TMultisig {
|
||||
@@ -110,7 +111,7 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi
|
||||
fmt.Printf("init set %s t0%d\n", e, counter)
|
||||
|
||||
value := cbg.CborInt(counter)
|
||||
if err := amap.Put(adt.AddrKey(e), &value); err != nil {
|
||||
if err := amap.Put(abi.AddrKey(e), &value); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
counter = counter + 1
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
@@ -31,6 +32,7 @@ import (
|
||||
"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/journal"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
|
||||
@@ -50,6 +52,7 @@ var RepublishInterval = time.Duration(10*build.BlockDelaySecs+build.PropagationD
|
||||
|
||||
var minimumBaseFee = types.NewInt(uint64(build.MinimumBaseFee))
|
||||
var baseFeeLowerBoundFactor = types.NewInt(10)
|
||||
var baseFeeLowerBoundFactorConservative = types.NewInt(100)
|
||||
|
||||
var MaxActorPendingMessages = 1000
|
||||
|
||||
@@ -82,9 +85,25 @@ const (
|
||||
localUpdates = "update"
|
||||
)
|
||||
|
||||
// this is *temporary* mutilation until we have implemented uncapped miner penalties -- it will go
|
||||
// away in the next fork.
|
||||
var strictBaseFeeValidation = false
|
||||
// Journal event types.
|
||||
const (
|
||||
evtTypeMpoolAdd = iota
|
||||
evtTypeMpoolRemove
|
||||
evtTypeMpoolRepub
|
||||
)
|
||||
|
||||
// MessagePoolEvt is the journal entry for message pool events.
|
||||
type MessagePoolEvt struct {
|
||||
Action string
|
||||
Messages []MessagePoolEvtMessage
|
||||
Error error `json:",omitempty"`
|
||||
}
|
||||
|
||||
type MessagePoolEvtMessage struct {
|
||||
types.Message
|
||||
|
||||
CID cid.Cid
|
||||
}
|
||||
|
||||
func init() {
|
||||
// if the republish interval is too short compared to the pubsub timecache, adjust it
|
||||
@@ -139,6 +158,8 @@ type MessagePool struct {
|
||||
netName dtypes.NetworkName
|
||||
|
||||
sigValCache *lru.TwoQueueCache
|
||||
|
||||
evtTypes [3]journal.EventType
|
||||
}
|
||||
|
||||
type msgSet struct {
|
||||
@@ -160,6 +181,22 @@ func ComputeMinRBF(curPrem abi.TokenAmount) abi.TokenAmount {
|
||||
return types.BigAdd(minPrice, types.NewInt(1))
|
||||
}
|
||||
|
||||
func CapGasFee(msg *types.Message, maxFee abi.TokenAmount) {
|
||||
if maxFee.Equals(big.Zero()) {
|
||||
maxFee = types.NewInt(build.FilecoinPrecision / 10)
|
||||
}
|
||||
|
||||
gl := types.NewInt(uint64(msg.GasLimit))
|
||||
totalFee := types.BigMul(msg.GasFeeCap, gl)
|
||||
|
||||
if totalFee.LessThanEqual(maxFee) {
|
||||
return
|
||||
}
|
||||
|
||||
msg.GasFeeCap = big.Div(maxFee, gl)
|
||||
msg.GasPremium = big.Min(msg.GasFeeCap, msg.GasPremium) // cap premium at FeeCap
|
||||
}
|
||||
|
||||
func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, strict bool) (bool, error) {
|
||||
nextNonce := ms.nextNonce
|
||||
nonceGap := false
|
||||
@@ -299,6 +336,11 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa
|
||||
api: api,
|
||||
netName: netName,
|
||||
cfg: cfg,
|
||||
evtTypes: [...]journal.EventType{
|
||||
evtTypeMpoolAdd: journal.J.RegisterEventType("mpool", "add"),
|
||||
evtTypeMpoolRemove: journal.J.RegisterEventType("mpool", "remove"),
|
||||
evtTypeMpoolRepub: journal.J.RegisterEventType("mpool", "repub"),
|
||||
},
|
||||
}
|
||||
|
||||
// enable initial prunes
|
||||
@@ -350,10 +392,12 @@ func (mp *MessagePool) runLoop() {
|
||||
if err := mp.republishPendingMessages(); err != nil {
|
||||
log.Errorf("error while republishing messages: %s", err)
|
||||
}
|
||||
|
||||
case <-mp.pruneTrigger:
|
||||
if err := mp.pruneExcessMessages(); err != nil {
|
||||
log.Errorf("failed to prune excess messages from mempool: %s", err)
|
||||
}
|
||||
|
||||
case <-mp.closer:
|
||||
mp.repubTk.Stop()
|
||||
return
|
||||
@@ -397,18 +441,27 @@ func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.T
|
||||
// Note that for local messages, we always add them so that they can be accepted and republished
|
||||
// automatically.
|
||||
publish := local
|
||||
if strictBaseFeeValidation && len(curTs.Blocks()) > 0 {
|
||||
baseFee := curTs.Blocks()[0].ParentBaseFee
|
||||
baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor)
|
||||
if m.Message.GasFeeCap.LessThan(baseFeeLowerBound) {
|
||||
if local {
|
||||
log.Warnf("local message will not be immediately published because GasFeeCap doesn't meet the lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s)",
|
||||
m.Message.GasFeeCap, baseFeeLowerBound)
|
||||
publish = false
|
||||
} else {
|
||||
return false, xerrors.Errorf("GasFeeCap doesn't meet base fee lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s): %w",
|
||||
m.Message.GasFeeCap, baseFeeLowerBound, ErrSoftValidationFailure)
|
||||
}
|
||||
|
||||
var baseFee big.Int
|
||||
if len(curTs.Blocks()) > 0 {
|
||||
baseFee = curTs.Blocks()[0].ParentBaseFee
|
||||
} else {
|
||||
var err error
|
||||
baseFee, err = mp.api.ChainComputeBaseFee(context.TODO(), curTs)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("computing basefee: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
baseFeeLowerBound := getBaseFeeLowerBound(baseFee, baseFeeLowerBoundFactorConservative)
|
||||
if m.Message.GasFeeCap.LessThan(baseFeeLowerBound) {
|
||||
if local {
|
||||
log.Warnf("local message will not be immediately published because GasFeeCap doesn't meet the lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s)",
|
||||
m.Message.GasFeeCap, baseFeeLowerBound)
|
||||
publish = false
|
||||
} else {
|
||||
return false, xerrors.Errorf("GasFeeCap doesn't meet base fee lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s): %w",
|
||||
m.Message.GasFeeCap, baseFeeLowerBound, ErrSoftValidationFailure)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,7 +643,7 @@ func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet, local
|
||||
return false, err
|
||||
}
|
||||
|
||||
return publish, mp.addLocked(m, true)
|
||||
return publish, mp.addLocked(m, !local)
|
||||
}
|
||||
|
||||
func (mp *MessagePool) addLoaded(m *types.SignedMessage) error {
|
||||
@@ -683,6 +736,14 @@ func (mp *MessagePool) addLocked(m *types.SignedMessage, strict bool) error {
|
||||
Type: api.MpoolAdd,
|
||||
Message: m,
|
||||
}, localUpdates)
|
||||
|
||||
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolAdd], func() interface{} {
|
||||
return MessagePoolEvt{
|
||||
Action: "add",
|
||||
Messages: []MessagePoolEvtMessage{{Message: m.Message, CID: m.Cid()}},
|
||||
}
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -812,7 +873,7 @@ func (mp *MessagePool) PushWithNonce(ctx context.Context, addr address.Address,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := mp.addLocked(msg, true); err != nil {
|
||||
if err := mp.addLocked(msg, false); err != nil {
|
||||
return nil, xerrors.Errorf("add locked failed: %w", err)
|
||||
}
|
||||
if err := mp.addLocal(msg, msgb); err != nil {
|
||||
@@ -845,6 +906,12 @@ func (mp *MessagePool) remove(from address.Address, nonce uint64, applied bool)
|
||||
Message: m,
|
||||
}, localUpdates)
|
||||
|
||||
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolRemove], func() interface{} {
|
||||
return MessagePoolEvt{
|
||||
Action: "remove",
|
||||
Messages: []MessagePoolEvtMessage{{Message: m.Message, CID: m.Cid()}}}
|
||||
})
|
||||
|
||||
mp.currentSize--
|
||||
}
|
||||
|
||||
@@ -1282,3 +1349,12 @@ func (mp *MessagePool) Clear(local bool) {
|
||||
delete(mp.pending, a)
|
||||
}
|
||||
}
|
||||
|
||||
func getBaseFeeLowerBound(baseFee, factor types.BigInt) types.BigInt {
|
||||
baseFeeLowerBound := types.BigDiv(baseFee, factor)
|
||||
if baseFeeLowerBound.LessThan(minimumBaseFee) {
|
||||
baseFeeLowerBound = minimumBaseFee
|
||||
}
|
||||
|
||||
return baseFeeLowerBound
|
||||
}
|
||||
|
||||
@@ -46,13 +46,21 @@ func (mp *MessagePool) pruneMessages(ctx context.Context, ts *types.TipSet) erro
|
||||
if err != nil {
|
||||
return xerrors.Errorf("computing basefee: %w", err)
|
||||
}
|
||||
baseFeeLowerBound := getBaseFeeLowerBound(baseFee, baseFeeLowerBoundFactor)
|
||||
|
||||
pending, _ := mp.getPendingMessages(ts, ts)
|
||||
|
||||
// priority actors -- not pruned
|
||||
priority := make(map[address.Address]struct{})
|
||||
// protected actors -- not pruned
|
||||
protected := make(map[address.Address]struct{})
|
||||
|
||||
// we never prune priority addresses
|
||||
for _, actor := range mp.cfg.PriorityAddrs {
|
||||
priority[actor] = struct{}{}
|
||||
protected[actor] = struct{}{}
|
||||
}
|
||||
|
||||
// we also never prune locally published messages
|
||||
for actor := range mp.localAddrs {
|
||||
protected[actor] = struct{}{}
|
||||
}
|
||||
|
||||
// Collect all messages to track which ones to remove and create chains for block inclusion
|
||||
@@ -61,18 +69,18 @@ func (mp *MessagePool) pruneMessages(ctx context.Context, ts *types.TipSet) erro
|
||||
|
||||
var chains []*msgChain
|
||||
for actor, mset := range pending {
|
||||
// we never prune priority actors
|
||||
_, keep := priority[actor]
|
||||
// we never prune protected actors
|
||||
_, keep := protected[actor]
|
||||
if keep {
|
||||
keepCount += len(mset)
|
||||
continue
|
||||
}
|
||||
|
||||
// not a priority actor, track the messages and create chains
|
||||
// not a protected actor, track the messages and create chains
|
||||
for _, m := range mset {
|
||||
pruneMsgs[m.Message.Cid()] = m
|
||||
}
|
||||
actorChains := mp.createMessageChains(actor, mset, baseFee, ts)
|
||||
actorChains := mp.createMessageChains(actor, mset, baseFeeLowerBound, ts)
|
||||
chains = append(chains, actorChains...)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
@@ -27,11 +28,7 @@ func (mp *MessagePool) republishPendingMessages() error {
|
||||
mp.curTsLk.Unlock()
|
||||
return xerrors.Errorf("computing basefee: %w", err)
|
||||
}
|
||||
|
||||
baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor)
|
||||
if baseFeeLowerBoundFactor.LessThan(minimumBaseFee) {
|
||||
baseFeeLowerBound = minimumBaseFee
|
||||
}
|
||||
baseFeeLowerBound := getBaseFeeLowerBound(baseFee, baseFeeLowerBoundFactor)
|
||||
|
||||
pending := make(map[address.Address]map[uint64]*types.SignedMessage)
|
||||
mp.lk.Lock()
|
||||
@@ -150,6 +147,19 @@ loop:
|
||||
}
|
||||
}
|
||||
|
||||
if len(msgs) > 0 {
|
||||
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolRepub], func() interface{} {
|
||||
msgs := make([]MessagePoolEvtMessage, 0, len(msgs))
|
||||
for _, m := range msgs {
|
||||
msgs = append(msgs, MessagePoolEvtMessage{Message: m.Message, CID: m.Cid()})
|
||||
}
|
||||
return MessagePoolEvt{
|
||||
Action: "repub",
|
||||
Messages: msgs,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// track most recently republished messages
|
||||
republished := make(map[cid.Cid]struct{})
|
||||
for _, m := range msgs[:count] {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
|
||||
@@ -209,7 +210,7 @@ func (st *StateTree) GetActor(addr address.Address) (*types.Actor, error) {
|
||||
}
|
||||
|
||||
var act types.Actor
|
||||
if found, err := st.root.Get(adt.AddrKey(addr), &act); err != nil {
|
||||
if found, err := st.root.Get(abi.AddrKey(addr), &act); err != nil {
|
||||
return nil, xerrors.Errorf("hamt find failed: %w", err)
|
||||
} else if !found {
|
||||
return nil, types.ErrActorNotFound
|
||||
@@ -254,11 +255,11 @@ func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) {
|
||||
|
||||
for addr, sto := range st.snaps.layers[0].actors {
|
||||
if sto.Delete {
|
||||
if err := st.root.Delete(adt.AddrKey(addr)); err != nil {
|
||||
if err := st.root.Delete(abi.AddrKey(addr)); err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
} else {
|
||||
if err := st.root.Put(adt.AddrKey(addr), &sto.Act); err != nil {
|
||||
if err := st.root.Put(abi.AddrKey(addr), &sto.Act); err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"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"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
@@ -73,18 +72,18 @@ func (ta *testActor) Exports() []interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
func (ta *testActor) Constructor(rt runtime.Runtime, params *adt.EmptyValue) *adt.EmptyValue {
|
||||
func (ta *testActor) Constructor(rt runtime.Runtime, params *abi.EmptyValue) *abi.EmptyValue {
|
||||
rt.ValidateImmediateCallerAcceptAny()
|
||||
rt.State().Create(&testActorState{11})
|
||||
fmt.Println("NEW ACTOR ADDRESS IS: ", rt.Message().Receiver())
|
||||
rt.StateCreate(&testActorState{11})
|
||||
fmt.Println("NEW ACTOR ADDRESS IS: ", rt.Receiver())
|
||||
|
||||
return adt.Empty
|
||||
return abi.Empty
|
||||
}
|
||||
|
||||
func (ta *testActor) TestMethod(rt runtime.Runtime, params *adt.EmptyValue) *adt.EmptyValue {
|
||||
func (ta *testActor) TestMethod(rt runtime.Runtime, params *abi.EmptyValue) *abi.EmptyValue {
|
||||
rt.ValidateImmediateCallerAcceptAny()
|
||||
var st testActorState
|
||||
rt.State().Readonly(&st)
|
||||
rt.StateReadonly(&st)
|
||||
|
||||
if rt.CurrEpoch() > testForkHeight {
|
||||
if st.HasUpgraded != 55 {
|
||||
@@ -96,7 +95,7 @@ func (ta *testActor) TestMethod(rt runtime.Runtime, params *adt.EmptyValue) *adt
|
||||
}
|
||||
}
|
||||
|
||||
return adt.Empty
|
||||
return abi.Empty
|
||||
}
|
||||
|
||||
func TestForkHeightTriggers(t *testing.T) {
|
||||
|
||||
+12
-8
@@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
|
||||
@@ -233,8 +233,8 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
}
|
||||
|
||||
receipts = append(receipts, &r.MessageReceipt)
|
||||
gasReward = big.Add(gasReward, r.MinerTip)
|
||||
penalty = big.Add(penalty, r.Penalty)
|
||||
gasReward = big.Add(gasReward, r.GasCosts.MinerTip)
|
||||
penalty = big.Add(penalty, r.GasCosts.MinerPenalty)
|
||||
|
||||
if cb != nil {
|
||||
if err := cb(cm.Cid(), m, r); err != nil {
|
||||
@@ -1124,14 +1124,18 @@ func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.Cha
|
||||
return csi.FilCirculating, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) runtime.NetworkVersion {
|
||||
if build.UpgradeBreezeHeight == 0 {
|
||||
return runtime.NetworkVersion1
|
||||
func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) network.Version {
|
||||
if build.UseNewestNetwork() {
|
||||
return build.NewestNetworkVersion
|
||||
}
|
||||
|
||||
if height <= build.UpgradeBreezeHeight {
|
||||
return runtime.NetworkVersion0
|
||||
return network.Version0
|
||||
}
|
||||
|
||||
return runtime.NetworkVersion1
|
||||
if height <= build.UpgradeSmokeHeight {
|
||||
return network.Version1
|
||||
}
|
||||
|
||||
return build.NewestNetworkVersion
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ func GetPowerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr addres
|
||||
}
|
||||
|
||||
var claim power.Claim
|
||||
if _, err := cm.Get(adt.AddrKey(maddr), &claim); err != nil {
|
||||
if _, err := cm.Get(abi.AddrKey(maddr), &claim); err != nil {
|
||||
return power.Claim{}, power.Claim{}, err
|
||||
}
|
||||
|
||||
@@ -312,7 +312,7 @@ func GetMinerSlashed(ctx context.Context, sm *StateManager, ts *types.TipSet, ma
|
||||
return false, err
|
||||
}
|
||||
|
||||
ok, err := claims.Get(power.AddrKey(maddr), nil)
|
||||
ok, err := claims.Get(abi.AddrKey(maddr), nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -502,7 +502,7 @@ func GetLookbackTipSetForRound(ctx context.Context, sm *StateManager, ts *types.
|
||||
return lbts, nil
|
||||
}
|
||||
|
||||
func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBeacon, tsk types.TipSetKey, round abi.ChainEpoch, maddr address.Address, pv ffiwrapper.Verifier) (*api.MiningBaseInfo, error) {
|
||||
func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule, tsk types.TipSetKey, round abi.ChainEpoch, maddr address.Address, pv ffiwrapper.Verifier) (*api.MiningBaseInfo, error) {
|
||||
ts, err := sm.ChainStore().LoadTipSet(tsk)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load tipset for mining base: %w", err)
|
||||
@@ -517,7 +517,7 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBe
|
||||
prev = &types.BeaconEntry{}
|
||||
}
|
||||
|
||||
entries, err := beacon.BeaconEntriesForBlock(ctx, bcn, round, *prev)
|
||||
entries, err := beacon.BeaconEntriesForBlock(ctx, bcs, round, ts.Height(), *prev)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -554,7 +554,7 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBe
|
||||
|
||||
sectors, err := GetSectorsForWinningPoSt(ctx, pv, sm, lbst, maddr, prand)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting wpost proving set: %w", err)
|
||||
return nil, xerrors.Errorf("getting winning post proving set: %w", err)
|
||||
}
|
||||
|
||||
if len(sectors) == 0 {
|
||||
@@ -624,8 +624,8 @@ func init() {
|
||||
// Explicitly add send, it's special.
|
||||
methods[builtin.MethodSend] = MethodMeta{
|
||||
Name: "Send",
|
||||
Params: reflect.TypeOf(new(adt.EmptyValue)),
|
||||
Ret: reflect.TypeOf(new(adt.EmptyValue)),
|
||||
Params: reflect.TypeOf(new(abi.EmptyValue)),
|
||||
Ret: reflect.TypeOf(new(abi.EmptyValue)),
|
||||
}
|
||||
|
||||
// Learn method names from the builtin.Methods* structs.
|
||||
|
||||
+12
-6
@@ -11,14 +11,20 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func computeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int) types.BigInt {
|
||||
// deta := 1/PackingEfficiency * gasLimitUsed/noOfBlocks - build.BlockGasTarget
|
||||
// change := baseFee * deta / BlockGasTarget / BaseFeeMaxChangeDenom
|
||||
func ComputeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int, epoch abi.ChainEpoch) types.BigInt {
|
||||
// deta := gasLimitUsed/noOfBlocks - build.BlockGasTarget
|
||||
// change := baseFee * deta / BlockGasTarget
|
||||
// nextBaseFee = baseFee + change
|
||||
// nextBaseFee = max(nextBaseFee, build.MinimumBaseFee)
|
||||
|
||||
delta := build.PackingEfficiencyDenom * gasLimitUsed / (int64(noOfBlocks) * build.PackingEfficiencyNum)
|
||||
delta -= build.BlockGasTarget
|
||||
var delta int64
|
||||
if epoch > build.UpgradeSmokeHeight {
|
||||
delta = gasLimitUsed / int64(noOfBlocks)
|
||||
delta -= build.BlockGasTarget
|
||||
} else {
|
||||
delta = build.PackingEfficiencyDenom * gasLimitUsed / (int64(noOfBlocks) * build.PackingEfficiencyNum)
|
||||
delta -= build.BlockGasTarget
|
||||
}
|
||||
|
||||
// cap change at 12.5% (BaseFeeMaxChangeDenom) by capping delta
|
||||
if delta > build.BlockGasTarget {
|
||||
@@ -73,5 +79,5 @@ func (cs *ChainStore) ComputeBaseFee(ctx context.Context, ts *types.TipSet) (abi
|
||||
}
|
||||
parentBaseFee := ts.Blocks()[0].ParentBaseFee
|
||||
|
||||
return computeNextBaseFee(parentBaseFee, totalLimit, len(ts.Blocks())), nil
|
||||
return ComputeNextBaseFee(parentBaseFee, totalLimit, len(ts.Blocks()), ts.Height()), nil
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func TestBaseFee(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(fmt.Sprintf("%v", test), func(t *testing.T) {
|
||||
output := computeNextBaseFee(types.NewInt(test.basefee), test.limitUsed, test.noOfBlocks)
|
||||
output := ComputeNextBaseFee(types.NewInt(test.basefee), test.limitUsed, test.noOfBlocks, 0)
|
||||
assert.Equal(t, fmt.Sprintf("%d", test.output), output.String())
|
||||
})
|
||||
}
|
||||
|
||||
+42
-32
@@ -18,7 +18,6 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||
@@ -72,6 +71,20 @@ func init() {
|
||||
// ReorgNotifee represents a callback that gets called upon reorgs.
|
||||
type ReorgNotifee func(rev, app []*types.TipSet) error
|
||||
|
||||
// Journal event types.
|
||||
const (
|
||||
evtTypeHeadChange = iota
|
||||
)
|
||||
|
||||
type HeadChangeEvt struct {
|
||||
From types.TipSetKey
|
||||
FromHeight abi.ChainEpoch
|
||||
To types.TipSetKey
|
||||
ToHeight abi.ChainEpoch
|
||||
RevertCount int
|
||||
ApplyCount int
|
||||
}
|
||||
|
||||
// ChainStore is the main point of access to chain data.
|
||||
//
|
||||
// Raw chain data is stored in the Blockstore, with relevant markers (genesis,
|
||||
@@ -103,6 +116,8 @@ type ChainStore struct {
|
||||
tsCache *lru.ARCCache
|
||||
|
||||
vmcalls vm.SyscallBuilder
|
||||
|
||||
evtTypes [1]journal.EventType
|
||||
}
|
||||
|
||||
func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls vm.SyscallBuilder) *ChainStore {
|
||||
@@ -118,6 +133,10 @@ func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls vm.SyscallB
|
||||
vmcalls: vmcalls,
|
||||
}
|
||||
|
||||
cs.evtTypes = [1]journal.EventType{
|
||||
evtTypeHeadChange: journal.J.RegisterEventType("sync", "head_change"),
|
||||
}
|
||||
|
||||
ci := NewChainIndex(cs.LoadTipSet)
|
||||
|
||||
cs.cindex = ci
|
||||
@@ -344,12 +363,15 @@ func (cs *ChainStore) reorgWorker(ctx context.Context, initialNotifees []ReorgNo
|
||||
continue
|
||||
}
|
||||
|
||||
journal.Add("sync", map[string]interface{}{
|
||||
"op": "headChange",
|
||||
"from": r.old.Key(),
|
||||
"to": r.new.Key(),
|
||||
"rev": len(revert),
|
||||
"apply": len(apply),
|
||||
journal.J.RecordEvent(cs.evtTypes[evtTypeHeadChange], func() interface{} {
|
||||
return HeadChangeEvt{
|
||||
From: r.old.Key(),
|
||||
FromHeight: r.old.Height(),
|
||||
To: r.new.Key(),
|
||||
ToHeight: r.new.Height(),
|
||||
RevertCount: len(revert),
|
||||
ApplyCount: len(apply),
|
||||
}
|
||||
})
|
||||
|
||||
// reverse the apply array
|
||||
@@ -471,7 +493,7 @@ func (cs *ChainStore) IsAncestorOf(a, b *types.TipSet) (bool, error) {
|
||||
|
||||
cur := b
|
||||
for !a.Equals(cur) && cur.Height() > a.Height() {
|
||||
next, err := cs.LoadTipSet(b.Parents())
|
||||
next, err := cs.LoadTipSet(cur.Parents())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -744,32 +766,16 @@ type BlockMessages struct {
|
||||
func (cs *ChainStore) BlockMsgsForTipset(ts *types.TipSet) ([]BlockMessages, error) {
|
||||
applied := make(map[address.Address]uint64)
|
||||
|
||||
cst := cbor.NewCborStore(cs.bs)
|
||||
st, err := state.LoadStateTree(cst, ts.Blocks()[0].ParentStateRoot)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load state tree")
|
||||
}
|
||||
|
||||
preloadAddr := func(a address.Address) error {
|
||||
if _, ok := applied[a]; !ok {
|
||||
act, err := st.GetActor(a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
applied[a] = act.Nonce
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
selectMsg := func(m *types.Message) (bool, error) {
|
||||
if err := preloadAddr(m.From); err != nil {
|
||||
return false, err
|
||||
// The first match for a sender is guaranteed to have correct nonce -- the block isn't valid otherwise
|
||||
if _, ok := applied[m.From]; !ok {
|
||||
applied[m.From] = m.Nonce
|
||||
}
|
||||
|
||||
if applied[m.From] != m.Nonce {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
applied[m.From]++
|
||||
|
||||
return true, nil
|
||||
@@ -1159,7 +1165,7 @@ func recurseLinks(bs bstore.Blockstore, walked *cid.Set, root cid.Cid, in []cid.
|
||||
return in, rerr
|
||||
}
|
||||
|
||||
func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRoots abi.ChainEpoch, w io.Writer) error {
|
||||
func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRoots abi.ChainEpoch, skipOldMsgs bool, w io.Writer) error {
|
||||
if ts == nil {
|
||||
ts = cs.GetHeaviestTipSet()
|
||||
}
|
||||
@@ -1197,9 +1203,13 @@ func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRo
|
||||
return xerrors.Errorf("unmarshaling block header (cid=%s): %w", blk, err)
|
||||
}
|
||||
|
||||
cids, err := recurseLinks(cs.bs, walked, b.Messages, []cid.Cid{b.Messages})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("recursing messages failed: %w", err)
|
||||
var cids []cid.Cid
|
||||
if !skipOldMsgs || b.Height > ts.Height()-inclRecentRoots {
|
||||
mcids, err := recurseLinks(cs.bs, walked, b.Messages, []cid.Cid{b.Messages})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("recursing messages failed: %w", err)
|
||||
}
|
||||
cids = mcids
|
||||
}
|
||||
|
||||
if b.Height > 0 {
|
||||
|
||||
@@ -96,7 +96,7 @@ func TestChainExportImport(t *testing.T) {
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if err := cg.ChainStore().Export(context.TODO(), last, 0, buf); err != nil {
|
||||
if err := cg.ChainStore().Export(context.TODO(), last, 0, false, buf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
+23
-20
@@ -58,7 +58,14 @@ import (
|
||||
// the theoretical max height based on systime are quickly rejected
|
||||
const MaxHeightDrift = 5
|
||||
|
||||
var defaultMessageFetchWindowSize = 200
|
||||
var (
|
||||
// LocalIncoming is the _local_ pubsub (unrelated to libp2p pubsub) topic
|
||||
// where the Syncer publishes candidate chain heads to be synced.
|
||||
LocalIncoming = "incoming"
|
||||
|
||||
log = logging.Logger("chain")
|
||||
defaultMessageFetchWindowSize = 200
|
||||
)
|
||||
|
||||
func init() {
|
||||
if s := os.Getenv("LOTUS_BSYNC_MSG_WINDOW"); s != "" {
|
||||
@@ -71,10 +78,6 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
//
|
||||
@@ -103,7 +106,7 @@ type Syncer struct {
|
||||
store *store.ChainStore
|
||||
|
||||
// handle to the random beacon for verification
|
||||
beacon beacon.RandomBeacon
|
||||
beacon beacon.Schedule
|
||||
|
||||
// the state manager handles making state queries
|
||||
sm *stmgr.StateManager
|
||||
@@ -119,7 +122,7 @@ type Syncer struct {
|
||||
|
||||
self peer.ID
|
||||
|
||||
syncmgr *SyncManager
|
||||
syncmgr SyncManager
|
||||
|
||||
connmgr connmgr.ConnManager
|
||||
|
||||
@@ -140,8 +143,10 @@ type Syncer struct {
|
||||
ds dtypes.MetadataDS
|
||||
}
|
||||
|
||||
type SyncManagerCtor func(syncFn SyncFunc) SyncManager
|
||||
|
||||
// NewSyncer creates a new Syncer object.
|
||||
func NewSyncer(ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*Syncer, error) {
|
||||
func NewSyncer(ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, syncMgrCtor SyncManagerCtor, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.Schedule, verifier ffiwrapper.Verifier) (*Syncer, error) {
|
||||
gen, err := sm.ChainStore().GetGenesis()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting genesis block: %w", err)
|
||||
@@ -181,7 +186,7 @@ func NewSyncer(ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.C
|
||||
log.Warn("*********************************************************************************************")
|
||||
}
|
||||
|
||||
s.syncmgr = NewSyncManager(s.Sync)
|
||||
s.syncmgr = syncMgrCtor(s.Sync)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
@@ -648,7 +653,7 @@ func (syncer *Syncer) minerIsValid(ctx context.Context, maddr address.Address, b
|
||||
}
|
||||
|
||||
var claim power.Claim
|
||||
exist, err := cm.Get(adt.AddrKey(maddr), &claim)
|
||||
exist, err := cm.Get(abi.AddrKey(maddr), &claim)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -879,7 +884,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := beacon.ValidateBlockValues(syncer.beacon, h, *prevBeacon); err != nil {
|
||||
if err := beacon.ValidateBlockValues(syncer.beacon, h, baseTs.Height(), *prevBeacon); err != nil {
|
||||
return xerrors.Errorf("failed to validate blocks random beacon values: %w", err)
|
||||
}
|
||||
return nil
|
||||
@@ -891,10 +896,12 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
|
||||
return xerrors.Errorf("failed to marshal miner address to cbor: %w", err)
|
||||
}
|
||||
|
||||
beaconBase := *prevBeacon
|
||||
if len(h.BeaconEntries) == 0 {
|
||||
if h.Height > build.UpgradeSmokeHeight {
|
||||
buf.Write(baseTs.MinTicket().VRFProof)
|
||||
} else {
|
||||
}
|
||||
|
||||
beaconBase := *prevBeacon
|
||||
if len(h.BeaconEntries) != 0 {
|
||||
beaconBase = h.BeaconEntries[len(h.BeaconEntries)-1]
|
||||
}
|
||||
|
||||
@@ -984,7 +991,7 @@ func (syncer *Syncer) VerifyWinningPoStProof(ctx context.Context, h *types.Block
|
||||
|
||||
rand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, h.Height, buf.Bytes())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get randomness for verifying winningPost proof: %w", err)
|
||||
return xerrors.Errorf("failed to get randomness for verifying winning post proof: %w", err)
|
||||
}
|
||||
|
||||
mid, err := address.IDFromAddress(h.Miner)
|
||||
@@ -1663,11 +1670,7 @@ func VerifyElectionPoStVRF(ctx context.Context, worker address.Address, rand []b
|
||||
}
|
||||
|
||||
func (syncer *Syncer) State() []SyncerState {
|
||||
var out []SyncerState
|
||||
for _, ss := range syncer.syncmgr.syncStates {
|
||||
out = append(out, ss.Snapshot())
|
||||
}
|
||||
return out
|
||||
return syncer.syncmgr.State()
|
||||
}
|
||||
|
||||
// MarkBad manually adds a block to the "bad blocks" cache.
|
||||
|
||||
+48
-16
@@ -20,7 +20,28 @@ const (
|
||||
|
||||
type SyncFunc func(context.Context, *types.TipSet) error
|
||||
|
||||
type SyncManager struct {
|
||||
// SyncManager manages the chain synchronization process, both at bootstrap time
|
||||
// and during ongoing operation.
|
||||
//
|
||||
// It receives candidate chain heads in the form of tipsets from peers,
|
||||
// and schedules them onto sync workers, deduplicating processing for
|
||||
// already-active syncs.
|
||||
type SyncManager interface {
|
||||
// Start starts the SyncManager.
|
||||
Start()
|
||||
|
||||
// Stop stops the SyncManager.
|
||||
Stop()
|
||||
|
||||
// SetPeerHead informs the SyncManager that the supplied peer reported the
|
||||
// supplied tipset.
|
||||
SetPeerHead(ctx context.Context, p peer.ID, ts *types.TipSet)
|
||||
|
||||
// State retrieves the state of the sync workers.
|
||||
State() []SyncerState
|
||||
}
|
||||
|
||||
type syncManager struct {
|
||||
lk sync.Mutex
|
||||
peerHeads map[peer.ID]*types.TipSet
|
||||
|
||||
@@ -48,6 +69,8 @@ type SyncManager struct {
|
||||
workerChan chan *types.TipSet
|
||||
}
|
||||
|
||||
var _ SyncManager = (*syncManager)(nil)
|
||||
|
||||
type syncResult struct {
|
||||
ts *types.TipSet
|
||||
success bool
|
||||
@@ -55,8 +78,8 @@ type syncResult struct {
|
||||
|
||||
const syncWorkerCount = 3
|
||||
|
||||
func NewSyncManager(sync SyncFunc) *SyncManager {
|
||||
return &SyncManager{
|
||||
func NewSyncManager(sync SyncFunc) SyncManager {
|
||||
return &syncManager{
|
||||
bspThresh: 1,
|
||||
peerHeads: make(map[peer.ID]*types.TipSet),
|
||||
syncTargets: make(chan *types.TipSet),
|
||||
@@ -69,18 +92,18 @@ func NewSyncManager(sync SyncFunc) *SyncManager {
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *SyncManager) Start() {
|
||||
func (sm *syncManager) Start() {
|
||||
go sm.syncScheduler()
|
||||
for i := 0; i < syncWorkerCount; i++ {
|
||||
go sm.syncWorker(i)
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *SyncManager) Stop() {
|
||||
func (sm *syncManager) Stop() {
|
||||
close(sm.stop)
|
||||
}
|
||||
|
||||
func (sm *SyncManager) SetPeerHead(ctx context.Context, p peer.ID, ts *types.TipSet) {
|
||||
func (sm *syncManager) SetPeerHead(ctx context.Context, p peer.ID, ts *types.TipSet) {
|
||||
sm.lk.Lock()
|
||||
defer sm.lk.Unlock()
|
||||
sm.peerHeads[p] = ts
|
||||
@@ -105,6 +128,14 @@ func (sm *SyncManager) SetPeerHead(ctx context.Context, p peer.ID, ts *types.Tip
|
||||
sm.incomingTipSets <- ts
|
||||
}
|
||||
|
||||
func (sm *syncManager) State() []SyncerState {
|
||||
ret := make([]SyncerState, 0, len(sm.syncStates))
|
||||
for _, s := range sm.syncStates {
|
||||
ret = append(ret, s.Snapshot())
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type syncBucketSet struct {
|
||||
buckets []*syncTargetBucket
|
||||
}
|
||||
@@ -234,7 +265,7 @@ func (stb *syncTargetBucket) heaviestTipSet() *types.TipSet {
|
||||
return best
|
||||
}
|
||||
|
||||
func (sm *SyncManager) selectSyncTarget() (*types.TipSet, error) {
|
||||
func (sm *syncManager) selectSyncTarget() (*types.TipSet, error) {
|
||||
var buckets syncBucketSet
|
||||
|
||||
var peerHeads []*types.TipSet
|
||||
@@ -258,7 +289,7 @@ func (sm *SyncManager) selectSyncTarget() (*types.TipSet, error) {
|
||||
return buckets.Heaviest(), nil
|
||||
}
|
||||
|
||||
func (sm *SyncManager) syncScheduler() {
|
||||
func (sm *syncManager) syncScheduler() {
|
||||
|
||||
for {
|
||||
select {
|
||||
@@ -280,7 +311,7 @@ func (sm *SyncManager) syncScheduler() {
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *SyncManager) scheduleIncoming(ts *types.TipSet) {
|
||||
func (sm *syncManager) scheduleIncoming(ts *types.TipSet) {
|
||||
log.Debug("scheduling incoming tipset sync: ", ts.Cids())
|
||||
if sm.getBootstrapState() == BSStateSelected {
|
||||
sm.setBootstrapState(BSStateScheduled)
|
||||
@@ -328,10 +359,11 @@ func (sm *SyncManager) scheduleIncoming(ts *types.TipSet) {
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *SyncManager) scheduleProcessResult(res *syncResult) {
|
||||
func (sm *syncManager) scheduleProcessResult(res *syncResult) {
|
||||
if res.success && sm.getBootstrapState() != BSStateComplete {
|
||||
sm.setBootstrapState(BSStateComplete)
|
||||
}
|
||||
|
||||
delete(sm.activeSyncs, res.ts.Key())
|
||||
relbucket := sm.activeSyncTips.PopRelated(res.ts)
|
||||
if relbucket != nil {
|
||||
@@ -360,7 +392,7 @@ func (sm *SyncManager) scheduleProcessResult(res *syncResult) {
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *SyncManager) scheduleWorkSent() {
|
||||
func (sm *syncManager) scheduleWorkSent() {
|
||||
hts := sm.nextSyncTarget.heaviestTipSet()
|
||||
sm.activeSyncs[hts.Key()] = hts
|
||||
|
||||
@@ -372,7 +404,7 @@ func (sm *SyncManager) scheduleWorkSent() {
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *SyncManager) syncWorker(id int) {
|
||||
func (sm *syncManager) syncWorker(id int) {
|
||||
ss := &SyncerState{}
|
||||
sm.syncStates[id] = ss
|
||||
for {
|
||||
@@ -397,7 +429,7 @@ func (sm *SyncManager) syncWorker(id int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *SyncManager) syncedPeerCount() int {
|
||||
func (sm *syncManager) syncedPeerCount() int {
|
||||
var count int
|
||||
for _, ts := range sm.peerHeads {
|
||||
if ts.Height() > 0 {
|
||||
@@ -407,19 +439,19 @@ func (sm *SyncManager) syncedPeerCount() int {
|
||||
return count
|
||||
}
|
||||
|
||||
func (sm *SyncManager) getBootstrapState() int {
|
||||
func (sm *syncManager) getBootstrapState() int {
|
||||
sm.bssLk.Lock()
|
||||
defer sm.bssLk.Unlock()
|
||||
return sm.bootstrapState
|
||||
}
|
||||
|
||||
func (sm *SyncManager) setBootstrapState(v int) {
|
||||
func (sm *syncManager) setBootstrapState(v int) {
|
||||
sm.bssLk.Lock()
|
||||
defer sm.bssLk.Unlock()
|
||||
sm.bootstrapState = v
|
||||
}
|
||||
|
||||
func (sm *SyncManager) IsBootstrapped() bool {
|
||||
func (sm *syncManager) IsBootstrapped() bool {
|
||||
sm.bssLk.Lock()
|
||||
defer sm.bssLk.Unlock()
|
||||
return sm.bootstrapState == BSStateComplete
|
||||
|
||||
@@ -17,7 +17,7 @@ type syncOp struct {
|
||||
done func()
|
||||
}
|
||||
|
||||
func runSyncMgrTest(t *testing.T, tname string, thresh int, tf func(*testing.T, *SyncManager, chan *syncOp)) {
|
||||
func runSyncMgrTest(t *testing.T, tname string, thresh int, tf func(*testing.T, *syncManager, chan *syncOp)) {
|
||||
syncTargets := make(chan *syncOp)
|
||||
sm := NewSyncManager(func(ctx context.Context, ts *types.TipSet) error {
|
||||
ch := make(chan struct{})
|
||||
@@ -27,7 +27,7 @@ func runSyncMgrTest(t *testing.T, tname string, thresh int, tf func(*testing.T,
|
||||
}
|
||||
<-ch
|
||||
return nil
|
||||
})
|
||||
}).(*syncManager)
|
||||
sm.bspThresh = thresh
|
||||
|
||||
sm.Start()
|
||||
@@ -77,12 +77,12 @@ func TestSyncManager(t *testing.T) {
|
||||
c3 := mock.TipSet(mock.MkBlock(b, 3, 5))
|
||||
d := mock.TipSet(mock.MkBlock(c1, 4, 5))
|
||||
|
||||
runSyncMgrTest(t, "testBootstrap", 1, func(t *testing.T, sm *SyncManager, stc chan *syncOp) {
|
||||
runSyncMgrTest(t, "testBootstrap", 1, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
||||
sm.SetPeerHead(ctx, "peer1", c1)
|
||||
assertGetSyncOp(t, stc, c1)
|
||||
})
|
||||
|
||||
runSyncMgrTest(t, "testBootstrap", 2, func(t *testing.T, sm *SyncManager, stc chan *syncOp) {
|
||||
runSyncMgrTest(t, "testBootstrap", 2, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
||||
sm.SetPeerHead(ctx, "peer1", c1)
|
||||
assertNoOp(t, stc)
|
||||
|
||||
@@ -90,7 +90,7 @@ func TestSyncManager(t *testing.T) {
|
||||
assertGetSyncOp(t, stc, c1)
|
||||
})
|
||||
|
||||
runSyncMgrTest(t, "testSyncAfterBootstrap", 1, func(t *testing.T, sm *SyncManager, stc chan *syncOp) {
|
||||
runSyncMgrTest(t, "testSyncAfterBootstrap", 1, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
||||
sm.SetPeerHead(ctx, "peer1", b)
|
||||
assertGetSyncOp(t, stc, b)
|
||||
|
||||
@@ -101,7 +101,7 @@ func TestSyncManager(t *testing.T) {
|
||||
assertGetSyncOp(t, stc, c2)
|
||||
})
|
||||
|
||||
runSyncMgrTest(t, "testCoalescing", 1, func(t *testing.T, sm *SyncManager, stc chan *syncOp) {
|
||||
runSyncMgrTest(t, "testCoalescing", 1, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
||||
sm.SetPeerHead(ctx, "peer1", a)
|
||||
assertGetSyncOp(t, stc, a)
|
||||
|
||||
@@ -122,7 +122,7 @@ func TestSyncManager(t *testing.T) {
|
||||
assertGetSyncOp(t, stc, d)
|
||||
})
|
||||
|
||||
runSyncMgrTest(t, "testSyncIncomingTipset", 1, func(t *testing.T, sm *SyncManager, stc chan *syncOp) {
|
||||
runSyncMgrTest(t, "testSyncIncomingTipset", 1, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
||||
sm.SetPeerHead(ctx, "peer1", a)
|
||||
assertGetSyncOp(t, stc, a)
|
||||
|
||||
|
||||
+86
-1
@@ -662,6 +662,49 @@ func TestDuplicateNonce(t *testing.T) {
|
||||
require.Equal(t, includedMsg, mft[0].VMMessage().Cid(), "messages for tipset didn't contain expected message")
|
||||
}
|
||||
|
||||
// This test asserts that a block that includes a message with bad nonce can't be synced. A nonce is "bad" if it can't
|
||||
// be applied on the parent state.
|
||||
func TestBadNonce(t *testing.T) {
|
||||
H := 10
|
||||
tu := prepSyncTest(t, H)
|
||||
|
||||
base := tu.g.CurTipset
|
||||
|
||||
// Produce a message from the banker with a bad nonce
|
||||
makeBadMsg := func() *types.SignedMessage {
|
||||
|
||||
ba, err := tu.nds[0].StateGetActor(context.TODO(), tu.g.Banker(), base.TipSet().Key())
|
||||
require.NoError(t, err)
|
||||
msg := types.Message{
|
||||
To: tu.g.Banker(),
|
||||
From: tu.g.Banker(),
|
||||
|
||||
Nonce: ba.Nonce + 5,
|
||||
|
||||
Value: types.NewInt(1),
|
||||
|
||||
Method: 0,
|
||||
|
||||
GasLimit: 100_000_000,
|
||||
GasFeeCap: types.NewInt(0),
|
||||
GasPremium: types.NewInt(0),
|
||||
}
|
||||
|
||||
sig, err := tu.g.Wallet().Sign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes())
|
||||
require.NoError(t, err)
|
||||
|
||||
return &types.SignedMessage{
|
||||
Message: msg,
|
||||
Signature: *sig,
|
||||
}
|
||||
}
|
||||
|
||||
msgs := make([][]*types.SignedMessage, 1)
|
||||
msgs[0] = []*types.SignedMessage{makeBadMsg()}
|
||||
|
||||
tu.mineOnBlock(base, 0, []int{0}, true, true, msgs)
|
||||
}
|
||||
|
||||
func BenchmarkSyncBasic(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
runSyncBenchLength(b, 100)
|
||||
@@ -709,7 +752,7 @@ func TestSyncInputs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyncCheckpoint(t *testing.T) {
|
||||
func TestSyncCheckpointHead(t *testing.T) {
|
||||
H := 10
|
||||
tu := prepSyncTest(t, H)
|
||||
|
||||
@@ -750,3 +793,45 @@ func TestSyncCheckpoint(t *testing.T) {
|
||||
require.Equal(tu.t, p1Head, a.TipSet())
|
||||
tu.assertBad(p1, b.TipSet())
|
||||
}
|
||||
|
||||
func TestSyncCheckpointEarlierThanHead(t *testing.T) {
|
||||
H := 10
|
||||
tu := prepSyncTest(t, H)
|
||||
|
||||
p1 := tu.addClientNode()
|
||||
p2 := tu.addClientNode()
|
||||
|
||||
fmt.Println("GENESIS: ", tu.g.Genesis().Cid())
|
||||
tu.loadChainToNode(p1)
|
||||
tu.loadChainToNode(p2)
|
||||
|
||||
base := tu.g.CurTipset
|
||||
fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height())
|
||||
|
||||
// The two nodes fork at this point into 'a' and 'b'
|
||||
a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil)
|
||||
a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil)
|
||||
a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil)
|
||||
|
||||
tu.waitUntilSyncTarget(p1, a.TipSet())
|
||||
tu.checkpointTs(p1, a1.TipSet().Key())
|
||||
|
||||
require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet()))
|
||||
// chain B will now be heaviest
|
||||
b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil)
|
||||
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil)
|
||||
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil)
|
||||
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil)
|
||||
|
||||
fmt.Println("A: ", a.Cids(), a.TipSet().Height())
|
||||
fmt.Println("B: ", b.Cids(), b.TipSet().Height())
|
||||
|
||||
// Now for the fun part!! p1 should mark p2's head as BAD.
|
||||
|
||||
require.NoError(t, tu.mn.LinkAll())
|
||||
tu.connect(p1, p2)
|
||||
tu.waitUntilNodeHasTs(p1, b.TipSet().Key())
|
||||
p1Head := tu.getHead(p1)
|
||||
require.Equal(tu.t, p1Head, a.TipSet())
|
||||
tu.assertBad(p1, b.TipSet())
|
||||
}
|
||||
|
||||
+12
-7
@@ -22,6 +22,17 @@ type GasOutputs struct {
|
||||
GasBurned int64
|
||||
}
|
||||
|
||||
// ZeroGasOutputs returns a logically zeroed GasOutputs.
|
||||
func ZeroGasOutputs() GasOutputs {
|
||||
return GasOutputs{
|
||||
BaseFeeBurn: big.Zero(),
|
||||
OverEstimationBurn: big.Zero(),
|
||||
MinerPenalty: big.Zero(),
|
||||
MinerTip: big.Zero(),
|
||||
Refund: big.Zero(),
|
||||
}
|
||||
}
|
||||
|
||||
// ComputeGasOverestimationBurn computes amount of gas to be refunded and amount of gas to be burned
|
||||
// Result is (refund, burn)
|
||||
func ComputeGasOverestimationBurn(gasUsed, gasLimit int64) (int64, int64) {
|
||||
@@ -58,13 +69,7 @@ func ComputeGasOverestimationBurn(gasUsed, gasLimit int64) (int64, int64) {
|
||||
|
||||
func ComputeGasOutputs(gasUsed, gasLimit int64, baseFee, feeCap, gasPremium abi.TokenAmount) GasOutputs {
|
||||
gasUsedBig := big.NewInt(gasUsed)
|
||||
out := GasOutputs{
|
||||
BaseFeeBurn: big.Zero(),
|
||||
OverEstimationBurn: big.Zero(),
|
||||
MinerPenalty: big.Zero(),
|
||||
MinerTip: big.Zero(),
|
||||
Refund: big.Zero(),
|
||||
}
|
||||
out := ZeroGasOutputs()
|
||||
|
||||
baseFeeToPay := baseFee
|
||||
if baseFee.Cmp(feeCap.Int) > 0 {
|
||||
|
||||
+3
-5
@@ -15,6 +15,7 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/cron"
|
||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
@@ -27,9 +28,6 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/system"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
vmr "github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||
)
|
||||
|
||||
type Invoker struct {
|
||||
@@ -47,7 +45,7 @@ func NewInvoker() *Invoker {
|
||||
}
|
||||
|
||||
// add builtInCode using: register(cid, singleton)
|
||||
inv.Register(builtin.SystemActorCodeID, system.Actor{}, adt.EmptyValue{})
|
||||
inv.Register(builtin.SystemActorCodeID, system.Actor{}, abi.EmptyValue{})
|
||||
inv.Register(builtin.InitActorCodeID, init_.Actor{}, init_.State{})
|
||||
inv.Register(builtin.RewardActorCodeID, reward.Actor{}, reward.State{})
|
||||
inv.Register(builtin.CronActorCodeID, cron.Actor{}, cron.State{})
|
||||
@@ -66,7 +64,7 @@ func (inv *Invoker) Invoke(codeCid cid.Cid, rt runtime.Runtime, method abi.Metho
|
||||
|
||||
code, ok := inv.builtInCode[codeCid]
|
||||
if !ok {
|
||||
log.Errorf("no code for actor %s (Addr: %s)", codeCid, rt.Message().Receiver())
|
||||
log.Errorf("no code for actor %s (Addr: %s)", codeCid, rt.Receiver())
|
||||
return nil, aerrors.Newf(exitcode.SysErrorIllegalActor, "no code for actor %s(%d)(%s)", codeCid, method, hex.EncodeToString(params))
|
||||
}
|
||||
if method >= abi.MethodNum(len(code)) || code[method] == nil {
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
"github.com/stretchr/testify/assert"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
@@ -13,7 +15,6 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
)
|
||||
|
||||
type basicContract struct{}
|
||||
@@ -60,17 +61,17 @@ func (b basicContract) Exports() []interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
func (basicContract) InvokeSomething0(rt runtime.Runtime, params *basicParams) *adt.EmptyValue {
|
||||
func (basicContract) InvokeSomething0(rt runtime.Runtime, params *basicParams) *abi.EmptyValue {
|
||||
rt.Abortf(exitcode.ExitCode(params.B), "params.B")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (basicContract) BadParam(rt runtime.Runtime, params *basicParams) *adt.EmptyValue {
|
||||
func (basicContract) BadParam(rt runtime.Runtime, params *basicParams) *abi.EmptyValue {
|
||||
rt.Abortf(255, "bad params")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (basicContract) InvokeSomething10(rt runtime.Runtime, params *basicParams) *adt.EmptyValue {
|
||||
func (basicContract) InvokeSomething10(rt runtime.Runtime, params *basicParams) *abi.EmptyValue {
|
||||
rt.Abortf(exitcode.ExitCode(params.B+10), "params.B")
|
||||
return nil
|
||||
}
|
||||
|
||||
+58
-73
@@ -8,18 +8,19 @@ import (
|
||||
gruntime "runtime"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
rtt "github.com/filecoin-project/go-state-types/rt"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
vmr "github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
rt0 "github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
ipldcbor "github.com/ipfs/go-ipld-cbor"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@@ -30,20 +31,20 @@ import (
|
||||
)
|
||||
|
||||
type Runtime struct {
|
||||
types.Message
|
||||
rt0.Syscalls
|
||||
|
||||
ctx context.Context
|
||||
|
||||
vm *VM
|
||||
state *state.StateTree
|
||||
vmsg vmr.Message
|
||||
height abi.ChainEpoch
|
||||
cst cbor.IpldStore
|
||||
cst ipldcbor.IpldStore
|
||||
pricelist Pricelist
|
||||
|
||||
gasAvailable int64
|
||||
gasUsed int64
|
||||
|
||||
sys runtime.Syscalls
|
||||
|
||||
// address that started invoke chain
|
||||
origin address.Address
|
||||
originNonce uint64
|
||||
@@ -56,7 +57,7 @@ type Runtime struct {
|
||||
lastGasCharge *types.GasTrace
|
||||
}
|
||||
|
||||
func (rt *Runtime) NetworkVersion() vmr.NetworkVersion {
|
||||
func (rt *Runtime) NetworkVersion() network.Version {
|
||||
return rt.vm.GetNtwkVersion(rt.ctx, rt.CurrEpoch())
|
||||
}
|
||||
|
||||
@@ -84,11 +85,11 @@ type notFoundErr interface {
|
||||
IsNotFound() bool
|
||||
}
|
||||
|
||||
func (rt *Runtime) Get(c cid.Cid, o vmr.CBORUnmarshaler) bool {
|
||||
func (rt *Runtime) StoreGet(c cid.Cid, o cbor.Unmarshaler) bool {
|
||||
if err := rt.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)) {
|
||||
if xerrors.As(err, new(ipldcbor.SerializationError)) {
|
||||
panic(aerrors.Newf(exitcode.ErrSerialization, "failed to unmarshal cbor object %s", err))
|
||||
}
|
||||
return false
|
||||
@@ -99,10 +100,10 @@ func (rt *Runtime) Get(c cid.Cid, o vmr.CBORUnmarshaler) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (rt *Runtime) Put(x vmr.CBORMarshaler) cid.Cid {
|
||||
func (rt *Runtime) StorePut(x cbor.Marshaler) cid.Cid {
|
||||
c, err := rt.cst.Put(context.TODO(), x)
|
||||
if err != nil {
|
||||
if xerrors.As(err, new(cbor.SerializationError)) {
|
||||
if xerrors.As(err, new(ipldcbor.SerializationError)) {
|
||||
panic(aerrors.Newf(exitcode.ErrSerialization, "failed to marshal cbor object %s", err))
|
||||
}
|
||||
panic(aerrors.Fatalf("failed to put cbor object: %s", err))
|
||||
@@ -110,7 +111,7 @@ func (rt *Runtime) Put(x vmr.CBORMarshaler) cid.Cid {
|
||||
return c
|
||||
}
|
||||
|
||||
var _ vmr.Runtime = (*Runtime)(nil)
|
||||
var _ rt0.Runtime = (*Runtime)(nil)
|
||||
|
||||
func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.ActorError) {
|
||||
defer func() {
|
||||
@@ -136,9 +137,9 @@ func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act
|
||||
switch ret := ret.(type) {
|
||||
case []byte:
|
||||
return ret, nil
|
||||
case *adt.EmptyValue:
|
||||
case *abi.EmptyValue:
|
||||
return nil, nil
|
||||
case cbg.CBORMarshaler:
|
||||
case cbor.Marshaler:
|
||||
buf := new(bytes.Buffer)
|
||||
if err := ret.MarshalCBOR(buf); err != nil {
|
||||
return nil, aerrors.Absorb(err, 2, "failed to marshal response to cbor")
|
||||
@@ -151,17 +152,13 @@ func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *Runtime) Message() vmr.Message {
|
||||
return rt.vmsg
|
||||
}
|
||||
|
||||
func (rt *Runtime) ValidateImmediateCallerAcceptAny() {
|
||||
rt.abortIfAlreadyValidated()
|
||||
return
|
||||
}
|
||||
|
||||
func (rt *Runtime) CurrentBalance() abi.TokenAmount {
|
||||
b, err := rt.GetBalance(rt.Message().Receiver())
|
||||
b, err := rt.GetBalance(rt.Receiver())
|
||||
if err != nil {
|
||||
rt.Abortf(err.RetCode(), "get current balance: %v", err)
|
||||
}
|
||||
@@ -197,10 +194,6 @@ func (rt *Runtime) GetRandomnessFromBeacon(personalization crypto.DomainSeparati
|
||||
return res
|
||||
}
|
||||
|
||||
func (rt *Runtime) Store() vmr.Store {
|
||||
return rt
|
||||
}
|
||||
|
||||
func (rt *Runtime) NewActorAddress() address.Address {
|
||||
var b bytes.Buffer
|
||||
oa, _ := ResolveToKeyAddr(rt.vm.cstate, rt.vm.cst, rt.origin)
|
||||
@@ -257,7 +250,7 @@ func (rt *Runtime) CreateActor(codeID cid.Cid, address address.Address) {
|
||||
// May only be called by the actor itself.
|
||||
func (rt *Runtime) DeleteActor(beneficiary address.Address) {
|
||||
rt.chargeGas(rt.Pricelist().OnDeleteActor())
|
||||
act, err := rt.state.GetActor(rt.Message().Receiver())
|
||||
act, err := rt.state.GetActor(rt.Receiver())
|
||||
if err != nil {
|
||||
if xerrors.Is(err, types.ErrActorNotFound) {
|
||||
rt.Abortf(exitcode.SysErrorIllegalActor, "failed to load actor in delete actor: %s", err)
|
||||
@@ -266,36 +259,32 @@ func (rt *Runtime) DeleteActor(beneficiary address.Address) {
|
||||
}
|
||||
if !act.Balance.IsZero() {
|
||||
// Transfer the executing actor's balance to the beneficiary
|
||||
if err := rt.vm.transfer(rt.Message().Receiver(), beneficiary, act.Balance); err != nil {
|
||||
if err := rt.vm.transfer(rt.Receiver(), beneficiary, act.Balance); err != nil {
|
||||
panic(aerrors.Fatalf("failed to transfer balance to beneficiary actor: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the executing actor
|
||||
if err := rt.state.DeleteActor(rt.Message().Receiver()); err != nil {
|
||||
if err := rt.state.DeleteActor(rt.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 (rt *Runtime) StartSpan(name string) vmr.TraceSpan {
|
||||
func (rt *Runtime) StartSpan(name string) func() {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (rt *Runtime) ValidateImmediateCallerIs(as ...address.Address) {
|
||||
rt.abortIfAlreadyValidated()
|
||||
imm := rt.Message().Caller()
|
||||
imm := rt.Caller()
|
||||
|
||||
for _, a := range as {
|
||||
if imm == a {
|
||||
return
|
||||
}
|
||||
}
|
||||
rt.Abortf(exitcode.SysErrForbidden, "caller %s is not one of %s", rt.Message().Caller(), as)
|
||||
rt.Abortf(exitcode.SysErrForbidden, "caller %s is not one of %s", rt.Caller(), as)
|
||||
}
|
||||
|
||||
func (rt *Runtime) Context() context.Context {
|
||||
@@ -313,7 +302,7 @@ func (rt *Runtime) AbortStateMsg(msg string) {
|
||||
|
||||
func (rt *Runtime) ValidateImmediateCallerType(ts ...cid.Cid) {
|
||||
rt.abortIfAlreadyValidated()
|
||||
callerCid, ok := rt.GetActorCodeCID(rt.Message().Caller())
|
||||
callerCid, ok := rt.GetActorCodeCID(rt.Caller())
|
||||
if !ok {
|
||||
panic(aerrors.Fatalf("failed to lookup code cid for caller"))
|
||||
}
|
||||
@@ -333,11 +322,11 @@ type dumbWrapperType struct {
|
||||
val []byte
|
||||
}
|
||||
|
||||
func (dwt *dumbWrapperType) Into(um vmr.CBORUnmarshaler) error {
|
||||
func (dwt *dumbWrapperType) Into(um cbor.Unmarshaler) 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) {
|
||||
func (rt *Runtime) Send(to address.Address, method abi.MethodNum, m cbor.Marshaler, value abi.TokenAmount, out cbor.Er) exitcode.ExitCode {
|
||||
if !rt.allowInternal {
|
||||
rt.Abortf(exitcode.SysErrorIllegalActor, "runtime.Send() is currently disallowed")
|
||||
}
|
||||
@@ -350,16 +339,20 @@ func (rt *Runtime) Send(to address.Address, method abi.MethodNum, m vmr.CBORMars
|
||||
params = buf.Bytes()
|
||||
}
|
||||
|
||||
ret, err := rt.internalSend(rt.Message().Receiver(), to, method, value, params)
|
||||
ret, err := rt.internalSend(rt.Receiver(), to, method, 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 &dumbWrapperType{nil}, err.RetCode()
|
||||
return err.RetCode()
|
||||
}
|
||||
_ = rt.chargeGasSafe(gasOnActorExec)
|
||||
return &dumbWrapperType{ret}, 0
|
||||
|
||||
if err := out.UnmarshalCBOR(bytes.NewReader(ret)); err != nil {
|
||||
rt.Abortf(exitcode.ErrSerialization, "failed to unmarshal return value: %s", err)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum, value types.BigInt, params []byte) ([]byte, aerrors.ActorError) {
|
||||
@@ -403,49 +396,41 @@ func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum,
|
||||
return ret, errSend
|
||||
}
|
||||
|
||||
func (rt *Runtime) State() vmr.StateHandle {
|
||||
return &shimStateHandle{rt: rt}
|
||||
}
|
||||
|
||||
type shimStateHandle struct {
|
||||
rt *Runtime
|
||||
}
|
||||
|
||||
func (ssh *shimStateHandle) Create(obj vmr.CBORMarshaler) {
|
||||
c := ssh.rt.Put(obj)
|
||||
err := ssh.rt.stateCommit(EmptyObjectCid, c)
|
||||
func (rt *Runtime) StateCreate(obj cbor.Marshaler) {
|
||||
c := rt.StorePut(obj)
|
||||
err := rt.stateCommit(EmptyObjectCid, c)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to commit state after creating object: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
func (ssh *shimStateHandle) Readonly(obj vmr.CBORUnmarshaler) {
|
||||
act, err := ssh.rt.state.GetActor(ssh.rt.Message().Receiver())
|
||||
func (rt *Runtime) StateReadonly(obj cbor.Unmarshaler) {
|
||||
act, err := rt.state.GetActor(rt.Receiver())
|
||||
if err != nil {
|
||||
ssh.rt.Abortf(exitcode.SysErrorIllegalArgument, "failed to get actor for Readonly state: %s", err)
|
||||
rt.Abortf(exitcode.SysErrorIllegalArgument, "failed to get actor for Readonly state: %s", err)
|
||||
}
|
||||
ssh.rt.Get(act.Head, obj)
|
||||
rt.StoreGet(act.Head, obj)
|
||||
}
|
||||
|
||||
func (ssh *shimStateHandle) Transaction(obj vmr.CBORer, f func()) {
|
||||
func (rt *Runtime) StateTransaction(obj cbor.Er, f func()) {
|
||||
if obj == nil {
|
||||
ssh.rt.Abortf(exitcode.SysErrorIllegalActor, "Must not pass nil to Transaction()")
|
||||
rt.Abortf(exitcode.SysErrorIllegalActor, "Must not pass nil to Transaction()")
|
||||
}
|
||||
|
||||
act, err := ssh.rt.state.GetActor(ssh.rt.Message().Receiver())
|
||||
act, err := rt.state.GetActor(rt.Receiver())
|
||||
if err != nil {
|
||||
ssh.rt.Abortf(exitcode.SysErrorIllegalActor, "failed to get actor for Transaction: %s", err)
|
||||
rt.Abortf(exitcode.SysErrorIllegalActor, "failed to get actor for Transaction: %s", err)
|
||||
}
|
||||
baseState := act.Head
|
||||
ssh.rt.Get(baseState, obj)
|
||||
rt.StoreGet(baseState, obj)
|
||||
|
||||
ssh.rt.allowInternal = false
|
||||
rt.allowInternal = false
|
||||
f()
|
||||
ssh.rt.allowInternal = true
|
||||
rt.allowInternal = true
|
||||
|
||||
c := ssh.rt.Put(obj)
|
||||
c := rt.StorePut(obj)
|
||||
|
||||
err = ssh.rt.stateCommit(baseState, c)
|
||||
err = rt.stateCommit(baseState, c)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to commit state after transaction: %w", err))
|
||||
}
|
||||
@@ -465,7 +450,7 @@ func (rt *Runtime) GetBalance(a address.Address) (types.BigInt, aerrors.ActorErr
|
||||
|
||||
func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
|
||||
// TODO: we can make this more efficient in the future...
|
||||
act, err := rt.state.GetActor(rt.Message().Receiver())
|
||||
act, err := rt.state.GetActor(rt.Receiver())
|
||||
if err != nil {
|
||||
return aerrors.Escalate(err, "failed to get actor to commit state")
|
||||
}
|
||||
@@ -476,7 +461,7 @@ func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
|
||||
|
||||
act.Head = newh
|
||||
|
||||
if err := rt.state.SetActor(rt.Message().Receiver(), act); err != nil {
|
||||
if err := rt.state.SetActor(rt.Receiver(), act); err != nil {
|
||||
return aerrors.Fatalf("failed to set actor in commit state: %s", err)
|
||||
}
|
||||
|
||||
@@ -571,15 +556,15 @@ func (rt *Runtime) abortIfAlreadyValidated() {
|
||||
rt.callerValidated = true
|
||||
}
|
||||
|
||||
func (rt *Runtime) Log(level vmr.LogLevel, msg string, args ...interface{}) {
|
||||
func (rt *Runtime) Log(level rtt.LogLevel, msg string, args ...interface{}) {
|
||||
switch level {
|
||||
case vmr.DEBUG:
|
||||
case rtt.DEBUG:
|
||||
actorLog.Debugf(msg, args...)
|
||||
case vmr.INFO:
|
||||
case rtt.INFO:
|
||||
actorLog.Infof(msg, args...)
|
||||
case vmr.WARN:
|
||||
case rtt.WARN:
|
||||
actorLog.Warnf(msg, args...)
|
||||
case vmr.ERROR:
|
||||
case rtt.ERROR:
|
||||
actorLog.Errorf(msg, args...)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,6 @@ func TestRuntimePutErrors(t *testing.T) {
|
||||
cst: cbor.NewCborStore(nil),
|
||||
}
|
||||
|
||||
rt.Put(&NotAVeryGoodMarshaler{})
|
||||
rt.StorePut(&NotAVeryGoodMarshaler{})
|
||||
t.Error("expected panic")
|
||||
}
|
||||
|
||||
+26
-23
@@ -7,7 +7,7 @@ import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||
|
||||
@@ -116,7 +116,7 @@ func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, origin addres
|
||||
Blocks: &gasChargingBlocks{rt.chargeGasFunc(2), rt.pricelist, vm.cst.Blocks},
|
||||
Atlas: vm.cst.Atlas,
|
||||
}
|
||||
rt.sys = pricedSyscalls{
|
||||
rt.Syscalls = pricedSyscalls{
|
||||
under: vm.Syscalls(ctx, vm.cstate, rt.cst),
|
||||
chargeGas: rt.chargeGasFunc(1),
|
||||
pl: rt.pricelist,
|
||||
@@ -128,7 +128,7 @@ func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, origin addres
|
||||
rt.Abortf(exitcode.SysErrInvalidReceiver, "resolve msg.From address failed")
|
||||
}
|
||||
vmm.From = resF
|
||||
rt.vmsg = &vmm
|
||||
rt.Message = vmm
|
||||
|
||||
return rt
|
||||
}
|
||||
@@ -142,7 +142,7 @@ func (vm *UnsafeVM) MakeRuntime(ctx context.Context, msg *types.Message, origin
|
||||
}
|
||||
|
||||
type CircSupplyCalculator func(context.Context, abi.ChainEpoch, *state.StateTree) (abi.TokenAmount, error)
|
||||
type NtwkVersionGetter func(context.Context, abi.ChainEpoch) runtime.NetworkVersion
|
||||
type NtwkVersionGetter func(context.Context, abi.ChainEpoch) network.Version
|
||||
|
||||
type VM struct {
|
||||
cstate *state.StateTree
|
||||
@@ -201,10 +201,9 @@ type Rand interface {
|
||||
type ApplyRet struct {
|
||||
types.MessageReceipt
|
||||
ActorErr aerrors.ActorError
|
||||
Penalty types.BigInt
|
||||
MinerTip types.BigInt
|
||||
ExecutionTrace types.ExecutionTrace
|
||||
Duration time.Duration
|
||||
GasCosts GasOutputs
|
||||
}
|
||||
|
||||
func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
|
||||
@@ -328,8 +327,7 @@ func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*Ap
|
||||
},
|
||||
ActorErr: actorErr,
|
||||
ExecutionTrace: rt.executionTrace,
|
||||
Penalty: types.NewInt(0),
|
||||
MinerTip: types.NewInt(0),
|
||||
GasCosts: GasOutputs{},
|
||||
Duration: time.Since(start),
|
||||
}, actorErr
|
||||
}
|
||||
@@ -357,14 +355,15 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
||||
msgGasCost := msgGas.Total()
|
||||
// this should never happen, but is currently still exercised by some tests
|
||||
if msgGasCost > msg.GasLimit {
|
||||
gasOutputs := ZeroGasOutputs()
|
||||
gasOutputs.MinerPenalty = types.BigMul(vm.baseFee, abi.NewTokenAmount(msgGasCost))
|
||||
return &ApplyRet{
|
||||
MessageReceipt: types.MessageReceipt{
|
||||
ExitCode: exitcode.SysErrOutOfGas,
|
||||
GasUsed: 0,
|
||||
},
|
||||
Penalty: types.BigMul(vm.baseFee, abi.NewTokenAmount(msgGasCost)),
|
||||
GasCosts: gasOutputs,
|
||||
Duration: time.Since(start),
|
||||
MinerTip: big.Zero(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -375,15 +374,16 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
||||
// this should never happen, but is currently still exercised by some tests
|
||||
if err != nil {
|
||||
if xerrors.Is(err, types.ErrActorNotFound) {
|
||||
gasOutputs := ZeroGasOutputs()
|
||||
gasOutputs.MinerPenalty = minerPenaltyAmount
|
||||
return &ApplyRet{
|
||||
MessageReceipt: types.MessageReceipt{
|
||||
ExitCode: exitcode.SysErrSenderInvalid,
|
||||
GasUsed: 0,
|
||||
},
|
||||
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "actor not found: %s", msg.From),
|
||||
Penalty: minerPenaltyAmount,
|
||||
GasCosts: gasOutputs,
|
||||
Duration: time.Since(start),
|
||||
MinerTip: big.Zero(),
|
||||
}, nil
|
||||
}
|
||||
return nil, xerrors.Errorf("failed to look up from actor: %w", err)
|
||||
@@ -391,19 +391,22 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
||||
|
||||
// this should never happen, but is currently still exercised by some tests
|
||||
if !fromActor.Code.Equals(builtin.AccountActorCodeID) {
|
||||
gasOutputs := ZeroGasOutputs()
|
||||
gasOutputs.MinerPenalty = minerPenaltyAmount
|
||||
return &ApplyRet{
|
||||
MessageReceipt: types.MessageReceipt{
|
||||
ExitCode: exitcode.SysErrSenderInvalid,
|
||||
GasUsed: 0,
|
||||
},
|
||||
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "send from not account actor: %s", fromActor.Code),
|
||||
Penalty: minerPenaltyAmount,
|
||||
GasCosts: gasOutputs,
|
||||
Duration: time.Since(start),
|
||||
MinerTip: big.Zero(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
if msg.Nonce != fromActor.Nonce {
|
||||
gasOutputs := ZeroGasOutputs()
|
||||
gasOutputs.MinerPenalty = minerPenaltyAmount
|
||||
return &ApplyRet{
|
||||
MessageReceipt: types.MessageReceipt{
|
||||
ExitCode: exitcode.SysErrSenderStateInvalid,
|
||||
@@ -411,14 +414,16 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
||||
},
|
||||
ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid,
|
||||
"actor nonce invalid: msg:%d != state:%d", msg.Nonce, fromActor.Nonce),
|
||||
Penalty: minerPenaltyAmount,
|
||||
|
||||
GasCosts: gasOutputs,
|
||||
Duration: time.Since(start),
|
||||
MinerTip: big.Zero(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
gascost := types.BigMul(types.NewInt(uint64(msg.GasLimit)), msg.GasFeeCap)
|
||||
if fromActor.Balance.LessThan(gascost) {
|
||||
gasOutputs := ZeroGasOutputs()
|
||||
gasOutputs.MinerPenalty = minerPenaltyAmount
|
||||
return &ApplyRet{
|
||||
MessageReceipt: types.MessageReceipt{
|
||||
ExitCode: exitcode.SysErrSenderStateInvalid,
|
||||
@@ -426,9 +431,8 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
||||
},
|
||||
ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid,
|
||||
"actor balance less than needed: %s < %s", types.FIL(fromActor.Balance), types.FIL(gascost)),
|
||||
Penalty: minerPenaltyAmount,
|
||||
GasCosts: gasOutputs,
|
||||
Duration: time.Since(start),
|
||||
MinerTip: big.Zero(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -521,8 +525,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
||||
},
|
||||
ActorErr: actorErr,
|
||||
ExecutionTrace: rt.executionTrace,
|
||||
Penalty: gasOutputs.MinerPenalty,
|
||||
MinerTip: gasOutputs.MinerTip,
|
||||
GasCosts: gasOutputs,
|
||||
Duration: time.Since(start),
|
||||
}, nil
|
||||
}
|
||||
@@ -700,9 +703,9 @@ func (vm *VM) Invoke(act *types.Actor, rt *Runtime, method abi.MethodNum, params
|
||||
defer span.End()
|
||||
if span.IsRecordingEvents() {
|
||||
span.AddAttributes(
|
||||
trace.StringAttribute("to", rt.Message().Receiver().String()),
|
||||
trace.StringAttribute("to", rt.Receiver().String()),
|
||||
trace.Int64Attribute("method", int64(method)),
|
||||
trace.StringAttribute("value", rt.Message().ValueReceived().String()),
|
||||
trace.StringAttribute("value", rt.ValueReceived().String()),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -722,7 +725,7 @@ func (vm *VM) SetInvoker(i *Invoker) {
|
||||
vm.inv = i
|
||||
}
|
||||
|
||||
func (vm *VM) GetNtwkVersion(ctx context.Context, ce abi.ChainEpoch) runtime.NetworkVersion {
|
||||
func (vm *VM) GetNtwkVersion(ctx context.Context, ce abi.ChainEpoch) network.Version {
|
||||
return vm.ntwkVersion(ctx, ce)
|
||||
}
|
||||
|
||||
|
||||
+11
-2
@@ -659,7 +659,7 @@ func handleHamtEpoch(ctx context.Context, api api.FullNode, r cid.Cid) error {
|
||||
}
|
||||
|
||||
return mp.ForEach(nil, func(key string) error {
|
||||
ik, err := adt.ParseIntKey(key)
|
||||
ik, err := abi.ParseIntKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -844,6 +844,9 @@ var chainExportCmd = &cli.Command{
|
||||
Name: "recent-stateroots",
|
||||
Usage: "specify the number of recent state roots to include in the export",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "skip-old-msgs",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
@@ -878,7 +881,13 @@ var chainExportCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
stream, err := api.ChainExport(ctx, rsrs, ts.Key())
|
||||
skipold := cctx.Bool("skip-old-msgs")
|
||||
|
||||
if rsrs == 0 && skipold {
|
||||
return fmt.Errorf("must pass recent stateroots along with skip-old-msgs")
|
||||
}
|
||||
|
||||
stream, err := api.ChainExport(ctx, rsrs, skipold, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
|
||||
tm "github.com/buger/goterm"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/fatih/color"
|
||||
@@ -527,6 +529,11 @@ func interactiveDeal(cctx *cli.Context) error {
|
||||
continue
|
||||
}
|
||||
|
||||
if days < int(build.MinDealDuration/builtin.EpochsInDay) {
|
||||
printErr(xerrors.Errorf("minimum duration is %d days", int(build.MinDealDuration/builtin.EpochsInDay)))
|
||||
continue
|
||||
}
|
||||
|
||||
state = "miner"
|
||||
case "miner":
|
||||
fmt.Print("Miner Address (t0..): ")
|
||||
|
||||
+20
-3
@@ -303,6 +303,10 @@ var mpoolReplaceCmd = &cli.Command{
|
||||
Name: "auto",
|
||||
Usage: "automatically reprice the specified message",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "max-fee",
|
||||
Usage: "Spend up to X FIL for this message (applicable for auto mode)",
|
||||
},
|
||||
},
|
||||
ArgsUsage: "[from] [nonce]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
@@ -353,17 +357,30 @@ var mpoolReplaceCmd = &cli.Command{
|
||||
msg := found.Message
|
||||
|
||||
if cctx.Bool("auto") {
|
||||
minRBF := messagepool.ComputeMinRBF(msg.GasPremium)
|
||||
|
||||
var mss *lapi.MessageSendSpec
|
||||
if cctx.IsSet("max-fee") {
|
||||
maxFee, err := types.BigFromString(cctx.String("max-fee"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing max-spend: %w", err)
|
||||
}
|
||||
mss = &lapi.MessageSendSpec{
|
||||
MaxFee: maxFee,
|
||||
}
|
||||
}
|
||||
|
||||
// msg.GasLimit = 0 // TODO: need to fix the way we estimate gas limits to account for the messages already being in the mempool
|
||||
msg.GasFeeCap = abi.NewTokenAmount(0)
|
||||
msg.GasPremium = abi.NewTokenAmount(0)
|
||||
retm, err := api.GasEstimateMessageGas(ctx, &msg, &lapi.MessageSendSpec{}, types.EmptyTSK)
|
||||
retm, err := api.GasEstimateMessageGas(ctx, &msg, mss, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to estimate gas values: %w", err)
|
||||
}
|
||||
msg.GasFeeCap = retm.GasFeeCap
|
||||
|
||||
minRBF := messagepool.ComputeMinRBF(msg.GasPremium)
|
||||
msg.GasPremium = big.Max(retm.GasPremium, minRBF)
|
||||
msg.GasFeeCap = big.Max(retm.GasFeeCap, msg.GasPremium)
|
||||
messagepool.CapGasFee(&msg, mss.Get().MaxFee)
|
||||
} else {
|
||||
msg.GasLimit = cctx.Int64("gas-limit")
|
||||
msg.GasPremium, err = types.BigFromString(cctx.String("gas-premium"))
|
||||
|
||||
+298
-2
@@ -37,9 +37,13 @@ var multisigCmd = &cli.Command{
|
||||
msigInspectCmd,
|
||||
msigProposeCmd,
|
||||
msigApproveCmd,
|
||||
msigAddProposeCmd,
|
||||
msigAddApproveCmd,
|
||||
msigAddCancelCmd,
|
||||
msigSwapProposeCmd,
|
||||
msigSwapApproveCmd,
|
||||
msigSwapCancelCmd,
|
||||
msigVestedCmd,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -506,6 +510,236 @@ var msigApproveCmd = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var msigAddProposeCmd = &cli.Command{
|
||||
Name: "add-propose",
|
||||
Usage: "Propose to add a signer",
|
||||
ArgsUsage: "[multisigAddress signer]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "increase-threshold",
|
||||
Usage: "whether the number of required signers should be increased",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "from",
|
||||
Usage: "account to send the propose message from",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.Args().Len() != 2 {
|
||||
return ShowHelp(cctx, fmt.Errorf("must pass multisig address and signer address"))
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
msig, err := address.NewFromString(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addr, err := address.NewFromString(cctx.Args().Get(1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var from address.Address
|
||||
if cctx.IsSet("from") {
|
||||
f, err := address.NewFromString(cctx.String("from"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
from = f
|
||||
} else {
|
||||
defaddr, err := api.WalletDefaultAddress(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
from = defaddr
|
||||
}
|
||||
|
||||
msgCid, err := api.MsigAddPropose(ctx, msig, from, addr, cctx.Bool("increase-threshold"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("sent add proposal in message: ", msgCid)
|
||||
|
||||
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if wait.Receipt.ExitCode != 0 {
|
||||
return fmt.Errorf("add proposal returned exit %d", wait.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var msigAddApproveCmd = &cli.Command{
|
||||
Name: "add-approve",
|
||||
Usage: "Approve a message to add a signer",
|
||||
ArgsUsage: "[multisigAddress proposerAddress txId newAddress increaseThreshold]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "from",
|
||||
Usage: "account to send the approve message from",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.Args().Len() != 5 {
|
||||
return ShowHelp(cctx, fmt.Errorf("must pass multisig address, proposer address, transaction id, new signer address, whether to increase threshold"))
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
msig, err := address.NewFromString(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
prop, err := address.NewFromString(cctx.Args().Get(1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
txid, err := strconv.ParseUint(cctx.Args().Get(2), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newAdd, err := address.NewFromString(cctx.Args().Get(3))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
inc, err := strconv.ParseBool(cctx.Args().Get(4))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var from address.Address
|
||||
if cctx.IsSet("from") {
|
||||
f, err := address.NewFromString(cctx.String("from"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
from = f
|
||||
} else {
|
||||
defaddr, err := api.WalletDefaultAddress(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
from = defaddr
|
||||
}
|
||||
|
||||
msgCid, err := api.MsigAddApprove(ctx, msig, from, txid, prop, newAdd, inc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("sent add approval in message: ", msgCid)
|
||||
|
||||
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if wait.Receipt.ExitCode != 0 {
|
||||
return fmt.Errorf("add approval returned exit %d", wait.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var msigAddCancelCmd = &cli.Command{
|
||||
Name: "add-cancel",
|
||||
Usage: "Cancel a message to add a signer",
|
||||
ArgsUsage: "[multisigAddress txId newAddress increaseThreshold]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "from",
|
||||
Usage: "account to send the approve message from",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.Args().Len() != 4 {
|
||||
return ShowHelp(cctx, fmt.Errorf("must pass multisig address, transaction id, new signer address, whether to increase threshold"))
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
msig, err := address.NewFromString(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
txid, err := strconv.ParseUint(cctx.Args().Get(1), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newAdd, err := address.NewFromString(cctx.Args().Get(2))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
inc, err := strconv.ParseBool(cctx.Args().Get(3))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var from address.Address
|
||||
if cctx.IsSet("from") {
|
||||
f, err := address.NewFromString(cctx.String("from"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
from = f
|
||||
} else {
|
||||
defaddr, err := api.WalletDefaultAddress(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
from = defaddr
|
||||
}
|
||||
|
||||
msgCid, err := api.MsigAddCancel(ctx, msig, from, txid, newAdd, inc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("sent add cancellation in message: ", msgCid)
|
||||
|
||||
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if wait.Receipt.ExitCode != 0 {
|
||||
return fmt.Errorf("add cancellation returned exit %d", wait.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var msigSwapProposeCmd = &cli.Command{
|
||||
Name: "swap-propose",
|
||||
Usage: "Propose to swap signers",
|
||||
@@ -722,7 +956,7 @@ var msigSwapCancelCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("sent swap approval in message: ", msgCid)
|
||||
fmt.Println("sent swap cancellation in message: ", msgCid)
|
||||
|
||||
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
|
||||
if err != nil {
|
||||
@@ -730,9 +964,71 @@ var msigSwapCancelCmd = &cli.Command{
|
||||
}
|
||||
|
||||
if wait.Receipt.ExitCode != 0 {
|
||||
return fmt.Errorf("swap approval returned exit %d", wait.Receipt.ExitCode)
|
||||
return fmt.Errorf("swap cancellation returned exit %d", wait.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var msigVestedCmd = &cli.Command{
|
||||
Name: "vested",
|
||||
Usage: "Gets the amount vested in an msig between two epochs",
|
||||
ArgsUsage: "[multisigAddress]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.Int64Flag{
|
||||
Name: "start-epoch",
|
||||
Usage: "start epoch to measure vesting from",
|
||||
Value: 0,
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
Name: "end-epoch",
|
||||
Usage: "end epoch to stop measure vesting at",
|
||||
Value: -1,
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.Args().Len() != 1 {
|
||||
return ShowHelp(cctx, fmt.Errorf("must pass multisig address"))
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
msig, err := address.NewFromString(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
start, err := api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Int64("start-epoch")), types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var end *types.TipSet
|
||||
if cctx.Int64("end-epoch") < 0 {
|
||||
end, err = LoadTipSet(ctx, cctx, api)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
end, err = api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Int64("end-epoch")), types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
ret, err := api.MsigGetVested(ctx, msig, start.Key(), end.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Vested: %s between %d and %d\n", types.FIL(ret), start.Height(), end.Height())
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
+6
-2
@@ -28,6 +28,8 @@ var paychCmd = &cli.Command{
|
||||
paychListCmd,
|
||||
paychVoucherCmd,
|
||||
paychSettleCmd,
|
||||
paychStatusCmd,
|
||||
paychStatusByFromToCmd,
|
||||
paychCloseCmd,
|
||||
},
|
||||
}
|
||||
@@ -102,6 +104,7 @@ var paychStatusByFromToCmd = &cli.Command{
|
||||
if cctx.Args().Len() != 2 {
|
||||
return ShowHelp(cctx, fmt.Errorf("must pass two arguments: <from address> <to address>"))
|
||||
}
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
from, err := address.NewFromString(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
@@ -119,7 +122,7 @@ var paychStatusByFromToCmd = &cli.Command{
|
||||
}
|
||||
defer closer()
|
||||
|
||||
avail, err := api.PaychAvailableFundsByFromTo(from, to)
|
||||
avail, err := api.PaychAvailableFundsByFromTo(ctx, from, to)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -137,6 +140,7 @@ var paychStatusCmd = &cli.Command{
|
||||
if cctx.Args().Len() != 1 {
|
||||
return ShowHelp(cctx, fmt.Errorf("must pass an argument: <channel address>"))
|
||||
}
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
ch, err := address.NewFromString(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
@@ -149,7 +153,7 @@ var paychStatusCmd = &cli.Command{
|
||||
}
|
||||
defer closer()
|
||||
|
||||
avail, err := api.PaychAvailableFunds(ch)
|
||||
avail, err := api.PaychAvailableFunds(ctx, ch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+153
-5
@@ -27,6 +27,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/exported"
|
||||
@@ -53,6 +54,7 @@ var stateCmd = &cli.Command{
|
||||
stateListActorsCmd,
|
||||
stateListMinersCmd,
|
||||
stateCircSupplyCmd,
|
||||
stateSectorCmd,
|
||||
stateGetActorCmd,
|
||||
stateLookupIDCmd,
|
||||
stateReplaySetCmd,
|
||||
@@ -64,6 +66,7 @@ var stateCmd = &cli.Command{
|
||||
stateGetDealSetCmd,
|
||||
stateWaitMsgCmd,
|
||||
stateSearchMsgCmd,
|
||||
stateMsgCostCmd,
|
||||
stateMinerInfo,
|
||||
stateMarketCmd,
|
||||
},
|
||||
@@ -118,11 +121,18 @@ var stateMinerInfo = &cli.Command{
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
cd, err := api.StateMinerProvingDeadline(ctx, addr, ts.Key())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner info: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Proving Period Start:\t%s\n", EpochTime(cd.CurrentEpoch, cd.PeriodStart))
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func parseTipSetString(ts string) ([]cid.Cid, error) {
|
||||
func ParseTipSetString(ts string) ([]cid.Cid, error) {
|
||||
strs := strings.Split(ts, ",")
|
||||
|
||||
var cids []cid.Cid
|
||||
@@ -160,7 +170,7 @@ func ParseTipSetRef(ctx context.Context, api api.FullNode, tss string) (*types.T
|
||||
return api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(h), types.EmptyTSK)
|
||||
}
|
||||
|
||||
cids, err := parseTipSetString(tss)
|
||||
cids, err := ParseTipSetString(tss)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1303,6 +1313,60 @@ var stateSearchMsgCmd = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var stateMsgCostCmd = &cli.Command{
|
||||
Name: "msg-cost",
|
||||
Usage: "Get the detailed gas costs of a message",
|
||||
ArgsUsage: "[messageCid]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must specify message cid to get gas costs for")
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
msg, err := cid.Decode(cctx.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tsk := types.EmptyTSK
|
||||
|
||||
ts, err := LoadTipSet(ctx, cctx, api)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ts != nil {
|
||||
tsk = ts.Key()
|
||||
}
|
||||
|
||||
mgc, err := api.StateMsgGasCost(ctx, msg, tsk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if mgc != nil {
|
||||
fmt.Printf("Message CID: %s", mgc.Message)
|
||||
fmt.Printf("\nGas Used: %d", mgc.GasUsed)
|
||||
fmt.Printf("\nBase Fee Burn: %d", mgc.BaseFeeBurn)
|
||||
fmt.Printf("\nOverestimation Burn: %d", mgc.OverEstimationBurn)
|
||||
fmt.Printf("\nMiner Tip: %d", mgc.MinerTip)
|
||||
fmt.Printf("\nRefund: %d", mgc.Refund)
|
||||
fmt.Printf("\nTotal Cost: %d", mgc.TotalCost)
|
||||
fmt.Printf("\nMiner Penalty: %d", mgc.MinerPenalty)
|
||||
} else {
|
||||
fmt.Print("message was not found on chain")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var stateCallCmd = &cli.Command{
|
||||
Name: "call",
|
||||
Usage: "Invoke a method on an actor locally",
|
||||
@@ -1384,7 +1448,7 @@ var stateCallCmd = &cli.Command{
|
||||
}
|
||||
|
||||
if ret.MsgRct.ExitCode != 0 {
|
||||
return fmt.Errorf("invocation failed (exit: %d): %s", ret.MsgRct.ExitCode, ret.Error)
|
||||
return fmt.Errorf("invocation failed (exit: %d, gasUsed: %d): %s", ret.MsgRct.ExitCode, ret.MsgRct.GasUsed, ret.Error)
|
||||
}
|
||||
|
||||
s, err := formatOutput(cctx.String("ret"), ret.MsgRct.Return)
|
||||
@@ -1392,6 +1456,7 @@ var stateCallCmd = &cli.Command{
|
||||
return fmt.Errorf("failed to format output: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("gas used: %d\n", ret.MsgRct.GasUsed)
|
||||
fmt.Printf("return: %s\n", s)
|
||||
|
||||
return nil
|
||||
@@ -1465,11 +1530,11 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er
|
||||
f := methods[method]
|
||||
|
||||
rf := reflect.TypeOf(f)
|
||||
if rf.NumIn() != 3 {
|
||||
if rf.NumIn() != 2 {
|
||||
return nil, fmt.Errorf("expected referenced method to have three arguments")
|
||||
}
|
||||
|
||||
paramObj := rf.In(2).Elem()
|
||||
paramObj := rf.In(1).Elem()
|
||||
if paramObj.NumField() != len(args) {
|
||||
return nil, fmt.Errorf("not enough arguments given to call that method (expecting %d)", paramObj.NumField())
|
||||
}
|
||||
@@ -1489,6 +1554,18 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er
|
||||
return nil, err
|
||||
}
|
||||
p.Elem().Field(i).Set(reflect.ValueOf(val))
|
||||
case reflect.TypeOf(abi.ChainEpoch(0)):
|
||||
val, err := strconv.ParseInt(args[i], 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.Elem().Field(i).Set(reflect.ValueOf(abi.ChainEpoch(val)))
|
||||
case reflect.TypeOf(big.Int{}):
|
||||
val, err := big.FromString(args[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.Elem().Field(i).Set(reflect.ValueOf(val))
|
||||
case reflect.TypeOf(peer.ID("")):
|
||||
pid, err := peer.Decode(args[i])
|
||||
if err != nil {
|
||||
@@ -1540,6 +1617,77 @@ var stateCircSupplyCmd = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var stateSectorCmd = &cli.Command{
|
||||
Name: "sector",
|
||||
Usage: "Get miner sector info",
|
||||
ArgsUsage: "[miner address] [sector number]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if cctx.Args().Len() != 2 {
|
||||
return xerrors.Errorf("expected 2 params")
|
||||
}
|
||||
|
||||
ts, err := LoadTipSet(ctx, cctx, api)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ts == nil {
|
||||
ts, err = api.ChainHead(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
maddr, err := address.NewFromString(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sid, err := strconv.ParseInt(cctx.Args().Get(1), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
si, err := api.StateSectorGetInfo(ctx, maddr, abi.SectorNumber(sid), ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("SectorNumber: ", si.SectorNumber)
|
||||
fmt.Println("SealProof: ", si.SealProof)
|
||||
fmt.Println("SealedCID: ", si.SealedCID)
|
||||
fmt.Println("DealIDs: ", si.DealIDs)
|
||||
fmt.Println()
|
||||
fmt.Println("Activation: ", EpochTime(ts.Height(), si.Activation))
|
||||
fmt.Println("Expiration: ", EpochTime(ts.Height(), si.Expiration))
|
||||
fmt.Println()
|
||||
fmt.Println("DealWeight: ", si.DealWeight)
|
||||
fmt.Println("VerifiedDealWeight: ", si.VerifiedDealWeight)
|
||||
fmt.Println("InitialPledge: ", types.FIL(si.InitialPledge))
|
||||
fmt.Println("ExpectedDayReward: ", types.FIL(si.ExpectedDayReward))
|
||||
fmt.Println("ExpectedStoragePledge: ", types.FIL(si.ExpectedStoragePledge))
|
||||
fmt.Println()
|
||||
|
||||
sp, err := api.StateSectorPartition(ctx, maddr, abi.SectorNumber(sid), ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Deadline: ", sp.Deadline)
|
||||
fmt.Println("Partition: ", sp.Partition)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var stateMarketCmd = &cli.Command{
|
||||
Name: "market",
|
||||
Usage: "Inspect the storage market actor",
|
||||
|
||||
+20
-1
@@ -2,10 +2,16 @@ package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
func parseTipSet(ctx context.Context, api api.FullNode, vals []string) (*types.TipSet, error) {
|
||||
@@ -26,3 +32,16 @@ func parseTipSet(ctx context.Context, api api.FullNode, vals []string) (*types.T
|
||||
|
||||
return types.NewTipSet(headers)
|
||||
}
|
||||
|
||||
func EpochTime(curr, e abi.ChainEpoch) string {
|
||||
switch {
|
||||
case curr > e:
|
||||
return fmt.Sprintf("%d (%s ago)", e, time.Second*time.Duration(int64(build.BlockDelaySecs)*int64(curr-e)))
|
||||
case curr == e:
|
||||
return fmt.Sprintf("%d (now)", e)
|
||||
case curr < e:
|
||||
return fmt.Sprintf("%d (in %s)", e, time.Second*time.Duration(int64(build.BlockDelaySecs)*int64(e-curr)))
|
||||
}
|
||||
|
||||
panic("math broke")
|
||||
}
|
||||
|
||||
@@ -56,6 +56,10 @@ var importBenchCmd = &cli.Command{
|
||||
Usage: "set the parallelism factor for batch seal verification",
|
||||
Value: runtime.NumCPU(),
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "repodir",
|
||||
Usage: "set the repo directory for the lotus bench run (defaults to /tmp)",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
vm.BatchSealVerifyParallelism = cctx.Int("batch-seal-verify-threads")
|
||||
@@ -70,9 +74,15 @@ var importBenchCmd = &cli.Command{
|
||||
}
|
||||
defer cfi.Close() //nolint:errcheck // read only file
|
||||
|
||||
tdir, err := ioutil.TempDir("", "lotus-import-bench")
|
||||
if err != nil {
|
||||
return err
|
||||
var tdir string
|
||||
if rdir := cctx.String("repodir"); rdir != "" {
|
||||
tdir = rdir
|
||||
} else {
|
||||
tmp, err := ioutil.TempDir("", "lotus-import-bench")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tdir = tmp
|
||||
}
|
||||
|
||||
bds, err := badger.NewDatastore(tdir, nil)
|
||||
|
||||
@@ -387,7 +387,7 @@ var sealBenchCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
log.Error("post verification failed")
|
||||
log.Error("window post verification failed")
|
||||
}
|
||||
|
||||
verifyWindowpost1 := time.Now()
|
||||
@@ -403,7 +403,7 @@ var sealBenchCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
log.Error("post verification failed")
|
||||
log.Error("window post verification failed")
|
||||
}
|
||||
|
||||
verifyWindowpost2 := time.Now()
|
||||
|
||||
@@ -221,7 +221,7 @@ func (p *Processor) processMiners(ctx context.Context, minerTips map[types.TipSe
|
||||
var claim power.Claim
|
||||
// get miner claim from power actors claim map and store if found, else the miner had no claim at
|
||||
// this tipset
|
||||
found, err := minersClaims.Get(adt.AddrKey(act.addr), &claim)
|
||||
found, err := minersClaims.Get(abi.AddrKey(act.addr), &claim)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -694,7 +694,7 @@ func (p *Processor) getMinerSectorChanges(ctx context.Context, m minerActorInfo)
|
||||
}
|
||||
|
||||
func (p *Processor) diffMinerPartitions(ctx context.Context, m minerActorInfo, events chan<- *MinerSectorsEvent) error {
|
||||
prevMiner, err := p.getMinerStateAt(ctx, m.common.addr, m.common.tsKey)
|
||||
prevMiner, err := p.getMinerStateAt(ctx, m.common.addr, m.common.parentTsKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -136,7 +136,8 @@ create unique index if not exists block_cid_uindex
|
||||
on blocks (cid,height);
|
||||
|
||||
create materialized view if not exists state_heights
|
||||
as select distinct height, parentstateroot from blocks;
|
||||
as select min(b.height) height, b.parentstateroot
|
||||
from blocks b group by b.parentstateroot;
|
||||
|
||||
create index if not exists state_heights_height_index
|
||||
on state_heights (height);
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
const LookbackCap = time.Hour
|
||||
|
||||
var (
|
||||
ErrLookbackTooLong = fmt.Errorf("lookbacks of more than %s are disallowed", LookbackCap)
|
||||
)
|
||||
|
||||
type GatewayAPI struct {
|
||||
api api.FullNode
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) getTipsetTimestamp(ctx context.Context, tsk types.TipSetKey) (time.Time, error) {
|
||||
if tsk.IsEmpty() {
|
||||
return time.Now(), nil
|
||||
}
|
||||
|
||||
ts, err := a.api.ChainGetTipSet(ctx, tsk)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
return time.Unix(int64(ts.Blocks()[0].Timestamp), 0), nil
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) checkTipset(ctx context.Context, ts types.TipSetKey) error {
|
||||
when, err := a.getTipsetTimestamp(ctx, ts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if time.Since(when) > time.Hour {
|
||||
return ErrLookbackTooLong
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "StateGetActor")
|
||||
defer span.End()
|
||||
|
||||
if err := a.checkTipset(ctx, ts); err != nil {
|
||||
return nil, fmt.Errorf("bad tipset: %w", err)
|
||||
}
|
||||
|
||||
return a.api.StateGetActor(ctx, actor, ts)
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) ChainHead(ctx context.Context) (*types.TipSet, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "ChainHead")
|
||||
defer span.End()
|
||||
// TODO: cache and invalidate cache when timestamp is up (or have internal ChainNotify)
|
||||
|
||||
return a.api.ChainHead(ctx)
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "ChainGetTipSet")
|
||||
defer span.End()
|
||||
|
||||
if err := a.checkTipset(ctx, tsk); err != nil {
|
||||
return nil, fmt.Errorf("bad tipset: %w", err)
|
||||
}
|
||||
|
||||
// TODO: since we're limiting lookbacks, should just cache this (could really even cache the json response bytes)
|
||||
return a.api.ChainGetTipSet(ctx, tsk)
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "MpoolPush")
|
||||
defer span.End()
|
||||
|
||||
// TODO: additional anti-spam checks
|
||||
|
||||
return a.api.MpoolPush(ctx, sm)
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/go-jsonrpc"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
"github.com/filecoin-project/lotus/lib/lotuslog"
|
||||
logging "github.com/ipfs/go-log"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var log = logging.Logger("gateway")
|
||||
|
||||
func main() {
|
||||
lotuslog.SetupLogLevels()
|
||||
|
||||
local := []*cli.Command{
|
||||
runCmd,
|
||||
}
|
||||
|
||||
app := &cli.App{
|
||||
Name: "lotus-gateway",
|
||||
Usage: "Public API server for lotus",
|
||||
Version: build.UserVersion(),
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "repo",
|
||||
EnvVars: []string{"LOTUS_PATH"},
|
||||
Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME
|
||||
},
|
||||
},
|
||||
|
||||
Commands: local,
|
||||
}
|
||||
app.Setup()
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
log.Warnf("%+v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var runCmd = &cli.Command{
|
||||
Name: "run",
|
||||
Usage: "Start api server",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "listen",
|
||||
Usage: "host address and port the api server will listen on",
|
||||
Value: "0.0.0.0:2346",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
log.Info("Starting lotus gateway")
|
||||
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
api, closer, err := lcli.GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
address := cctx.String("listen")
|
||||
mux := mux.NewRouter()
|
||||
|
||||
log.Info("Setting up API endpoint at " + address)
|
||||
|
||||
rpcServer := jsonrpc.NewServer()
|
||||
rpcServer.Register("Filecoin", &GatewayAPI{api: api})
|
||||
|
||||
mux.Handle("/rpc/v0", rpcServer)
|
||||
mux.PathPrefix("/").Handler(http.DefaultServeMux)
|
||||
|
||||
/*ah := &auth.Handler{
|
||||
Verify: nodeApi.AuthVerify,
|
||||
Next: mux.ServeHTTP,
|
||||
}*/
|
||||
|
||||
srv := &http.Server{
|
||||
Handler: mux,
|
||||
BaseContext: func(listener net.Listener) context.Context {
|
||||
return ctx
|
||||
},
|
||||
}
|
||||
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
log.Warn("Shutting down...")
|
||||
if err := srv.Shutdown(context.TODO()); err != nil {
|
||||
log.Errorf("shutting down RPC server failed: %s", err)
|
||||
}
|
||||
log.Warn("Graceful shutdown successful")
|
||||
}()
|
||||
|
||||
nl, err := net.Listen("tcp", address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return srv.Serve(nl)
|
||||
},
|
||||
}
|
||||
@@ -45,6 +45,8 @@ const FlagWorkerRepo = "worker-repo"
|
||||
const FlagWorkerRepoDeprecation = "workerrepo"
|
||||
|
||||
func main() {
|
||||
build.RunningNodeType = build.NodeWorker
|
||||
|
||||
lotuslog.SetupLogLevels()
|
||||
|
||||
local := []*cli.Command{
|
||||
@@ -187,8 +189,8 @@ var runCmd = &cli.Command{
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v.APIVersion != build.APIVersion {
|
||||
return xerrors.Errorf("lotus-miner API version doesn't match: local: %s", api.Version{APIVersion: build.APIVersion})
|
||||
if v.APIVersion != build.MinerAPIVersion {
|
||||
return xerrors.Errorf("lotus-miner API version doesn't match: expected: %s", api.Version{APIVersion: build.MinerAPIVersion})
|
||||
}
|
||||
log.Infof("Remote version %s", v)
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ type worker struct {
|
||||
}
|
||||
|
||||
func (w *worker) Version(context.Context) (build.Version, error) {
|
||||
return build.APIVersion, nil
|
||||
return build.WorkerAPIVersion, nil
|
||||
}
|
||||
|
||||
func (w *worker) StorageAddLocal(ctx context.Context, path string) error {
|
||||
|
||||
+173
-31
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
@@ -28,6 +29,9 @@ var bitFieldCmd = &cli.Command{
|
||||
bitFieldRunsCmd,
|
||||
bitFieldStatCmd,
|
||||
bitFieldDecodeCmd,
|
||||
bitFieldIntersectCmd,
|
||||
bitFieldEncodeCmd,
|
||||
bitFieldSubCmd,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -200,38 +204,9 @@ var bitFieldDecodeCmd = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
var val string
|
||||
if cctx.Args().Present() {
|
||||
val = cctx.Args().Get(0)
|
||||
} else {
|
||||
b, err := ioutil.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
val = string(b)
|
||||
}
|
||||
|
||||
var dec []byte
|
||||
switch cctx.String("enc") {
|
||||
case "base64":
|
||||
d, err := base64.StdEncoding.DecodeString(val)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decoding base64 value: %w", err)
|
||||
}
|
||||
dec = d
|
||||
case "hex":
|
||||
d, err := hex.DecodeString(val)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decoding hex value: %w", err)
|
||||
}
|
||||
dec = d
|
||||
default:
|
||||
return fmt.Errorf("unrecognized encoding: %s", cctx.String("enc"))
|
||||
}
|
||||
|
||||
rle, err := bitfield.NewFromBytes(dec)
|
||||
rle, err := decode(cctx, 0)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to parse bitfield: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
vals, err := rle.All(100000000000)
|
||||
@@ -243,3 +218,170 @@ var bitFieldDecodeCmd = &cli.Command{
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var bitFieldIntersectCmd = &cli.Command{
|
||||
Name: "intersect",
|
||||
Description: "intersect 2 bitfields and print the resulting bitfield as base64",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "enc",
|
||||
Value: "base64",
|
||||
Usage: "specify input encoding to parse",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
b, err := decode(cctx, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a, err := decode(cctx, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o, err := bitfield.IntersectBitField(a, b)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("intersect: %w", err)
|
||||
}
|
||||
|
||||
s, err := o.RunIterator()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bytes, err := rlepluslazy.EncodeRuns(s, []byte{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(base64.StdEncoding.EncodeToString(bytes))
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var bitFieldSubCmd = &cli.Command{
|
||||
Name: "sub",
|
||||
Description: "subtract 2 bitfields and print the resulting bitfield as base64",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "enc",
|
||||
Value: "base64",
|
||||
Usage: "specify input encoding to parse",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
b, err := decode(cctx, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a, err := decode(cctx, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o, err := bitfield.SubtractBitField(a, b)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("intersect: %w", err)
|
||||
}
|
||||
|
||||
s, err := o.RunIterator()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bytes, err := rlepluslazy.EncodeRuns(s, []byte{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(base64.StdEncoding.EncodeToString(bytes))
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var bitFieldEncodeCmd = &cli.Command{
|
||||
Name: "encode",
|
||||
Description: "encode a series of decimal numbers into a bitfield",
|
||||
ArgsUsage: "[infile]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "enc",
|
||||
Value: "base64",
|
||||
Usage: "specify input encoding to parse",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
f, err := os.Open(cctx.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close() // nolint
|
||||
|
||||
out := bitfield.New()
|
||||
for {
|
||||
var i uint64
|
||||
_, err := fmt.Fscan(f, &i)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
out.Set(i)
|
||||
}
|
||||
|
||||
s, err := out.RunIterator()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bytes, err := rlepluslazy.EncodeRuns(s, []byte{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(base64.StdEncoding.EncodeToString(bytes))
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func decode(cctx *cli.Context, a int) (bitfield.BitField, error) {
|
||||
var val string
|
||||
if cctx.Args().Present() {
|
||||
if a >= cctx.NArg() {
|
||||
return bitfield.BitField{}, xerrors.Errorf("need more than %d args", a)
|
||||
}
|
||||
val = cctx.Args().Get(a)
|
||||
} else {
|
||||
if a > 0 {
|
||||
return bitfield.BitField{}, xerrors.Errorf("need more than %d args", a)
|
||||
}
|
||||
b, err := ioutil.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
return bitfield.BitField{}, err
|
||||
}
|
||||
val = string(b)
|
||||
}
|
||||
|
||||
var dec []byte
|
||||
switch cctx.String("enc") {
|
||||
case "base64":
|
||||
d, err := base64.StdEncoding.DecodeString(val)
|
||||
if err != nil {
|
||||
return bitfield.BitField{}, fmt.Errorf("decoding base64 value: %w", err)
|
||||
}
|
||||
dec = d
|
||||
case "hex":
|
||||
d, err := hex.DecodeString(val)
|
||||
if err != nil {
|
||||
return bitfield.BitField{}, fmt.Errorf("decoding hex value: %w", err)
|
||||
}
|
||||
dec = d
|
||||
default:
|
||||
return bitfield.BitField{}, fmt.Errorf("unrecognized encoding: %s", cctx.String("enc"))
|
||||
}
|
||||
|
||||
return bitfield.NewFromBytes(dec)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
"github.com/filecoin-project/lotus/lib/blockstore"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
)
|
||||
|
||||
var exportChainCmd = &cli.Command{
|
||||
Name: "export",
|
||||
Description: "Export chain from repo (requires node to be offline)",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "repo",
|
||||
Value: "~/.lotus",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "tipset",
|
||||
Usage: "tipset to export from",
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
Name: "recent-stateroots",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "full-state",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "skip-old-msgs",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
return lcli.ShowHelp(cctx, fmt.Errorf("must specify file name to write export to"))
|
||||
}
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
r, err := repo.NewFS(cctx.String("repo"))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("opening fs repo: %w", err)
|
||||
}
|
||||
|
||||
exists, err := r.Exists()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
return xerrors.Errorf("lotus repo doesn't exist")
|
||||
}
|
||||
|
||||
lr, err := r.Lock(repo.FullNode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer lr.Close() //nolint:errcheck
|
||||
|
||||
fi, err := os.Create(cctx.Args().First())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("opening the output file: %w", err)
|
||||
}
|
||||
|
||||
defer fi.Close() //nolint:errcheck
|
||||
|
||||
ds, err := lr.Datastore("/chain")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mds, err := lr.Datastore("/metadata")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bs := blockstore.NewBlockstore(ds)
|
||||
|
||||
cs := store.NewChainStore(bs, mds, nil)
|
||||
if err := cs.Load(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nroots := abi.ChainEpoch(cctx.Int64("recent-stateroots"))
|
||||
fullstate := cctx.Bool("full-state")
|
||||
skipoldmsgs := cctx.Bool("skip-old-msgs")
|
||||
|
||||
var ts *types.TipSet
|
||||
if tss := cctx.String("tipset"); tss != "" {
|
||||
cids, err := lcli.ParseTipSetString(tss)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to parse tipset (%q): %w", tss, err)
|
||||
}
|
||||
|
||||
tsk := types.NewTipSetKey(cids...)
|
||||
|
||||
selts, err := cs.LoadTipSet(tsk)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("loading tipset: %w", err)
|
||||
}
|
||||
ts = selts
|
||||
} else {
|
||||
ts = cs.GetHeaviestTipSet()
|
||||
}
|
||||
|
||||
if fullstate {
|
||||
nroots = ts.Height() + 1
|
||||
}
|
||||
|
||||
if err := cs.Export(ctx, ts, nroots, skipoldmsgs, fi); err != nil {
|
||||
return xerrors.Errorf("export failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -33,6 +33,8 @@ func main() {
|
||||
mpoolCmd,
|
||||
genesisVerifyCmd,
|
||||
mathCmd,
|
||||
mpoolStatsCmd,
|
||||
exportChainCmd,
|
||||
}
|
||||
|
||||
app := &cli.App{
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"contrib.go.opencensus.io/exporter/prometheus"
|
||||
"github.com/ipfs/go-cid"
|
||||
logging "github.com/ipfs/go-log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.opencensus.io/stats"
|
||||
"go.opencensus.io/stats/view"
|
||||
"go.opencensus.io/tag"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
lapi "github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
)
|
||||
|
||||
var (
|
||||
MpoolAge = stats.Float64("mpoolage", "Age of messages in the mempool", stats.UnitSeconds)
|
||||
MpoolSize = stats.Int64("mpoolsize", "Number of messages in mempool", stats.UnitDimensionless)
|
||||
MpoolInboundRate = stats.Int64("inbound", "Counter for inbound messages", stats.UnitDimensionless)
|
||||
BlockInclusionRate = stats.Int64("inclusion", "Counter for message included in blocks", stats.UnitDimensionless)
|
||||
MsgWaitTime = stats.Float64("msg-wait-time", "Wait time of messages to make it into a block", stats.UnitSeconds)
|
||||
)
|
||||
|
||||
var (
|
||||
LeTag, _ = tag.NewKey("quantile")
|
||||
MTTag, _ = tag.NewKey("msg_type")
|
||||
)
|
||||
|
||||
var (
|
||||
AgeView = &view.View{
|
||||
Name: "mpool-age",
|
||||
Measure: MpoolAge,
|
||||
TagKeys: []tag.Key{LeTag, MTTag},
|
||||
Aggregation: view.LastValue(),
|
||||
}
|
||||
SizeView = &view.View{
|
||||
Name: "mpool-size",
|
||||
Measure: MpoolSize,
|
||||
TagKeys: []tag.Key{MTTag},
|
||||
Aggregation: view.LastValue(),
|
||||
}
|
||||
InboundRate = &view.View{
|
||||
Name: "msg-inbound",
|
||||
Measure: MpoolInboundRate,
|
||||
TagKeys: []tag.Key{MTTag},
|
||||
Aggregation: view.Count(),
|
||||
}
|
||||
InclusionRate = &view.View{
|
||||
Name: "msg-inclusion",
|
||||
Measure: BlockInclusionRate,
|
||||
TagKeys: []tag.Key{MTTag},
|
||||
Aggregation: view.Count(),
|
||||
}
|
||||
MsgWait = &view.View{
|
||||
Name: "msg-wait",
|
||||
Measure: MsgWaitTime,
|
||||
TagKeys: []tag.Key{MTTag},
|
||||
Aggregation: view.Distribution(10, 30, 60, 120, 240, 600, 1800, 3600),
|
||||
}
|
||||
)
|
||||
|
||||
type msgInfo struct {
|
||||
msg *types.SignedMessage
|
||||
seen time.Time
|
||||
}
|
||||
|
||||
var mpoolStatsCmd = &cli.Command{
|
||||
Name: "mpool-stats",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
logging.SetLogLevel("rpc", "ERROR")
|
||||
|
||||
if err := view.Register(AgeView, SizeView, InboundRate, InclusionRate, MsgWait); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
expo, err := prometheus.NewExporter(prometheus.Options{
|
||||
Namespace: "lotusmpool",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
http.Handle("/debug/metrics", expo)
|
||||
|
||||
go func() {
|
||||
if err := http.ListenAndServe(":10555", nil); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
api, closer, err := lcli.GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer closer()
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
|
||||
updates, err := api.MpoolSub(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mcache := make(map[address.Address]bool)
|
||||
isMiner := func(addr address.Address) (bool, error) {
|
||||
cache, ok := mcache[addr]
|
||||
if ok {
|
||||
return cache, nil
|
||||
}
|
||||
|
||||
act, err := api.StateGetActor(ctx, addr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
ism := act.Code == builtin.StorageMinerActorCodeID
|
||||
mcache[addr] = ism
|
||||
return ism, nil
|
||||
}
|
||||
|
||||
wpostTracker := make(map[cid.Cid]*msgInfo)
|
||||
tracker := make(map[cid.Cid]*msgInfo)
|
||||
tick := time.Tick(time.Second)
|
||||
for {
|
||||
select {
|
||||
case u, ok := <-updates:
|
||||
if !ok {
|
||||
return fmt.Errorf("connection with lotus node broke")
|
||||
}
|
||||
switch u.Type {
|
||||
case lapi.MpoolAdd:
|
||||
stats.Record(ctx, MpoolInboundRate.M(1))
|
||||
tracker[u.Message.Cid()] = &msgInfo{
|
||||
msg: u.Message,
|
||||
seen: time.Now(),
|
||||
}
|
||||
|
||||
if u.Message.Message.Method == builtin.MethodsMiner.SubmitWindowedPoSt {
|
||||
|
||||
miner, err := isMiner(u.Message.Message.To)
|
||||
if err != nil {
|
||||
log.Warnf("failed to determine if message target was to a miner: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if miner {
|
||||
wpostTracker[u.Message.Cid()] = &msgInfo{
|
||||
msg: u.Message,
|
||||
seen: time.Now(),
|
||||
}
|
||||
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, MpoolInboundRate.M(1))
|
||||
}
|
||||
}
|
||||
|
||||
case lapi.MpoolRemove:
|
||||
mi, ok := tracker[u.Message.Cid()]
|
||||
if ok {
|
||||
fmt.Printf("%s was in the mempool for %s (feecap=%s, prem=%s)\n", u.Message.Cid(), time.Since(mi.seen), u.Message.Message.GasFeeCap, u.Message.Message.GasPremium)
|
||||
stats.Record(ctx, BlockInclusionRate.M(1))
|
||||
stats.Record(ctx, MsgWaitTime.M(time.Since(mi.seen).Seconds()))
|
||||
delete(tracker, u.Message.Cid())
|
||||
}
|
||||
|
||||
wm, ok := wpostTracker[u.Message.Cid()]
|
||||
if ok {
|
||||
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, BlockInclusionRate.M(1))
|
||||
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, MsgWaitTime.M(time.Since(wm.seen).Seconds()))
|
||||
delete(wpostTracker, u.Message.Cid())
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unrecognized mpool update state: %d", u.Type)
|
||||
}
|
||||
case <-tick:
|
||||
var ages []time.Duration
|
||||
if len(tracker) > 0 {
|
||||
for _, v := range tracker {
|
||||
age := time.Since(v.seen)
|
||||
ages = append(ages, age)
|
||||
}
|
||||
|
||||
st := ageStats(ages)
|
||||
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "40")}, MpoolAge.M(st.Perc40.Seconds()))
|
||||
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "50")}, MpoolAge.M(st.Perc50.Seconds()))
|
||||
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "60")}, MpoolAge.M(st.Perc60.Seconds()))
|
||||
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "70")}, MpoolAge.M(st.Perc70.Seconds()))
|
||||
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "80")}, MpoolAge.M(st.Perc80.Seconds()))
|
||||
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "90")}, MpoolAge.M(st.Perc90.Seconds()))
|
||||
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "95")}, MpoolAge.M(st.Perc95.Seconds()))
|
||||
|
||||
stats.Record(ctx, MpoolSize.M(int64(len(tracker))))
|
||||
fmt.Printf("%d messages in mempool for average of %s, (%s / %s / %s)\n", st.Count, st.Average, st.Perc50, st.Perc80, st.Perc95)
|
||||
}
|
||||
|
||||
var wpages []time.Duration
|
||||
if len(wpostTracker) > 0 {
|
||||
for _, v := range wpostTracker {
|
||||
age := time.Since(v.seen)
|
||||
wpages = append(wpages, age)
|
||||
}
|
||||
|
||||
st := ageStats(wpages)
|
||||
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "40"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc40.Seconds()))
|
||||
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "50"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc50.Seconds()))
|
||||
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "60"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc60.Seconds()))
|
||||
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "70"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc70.Seconds()))
|
||||
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "80"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc80.Seconds()))
|
||||
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "90"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc90.Seconds()))
|
||||
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "95"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc95.Seconds()))
|
||||
|
||||
_ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, MpoolSize.M(int64(len(wpostTracker))))
|
||||
fmt.Printf("%d wpost messages in mempool for average of %s, (%s / %s / %s)\n", st.Count, st.Average, st.Perc50, st.Perc80, st.Perc95)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
type ageStat struct {
|
||||
Average time.Duration
|
||||
Max time.Duration
|
||||
Perc40 time.Duration
|
||||
Perc50 time.Duration
|
||||
Perc60 time.Duration
|
||||
Perc70 time.Duration
|
||||
Perc80 time.Duration
|
||||
Perc90 time.Duration
|
||||
Perc95 time.Duration
|
||||
Count int
|
||||
}
|
||||
|
||||
func ageStats(ages []time.Duration) *ageStat {
|
||||
sort.Slice(ages, func(i, j int) bool {
|
||||
return ages[i] < ages[j]
|
||||
})
|
||||
|
||||
st := ageStat{
|
||||
Count: len(ages),
|
||||
}
|
||||
var sum time.Duration
|
||||
for _, a := range ages {
|
||||
sum += a
|
||||
if a > st.Max {
|
||||
st.Max = a
|
||||
}
|
||||
}
|
||||
st.Average = sum / time.Duration(len(ages))
|
||||
|
||||
p40 := (4 * len(ages)) / 10
|
||||
p50 := len(ages) / 2
|
||||
p60 := (6 * len(ages)) / 10
|
||||
p70 := (7 * len(ages)) / 10
|
||||
p80 := (4 * len(ages)) / 5
|
||||
p90 := (9 * len(ages)) / 10
|
||||
p95 := (19 * len(ages)) / 20
|
||||
|
||||
st.Perc40 = ages[p40]
|
||||
st.Perc50 = ages[p50]
|
||||
st.Perc60 = ages[p60]
|
||||
st.Perc70 = ages[p70]
|
||||
st.Perc80 = ages[p80]
|
||||
st.Perc90 = ages[p90]
|
||||
st.Perc95 = ages[p95]
|
||||
|
||||
return &st
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
@@ -336,7 +337,7 @@ var verifRegCheckVerifierCmd = &cli.Command{
|
||||
}
|
||||
|
||||
var dcap verifreg.DataCap
|
||||
if found, err := vh.Get(adt.AddrKey(vaddr), &dcap); err != nil {
|
||||
if found, err := vh.Get(abi.AddrKey(vaddr), &dcap); err != nil {
|
||||
return err
|
||||
} else if !found {
|
||||
return fmt.Errorf("not found")
|
||||
|
||||
@@ -44,6 +44,7 @@ import (
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
||||
"github.com/filecoin-project/lotus/genesis"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/filecoin-project/lotus/miner"
|
||||
"github.com/filecoin-project/lotus/node/modules"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
@@ -179,8 +180,8 @@ var initCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
if !v.APIVersion.EqMajorMinor(build.APIVersion) {
|
||||
return xerrors.Errorf("Remote API version didn't match (local %s, remote %s)", build.APIVersion, v.APIVersion)
|
||||
if !v.APIVersion.EqMajorMinor(build.FullAPIVersion) {
|
||||
return xerrors.Errorf("Remote API version didn't match (expected %s, remote %s)", build.FullAPIVersion, v.APIVersion)
|
||||
}
|
||||
|
||||
log.Info("Initializing repo")
|
||||
@@ -459,6 +460,12 @@ func storageMinerInit(ctx context.Context, cctx *cli.Context, api lapi.FullNode,
|
||||
return err
|
||||
}
|
||||
|
||||
if jrnl, err := journal.OpenFSJournal(lr, journal.DefaultDisabledEvents); err == nil {
|
||||
journal.J = jrnl
|
||||
} else {
|
||||
return fmt.Errorf("failed to open filesystem journal: %w", err)
|
||||
}
|
||||
|
||||
m := miner.NewMiner(api, epp, a, slashfilter.New(mds))
|
||||
{
|
||||
if err := m.Start(ctx); err != nil {
|
||||
|
||||
@@ -26,6 +26,8 @@ const FlagMinerRepo = "miner-repo"
|
||||
const FlagMinerRepoDeprecation = "storagerepo"
|
||||
|
||||
func main() {
|
||||
build.RunningNodeType = build.NodeMiner
|
||||
|
||||
lotuslog.SetupLogLevels()
|
||||
|
||||
local := []*cli.Command{
|
||||
|
||||
@@ -5,16 +5,13 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
)
|
||||
@@ -203,8 +200,8 @@ var provingInfoCmd = &cli.Command{
|
||||
fmt.Printf("Current Epoch: %d\n", cd.CurrentEpoch)
|
||||
|
||||
fmt.Printf("Proving Period Boundary: %d\n", cd.PeriodStart%miner.WPoStProvingPeriod)
|
||||
fmt.Printf("Proving Period Start: %s\n", epochTime(cd.CurrentEpoch, cd.PeriodStart))
|
||||
fmt.Printf("Next Period Start: %s\n\n", epochTime(cd.CurrentEpoch, cd.PeriodStart+miner.WPoStProvingPeriod))
|
||||
fmt.Printf("Proving Period Start: %s\n", lcli.EpochTime(cd.CurrentEpoch, cd.PeriodStart))
|
||||
fmt.Printf("Next Period Start: %s\n\n", lcli.EpochTime(cd.CurrentEpoch, cd.PeriodStart+miner.WPoStProvingPeriod))
|
||||
|
||||
fmt.Printf("Faults: %d (%.2f%%)\n", faults, faultPerc)
|
||||
fmt.Printf("Recovering: %d\n", recovering)
|
||||
@@ -224,27 +221,14 @@ var provingInfoCmd = &cli.Command{
|
||||
fmt.Printf("Deadline Sectors: %d\n", curDeadlineSectors)
|
||||
}
|
||||
|
||||
fmt.Printf("Deadline Open: %s\n", epochTime(cd.CurrentEpoch, cd.Open))
|
||||
fmt.Printf("Deadline Close: %s\n", epochTime(cd.CurrentEpoch, cd.Close))
|
||||
fmt.Printf("Deadline Challenge: %s\n", epochTime(cd.CurrentEpoch, cd.Challenge))
|
||||
fmt.Printf("Deadline FaultCutoff: %s\n", epochTime(cd.CurrentEpoch, cd.FaultCutoff))
|
||||
fmt.Printf("Deadline Open: %s\n", lcli.EpochTime(cd.CurrentEpoch, cd.Open))
|
||||
fmt.Printf("Deadline Close: %s\n", lcli.EpochTime(cd.CurrentEpoch, cd.Close))
|
||||
fmt.Printf("Deadline Challenge: %s\n", lcli.EpochTime(cd.CurrentEpoch, cd.Challenge))
|
||||
fmt.Printf("Deadline FaultCutoff: %s\n", lcli.EpochTime(cd.CurrentEpoch, cd.FaultCutoff))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func epochTime(curr, e abi.ChainEpoch) string {
|
||||
switch {
|
||||
case curr > e:
|
||||
return fmt.Sprintf("%d (%s ago)", e, time.Second*time.Duration(int64(build.BlockDelaySecs)*int64(curr-e)))
|
||||
case curr == e:
|
||||
return fmt.Sprintf("%d (now)", e)
|
||||
case curr < e:
|
||||
return fmt.Sprintf("%d (in %s)", e, time.Second*time.Duration(int64(build.BlockDelaySecs)*int64(e-curr)))
|
||||
}
|
||||
|
||||
panic("math broke")
|
||||
}
|
||||
|
||||
var provingDeadlinesCmd = &cli.Command{
|
||||
Name: "deadlines",
|
||||
Usage: "View the current proving period deadlines information",
|
||||
|
||||
@@ -5,9 +5,12 @@ import (
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/docker/go-units"
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
)
|
||||
|
||||
@@ -17,6 +20,8 @@ var retrievalDealsCmd = &cli.Command{
|
||||
Subcommands: []*cli.Command{
|
||||
retrievalDealSelectionCmd,
|
||||
retrievalDealsListCmd,
|
||||
retrievalSetAskCmd,
|
||||
retrievalGetAskCmd,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -154,3 +159,112 @@ var retrievalDealsListCmd = &cli.Command{
|
||||
return w.Flush()
|
||||
},
|
||||
}
|
||||
|
||||
var retrievalSetAskCmd = &cli.Command{
|
||||
Name: "set-ask",
|
||||
Usage: "Configure the provider's retrieval ask",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "price",
|
||||
Usage: "Set the price of the ask for retrievals (FIL/GiB)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "unseal-price",
|
||||
Usage: "Set the price to unseal",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "payment-interval",
|
||||
Usage: "Set the payment interval (in bytes) for retrieval",
|
||||
DefaultText: "1MiB",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "payment-interval-increase",
|
||||
Usage: "Set the payment interval increase (in bytes) for retrieval",
|
||||
DefaultText: "1MiB",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
ctx := lcli.DaemonContext(cctx)
|
||||
|
||||
api, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
ask, err := api.MarketGetRetrievalAsk(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cctx.IsSet("price") {
|
||||
v, err := types.ParseFIL(cctx.String("price"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ask.PricePerByte = types.BigDiv(types.BigInt(v), types.NewInt(1<<30))
|
||||
}
|
||||
|
||||
if cctx.IsSet("unseal-price") {
|
||||
v, err := types.ParseFIL(cctx.String("unseal-price"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ask.UnsealPrice = abi.TokenAmount(v)
|
||||
}
|
||||
|
||||
if cctx.IsSet("payment-interval") {
|
||||
v, err := units.RAMInBytes(cctx.String("payment-interval"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ask.PaymentInterval = uint64(v)
|
||||
}
|
||||
|
||||
if cctx.IsSet("payment-interval-increase") {
|
||||
v, err := units.RAMInBytes(cctx.String("payment-interval-increase"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ask.PaymentIntervalIncrease = uint64(v)
|
||||
}
|
||||
|
||||
return api.MarketSetRetrievalAsk(ctx, ask)
|
||||
},
|
||||
}
|
||||
|
||||
var retrievalGetAskCmd = &cli.Command{
|
||||
Name: "get-ask",
|
||||
Usage: "Get the provider's current retrieval ask",
|
||||
Flags: []cli.Flag{},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
ctx := lcli.DaemonContext(cctx)
|
||||
|
||||
api, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
ask, err := api.MarketGetRetrievalAsk(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0)
|
||||
fmt.Fprintf(w, "Price per Byte\tUnseal Price\tPayment Interval\tPayment Interval Increase\n")
|
||||
if ask == nil {
|
||||
fmt.Fprintf(w, "<miner does not have an retrieval ask set>\n")
|
||||
return w.Flush()
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n",
|
||||
types.FIL(ask.PricePerByte),
|
||||
types.FIL(ask.UnsealPrice),
|
||||
units.BytesSize(float64(ask.PaymentInterval)),
|
||||
units.BytesSize(float64(ask.PaymentIntervalIncrease)),
|
||||
)
|
||||
return w.Flush()
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
@@ -77,8 +77,8 @@ var runCmd = &cli.Command{
|
||||
}
|
||||
}
|
||||
|
||||
if v.APIVersion != build.APIVersion {
|
||||
return xerrors.Errorf("lotus-daemon API version doesn't match: local: %s", api.Version{APIVersion: build.APIVersion})
|
||||
if v.APIVersion != build.FullAPIVersion {
|
||||
return xerrors.Errorf("lotus-daemon API version doesn't match: expected: %s", api.Version{APIVersion: build.FullAPIVersion})
|
||||
}
|
||||
|
||||
log.Info("Checking full node sync status")
|
||||
|
||||
@@ -46,6 +46,7 @@ func init() {
|
||||
return xerrors.Errorf("StateMinerWorker: %w", err)
|
||||
}
|
||||
|
||||
// XXX: This can't be right
|
||||
rand, err := api.ChainGetRandomnessFromTickets(ctx, head.Key(), crypto.DomainSeparationTag_TicketProduction, head.Height(), addr.Bytes())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get randomness: %w", err)
|
||||
|
||||
@@ -16,6 +16,8 @@ import (
|
||||
var AdvanceBlockCmd *cli.Command
|
||||
|
||||
func main() {
|
||||
build.RunningNodeType = build.NodeFull
|
||||
|
||||
lotuslog.SetupLogLevels()
|
||||
|
||||
local := []*cli.Command{
|
||||
|
||||
+62
-16
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
typegen "github.com/whyrusleeping/cbor-gen"
|
||||
@@ -62,6 +61,12 @@ const (
|
||||
// MethodMutateState is the identifier for the method that attempts to mutate
|
||||
// a state value in the actor.
|
||||
MethodMutateState
|
||||
// MethodAbortWith is the identifier for the method that panics optionally with
|
||||
// a passed exit code.
|
||||
MethodAbortWith
|
||||
// MethodInspectRuntime is the identifier for the method that returns the
|
||||
// current runtime values.
|
||||
MethodInspectRuntime
|
||||
)
|
||||
|
||||
// Exports defines the methods this actor exposes publicly.
|
||||
@@ -74,6 +79,8 @@ func (a Actor) Exports() []interface{} {
|
||||
MethodDeleteActor: a.DeleteActor,
|
||||
MethodSend: a.Send,
|
||||
MethodMutateState: a.MutateState,
|
||||
MethodAbortWith: a.AbortWith,
|
||||
MethodInspectRuntime: a.InspectRuntime,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,18 +104,14 @@ type SendReturn struct {
|
||||
// passed parameters.
|
||||
func (a Actor) Send(rt runtime.Runtime, args *SendArgs) *SendReturn {
|
||||
rt.ValidateImmediateCallerAcceptAny()
|
||||
ret, code := rt.Send(
|
||||
var out runtime.CBORBytes
|
||||
code := rt.Send(
|
||||
args.To,
|
||||
args.Method,
|
||||
runtime.CBORBytes(args.Params),
|
||||
args.Value,
|
||||
&out,
|
||||
)
|
||||
var out runtime.CBORBytes
|
||||
if ret != nil {
|
||||
if err := ret.Into(&out); err != nil {
|
||||
rt.Abortf(exitcode.ErrIllegalState, "failed to unmarshal send return: %v", err)
|
||||
}
|
||||
}
|
||||
return &SendReturn{
|
||||
Return: out,
|
||||
Code: code,
|
||||
@@ -116,7 +119,7 @@ func (a Actor) Send(rt runtime.Runtime, args *SendArgs) *SendReturn {
|
||||
}
|
||||
|
||||
// Constructor will panic because the Chaos actor is a singleton.
|
||||
func (a Actor) Constructor(_ runtime.Runtime, _ *adt.EmptyValue) *adt.EmptyValue {
|
||||
func (a Actor) Constructor(_ runtime.Runtime, _ *abi.EmptyValue) *abi.EmptyValue {
|
||||
panic("constructor should not be called; the Chaos actor is a singleton actor")
|
||||
}
|
||||
|
||||
@@ -127,7 +130,7 @@ func (a Actor) Constructor(_ runtime.Runtime, _ *adt.EmptyValue) *adt.EmptyValue
|
||||
// CallerValidationBranchAddrNilSet validates against an empty caller
|
||||
// address set.
|
||||
// CallerValidationBranchTypeNilSet validates against an empty caller type set.
|
||||
func (a Actor) CallerValidation(rt runtime.Runtime, branch *typegen.CborInt) *adt.EmptyValue {
|
||||
func (a Actor) CallerValidation(rt runtime.Runtime, branch *typegen.CborInt) *abi.EmptyValue {
|
||||
switch CallerValidationBranch(*branch) {
|
||||
case CallerValidationBranchNone:
|
||||
case CallerValidationBranchTwice:
|
||||
@@ -157,7 +160,7 @@ type CreateActorArgs struct {
|
||||
}
|
||||
|
||||
// CreateActor creates an actor with the supplied CID and Address.
|
||||
func (a Actor) CreateActor(rt runtime.Runtime, args *CreateActorArgs) *adt.EmptyValue {
|
||||
func (a Actor) CreateActor(rt runtime.Runtime, args *CreateActorArgs) *abi.EmptyValue {
|
||||
rt.ValidateImmediateCallerAcceptAny()
|
||||
|
||||
var (
|
||||
@@ -195,7 +198,7 @@ func (a Actor) ResolveAddress(rt runtime.Runtime, args *address.Address) *Resolv
|
||||
|
||||
// DeleteActor deletes the executing actor from the state tree, transferring any
|
||||
// balance to beneficiary.
|
||||
func (a Actor) DeleteActor(rt runtime.Runtime, beneficiary *address.Address) *adt.EmptyValue {
|
||||
func (a Actor) DeleteActor(rt runtime.Runtime, beneficiary *address.Address) *abi.EmptyValue {
|
||||
rt.ValidateImmediateCallerAcceptAny()
|
||||
rt.DeleteActor(*beneficiary)
|
||||
return nil
|
||||
@@ -209,19 +212,19 @@ type MutateStateArgs struct {
|
||||
}
|
||||
|
||||
// MutateState attempts to mutate a state value in the actor.
|
||||
func (a Actor) MutateState(rt runtime.Runtime, args *MutateStateArgs) *adt.EmptyValue {
|
||||
func (a Actor) MutateState(rt runtime.Runtime, args *MutateStateArgs) *abi.EmptyValue {
|
||||
rt.ValidateImmediateCallerAcceptAny()
|
||||
var st State
|
||||
switch args.Branch {
|
||||
case MutateInTransaction:
|
||||
rt.State().Transaction(&st, func() {
|
||||
rt.StateTransaction(&st, func() {
|
||||
st.Value = args.Value
|
||||
})
|
||||
case MutateReadonly:
|
||||
rt.State().Readonly(&st)
|
||||
rt.StateReadonly(&st)
|
||||
st.Value = args.Value
|
||||
case MutateAfterTransaction:
|
||||
rt.State().Transaction(&st, func() {
|
||||
rt.StateTransaction(&st, func() {
|
||||
st.Value = args.Value + "-in"
|
||||
})
|
||||
st.Value = args.Value
|
||||
@@ -230,3 +233,46 @@ func (a Actor) MutateState(rt runtime.Runtime, args *MutateStateArgs) *adt.Empty
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AbortWithArgs are the arguments to the Actor.AbortWith method, specifying the
|
||||
// exit code to (optionally) abort with and the message.
|
||||
type AbortWithArgs struct {
|
||||
Code exitcode.ExitCode
|
||||
Message string
|
||||
Uncontrolled bool
|
||||
}
|
||||
|
||||
// AbortWith simply causes a panic with the passed exit code.
|
||||
func (a Actor) AbortWith(rt runtime.Runtime, args *AbortWithArgs) *abi.EmptyValue {
|
||||
if args.Uncontrolled { // uncontrolled abort: directly panic
|
||||
panic(args.Message)
|
||||
} else {
|
||||
rt.Abortf(args.Code, args.Message)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InspectRuntimeReturn is the return value for the Actor.InspectRuntime method.
|
||||
type InspectRuntimeReturn struct {
|
||||
Caller address.Address
|
||||
Receiver address.Address
|
||||
ValueReceived abi.TokenAmount
|
||||
CurrEpoch abi.ChainEpoch
|
||||
CurrentBalance abi.TokenAmount
|
||||
State State
|
||||
}
|
||||
|
||||
// InspectRuntime returns a copy of the serializable values available in the Runtime.
|
||||
func (a Actor) InspectRuntime(rt runtime.Runtime, _ *abi.EmptyValue) *InspectRuntimeReturn {
|
||||
rt.ValidateImmediateCallerAcceptAny()
|
||||
var st State
|
||||
rt.StateReadonly(&st)
|
||||
return &InspectRuntimeReturn{
|
||||
Caller: rt.Caller(),
|
||||
Receiver: rt.Receiver(),
|
||||
ValueReceived: rt.ValueReceived(),
|
||||
CurrEpoch: rt.CurrEpoch(),
|
||||
CurrentBalance: rt.CurrentBalance(),
|
||||
State: st,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
package chaos
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/support/mock"
|
||||
atesting "github.com/filecoin-project/specs-actors/support/testing"
|
||||
)
|
||||
|
||||
func TestSingleton(t *testing.T) {
|
||||
receiver := atesting.NewIDAddr(t, 100)
|
||||
builder := mock.NewBuilder(context.Background(), receiver)
|
||||
|
||||
rt := builder.Build(t)
|
||||
var a Actor
|
||||
|
||||
msg := "constructor should not be called; the Chaos actor is a singleton actor"
|
||||
rt.ExpectAssertionFailure(msg, func() {
|
||||
rt.Call(a.Constructor, abi.Empty)
|
||||
})
|
||||
rt.Verify()
|
||||
}
|
||||
|
||||
func TestDeleteActor(t *testing.T) {
|
||||
receiver := atesting.NewIDAddr(t, 100)
|
||||
beneficiary := atesting.NewIDAddr(t, 101)
|
||||
builder := mock.NewBuilder(context.Background(), receiver)
|
||||
|
||||
rt := builder.Build(t)
|
||||
var a Actor
|
||||
|
||||
rt.ExpectValidateCallerAny()
|
||||
rt.ExpectDeleteActor(beneficiary)
|
||||
rt.Call(a.DeleteActor, &beneficiary)
|
||||
rt.Verify()
|
||||
}
|
||||
|
||||
func TestMutateStateInTransaction(t *testing.T) {
|
||||
receiver := atesting.NewIDAddr(t, 100)
|
||||
builder := mock.NewBuilder(context.Background(), receiver)
|
||||
|
||||
rt := builder.Build(t)
|
||||
var a Actor
|
||||
|
||||
rt.ExpectValidateCallerAny()
|
||||
rt.StateCreate(&State{})
|
||||
|
||||
val := "__mutstat test"
|
||||
rt.Call(a.MutateState, &MutateStateArgs{
|
||||
Value: val,
|
||||
Branch: MutateInTransaction,
|
||||
})
|
||||
|
||||
var st State
|
||||
rt.GetState(&st)
|
||||
|
||||
if st.Value != val {
|
||||
t.Fatal("state was not updated")
|
||||
}
|
||||
|
||||
rt.Verify()
|
||||
}
|
||||
|
||||
func TestMutateStateAfterTransaction(t *testing.T) {
|
||||
receiver := atesting.NewIDAddr(t, 100)
|
||||
builder := mock.NewBuilder(context.Background(), receiver)
|
||||
|
||||
rt := builder.Build(t)
|
||||
var a Actor
|
||||
|
||||
rt.ExpectValidateCallerAny()
|
||||
rt.StateCreate(&State{})
|
||||
|
||||
val := "__mutstat test"
|
||||
rt.Call(a.MutateState, &MutateStateArgs{
|
||||
Value: val,
|
||||
Branch: MutateAfterTransaction,
|
||||
})
|
||||
|
||||
var st State
|
||||
rt.GetState(&st)
|
||||
|
||||
// state should be updated successfully _in_ the transaction but not outside
|
||||
if st.Value != val+"-in" {
|
||||
t.Fatal("state was not updated")
|
||||
}
|
||||
|
||||
rt.Verify()
|
||||
}
|
||||
|
||||
func TestMutateStateReadonly(t *testing.T) {
|
||||
receiver := atesting.NewIDAddr(t, 100)
|
||||
builder := mock.NewBuilder(context.Background(), receiver)
|
||||
|
||||
rt := builder.Build(t)
|
||||
var a Actor
|
||||
|
||||
rt.ExpectValidateCallerAny()
|
||||
rt.StateCreate(&State{})
|
||||
|
||||
val := "__mutstat test"
|
||||
rt.Call(a.MutateState, &MutateStateArgs{
|
||||
Value: val,
|
||||
Branch: MutateReadonly,
|
||||
})
|
||||
|
||||
var st State
|
||||
rt.GetState(&st)
|
||||
|
||||
if st.Value != "" {
|
||||
t.Fatal("state was not expected to be updated")
|
||||
}
|
||||
|
||||
rt.Verify()
|
||||
}
|
||||
|
||||
func TestAbortWith(t *testing.T) {
|
||||
receiver := atesting.NewIDAddr(t, 100)
|
||||
builder := mock.NewBuilder(context.Background(), receiver)
|
||||
|
||||
rt := builder.Build(t)
|
||||
var a Actor
|
||||
|
||||
msg := "__test forbidden"
|
||||
rt.ExpectAbortContainsMessage(exitcode.ErrForbidden, msg, func() {
|
||||
rt.Call(a.AbortWith, &AbortWithArgs{
|
||||
Code: exitcode.ErrForbidden,
|
||||
Message: msg,
|
||||
Uncontrolled: false,
|
||||
})
|
||||
})
|
||||
rt.Verify()
|
||||
}
|
||||
|
||||
func TestAbortWithUncontrolled(t *testing.T) {
|
||||
receiver := atesting.NewIDAddr(t, 100)
|
||||
builder := mock.NewBuilder(context.Background(), receiver)
|
||||
|
||||
rt := builder.Build(t)
|
||||
var a Actor
|
||||
|
||||
msg := "__test uncontrolled panic"
|
||||
rt.ExpectAssertionFailure(msg, func() {
|
||||
rt.Call(a.AbortWith, &AbortWithArgs{
|
||||
Message: msg,
|
||||
Uncontrolled: true,
|
||||
})
|
||||
})
|
||||
rt.Verify()
|
||||
}
|
||||
|
||||
func TestInspectRuntime(t *testing.T) {
|
||||
caller := atesting.NewIDAddr(t, 100)
|
||||
receiver := atesting.NewIDAddr(t, 101)
|
||||
builder := mock.NewBuilder(context.Background(), receiver)
|
||||
|
||||
rt := builder.Build(t)
|
||||
rt.SetCaller(caller, builtin.AccountActorCodeID)
|
||||
rt.StateCreate(&State{})
|
||||
var a Actor
|
||||
|
||||
rt.ExpectValidateCallerAny()
|
||||
ret := rt.Call(a.InspectRuntime, abi.Empty)
|
||||
rtr, ok := ret.(*InspectRuntimeReturn)
|
||||
if !ok {
|
||||
t.Fatal("invalid return value")
|
||||
}
|
||||
if rtr.Caller != caller {
|
||||
t.Fatal("unexpected runtime caller")
|
||||
}
|
||||
if rtr.Receiver != receiver {
|
||||
t.Fatal("unexpected runtime receiver")
|
||||
}
|
||||
rt.Verify()
|
||||
}
|
||||
@@ -6,10 +6,10 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
abi "github.com/filecoin-project/go-state-types/abi"
|
||||
exitcode "github.com/filecoin-project/go-state-types/exitcode"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
xerrors "golang.org/x/xerrors"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
var _ = xerrors.Errorf
|
||||
@@ -614,3 +614,261 @@ func (t *MutateStateArgs) UnmarshalCBOR(r io.Reader) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var lengthBufAbortWithArgs = []byte{131}
|
||||
|
||||
func (t *AbortWithArgs) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write(lengthBufAbortWithArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scratch := make([]byte, 9)
|
||||
|
||||
// t.Code (exitcode.ExitCode) (int64)
|
||||
if t.Code >= 0 {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Code)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.Code-1)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// t.Message (string) (string)
|
||||
if len(t.Message) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field t.Message was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len(t.Message))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, string(t.Message)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.Uncontrolled (bool) (bool)
|
||||
if err := cbg.WriteBool(w, t.Uncontrolled); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *AbortWithArgs) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = AbortWithArgs{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("cbor input should be of type array")
|
||||
}
|
||||
|
||||
if extra != 3 {
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
}
|
||||
|
||||
// t.Code (exitcode.ExitCode) (int64)
|
||||
{
|
||||
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
var extraI int64
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch maj {
|
||||
case cbg.MajUnsignedInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 positive overflow")
|
||||
}
|
||||
case cbg.MajNegativeInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 negative oveflow")
|
||||
}
|
||||
extraI = -1 - extraI
|
||||
default:
|
||||
return fmt.Errorf("wrong type for int64 field: %d", maj)
|
||||
}
|
||||
|
||||
t.Code = exitcode.ExitCode(extraI)
|
||||
}
|
||||
// t.Message (string) (string)
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadStringBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.Message = string(sval)
|
||||
}
|
||||
// t.Uncontrolled (bool) (bool)
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajOther {
|
||||
return fmt.Errorf("booleans must be major type 7")
|
||||
}
|
||||
switch extra {
|
||||
case 20:
|
||||
t.Uncontrolled = false
|
||||
case 21:
|
||||
t.Uncontrolled = true
|
||||
default:
|
||||
return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var lengthBufInspectRuntimeReturn = []byte{134}
|
||||
|
||||
func (t *InspectRuntimeReturn) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write(lengthBufInspectRuntimeReturn); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scratch := make([]byte, 9)
|
||||
|
||||
// t.Caller (address.Address) (struct)
|
||||
if err := t.Caller.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.Receiver (address.Address) (struct)
|
||||
if err := t.Receiver.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.ValueReceived (big.Int) (struct)
|
||||
if err := t.ValueReceived.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.CurrEpoch (abi.ChainEpoch) (int64)
|
||||
if t.CurrEpoch >= 0 {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.CurrEpoch)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.CurrEpoch-1)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// t.CurrentBalance (big.Int) (struct)
|
||||
if err := t.CurrentBalance.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.State (chaos.State) (struct)
|
||||
if err := t.State.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *InspectRuntimeReturn) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = InspectRuntimeReturn{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("cbor input should be of type array")
|
||||
}
|
||||
|
||||
if extra != 6 {
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
}
|
||||
|
||||
// t.Caller (address.Address) (struct)
|
||||
|
||||
{
|
||||
|
||||
if err := t.Caller.UnmarshalCBOR(br); err != nil {
|
||||
return xerrors.Errorf("unmarshaling t.Caller: %w", err)
|
||||
}
|
||||
|
||||
}
|
||||
// t.Receiver (address.Address) (struct)
|
||||
|
||||
{
|
||||
|
||||
if err := t.Receiver.UnmarshalCBOR(br); err != nil {
|
||||
return xerrors.Errorf("unmarshaling t.Receiver: %w", err)
|
||||
}
|
||||
|
||||
}
|
||||
// t.ValueReceived (big.Int) (struct)
|
||||
|
||||
{
|
||||
|
||||
if err := t.ValueReceived.UnmarshalCBOR(br); err != nil {
|
||||
return xerrors.Errorf("unmarshaling t.ValueReceived: %w", err)
|
||||
}
|
||||
|
||||
}
|
||||
// t.CurrEpoch (abi.ChainEpoch) (int64)
|
||||
{
|
||||
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
var extraI int64
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch maj {
|
||||
case cbg.MajUnsignedInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 positive overflow")
|
||||
}
|
||||
case cbg.MajNegativeInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 negative oveflow")
|
||||
}
|
||||
extraI = -1 - extraI
|
||||
default:
|
||||
return fmt.Errorf("wrong type for int64 field: %d", maj)
|
||||
}
|
||||
|
||||
t.CurrEpoch = abi.ChainEpoch(extraI)
|
||||
}
|
||||
// t.CurrentBalance (big.Int) (struct)
|
||||
|
||||
{
|
||||
|
||||
if err := t.CurrentBalance.UnmarshalCBOR(br); err != nil {
|
||||
return xerrors.Errorf("unmarshaling t.CurrentBalance: %w", err)
|
||||
}
|
||||
|
||||
}
|
||||
// t.State (chaos.State) (struct)
|
||||
|
||||
{
|
||||
|
||||
if err := t.State.UnmarshalCBOR(br); err != nil {
|
||||
return xerrors.Errorf("unmarshaling t.State: %w", err)
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ func main() {
|
||||
chaos.SendArgs{},
|
||||
chaos.SendReturn{},
|
||||
chaos.MutateStateArgs{},
|
||||
chaos.AbortWithArgs{},
|
||||
chaos.InspectRuntimeReturn{},
|
||||
); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -75,10 +75,14 @@
|
||||
* [MpoolSetConfig](#MpoolSetConfig)
|
||||
* [MpoolSub](#MpoolSub)
|
||||
* [Msig](#Msig)
|
||||
* [MsigAddApprove](#MsigAddApprove)
|
||||
* [MsigAddCancel](#MsigAddCancel)
|
||||
* [MsigAddPropose](#MsigAddPropose)
|
||||
* [MsigApprove](#MsigApprove)
|
||||
* [MsigCancel](#MsigCancel)
|
||||
* [MsigCreate](#MsigCreate)
|
||||
* [MsigGetAvailableBalance](#MsigGetAvailableBalance)
|
||||
* [MsigGetVested](#MsigGetVested)
|
||||
* [MsigPropose](#MsigPropose)
|
||||
* [MsigSwapApprove](#MsigSwapApprove)
|
||||
* [MsigSwapCancel](#MsigSwapCancel)
|
||||
@@ -144,6 +148,7 @@
|
||||
* [StateMinerRecoveries](#StateMinerRecoveries)
|
||||
* [StateMinerSectorCount](#StateMinerSectorCount)
|
||||
* [StateMinerSectors](#StateMinerSectors)
|
||||
* [StateMsgGasCost](#StateMsgGasCost)
|
||||
* [StateNetworkName](#StateNetworkName)
|
||||
* [StateReadState](#StateReadState)
|
||||
* [StateReplay](#StateReplay)
|
||||
@@ -207,7 +212,7 @@ Response:
|
||||
```json
|
||||
{
|
||||
"Version": "string value",
|
||||
"APIVersion": 3584,
|
||||
"APIVersion": 3840,
|
||||
"BlockDelay": 42
|
||||
}
|
||||
```
|
||||
@@ -280,6 +285,7 @@ ChainExport returns a stream of bytes with CAR dump of chain data.
|
||||
The exported chain data includes the header chain from the given tipset
|
||||
back to genesis, the entire genesis state, and the most recent 'nroots'
|
||||
state trees.
|
||||
If oldmsgskip is set, messages from before the requested roots are also not included.
|
||||
|
||||
|
||||
Perms: read
|
||||
@@ -288,6 +294,7 @@ Inputs:
|
||||
```json
|
||||
[
|
||||
10101,
|
||||
true,
|
||||
[
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
@@ -1839,6 +1846,84 @@ The Msig methods are used to interact with multisig wallets on the
|
||||
filecoin network
|
||||
|
||||
|
||||
### MsigAddApprove
|
||||
MsigAddApprove approves a previously proposed AddSigner message
|
||||
It takes the following params: <multisig address>, <sender address of the approve msg>, <proposed message ID>,
|
||||
<proposer address>, <new signer>, <whether the number of required signers should be increased>
|
||||
|
||||
|
||||
Perms: sign
|
||||
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
"t01234",
|
||||
"t01234",
|
||||
42,
|
||||
"t01234",
|
||||
"t01234",
|
||||
true
|
||||
]
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
```
|
||||
|
||||
### MsigAddCancel
|
||||
MsigAddCancel cancels a previously proposed AddSigner message
|
||||
It takes the following params: <multisig address>, <sender address of the cancel msg>, <proposed message ID>,
|
||||
<new signer>, <whether the number of required signers should be increased>
|
||||
|
||||
|
||||
Perms: sign
|
||||
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
"t01234",
|
||||
"t01234",
|
||||
42,
|
||||
"t01234",
|
||||
true
|
||||
]
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
```
|
||||
|
||||
### MsigAddPropose
|
||||
MsigAddPropose proposes adding a signer in the multisig
|
||||
It takes the following params: <multisig address>, <sender address of the propose msg>,
|
||||
<new signer>, <whether the number of required signers should be increased>
|
||||
|
||||
|
||||
Perms: sign
|
||||
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
"t01234",
|
||||
"t01234",
|
||||
"t01234",
|
||||
true
|
||||
]
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
```
|
||||
|
||||
### MsigApprove
|
||||
MsigApprove approves a previously-proposed multisig message
|
||||
It takes the following params: <multisig address>, <proposed message ID>, <proposer address>, <recipient address>, <value to transfer>,
|
||||
@@ -1946,6 +2031,38 @@ Inputs:
|
||||
|
||||
Response: `"0"`
|
||||
|
||||
### MsigGetVested
|
||||
MsigGetVested returns the amount of FIL that vested in a multisig in a certain period.
|
||||
It takes the following params: <multisig address>, <start epoch>, <end epoch>
|
||||
|
||||
|
||||
Perms: read
|
||||
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
"t01234",
|
||||
[
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
{
|
||||
"/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
{
|
||||
"/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve"
|
||||
}
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
Response: `"0"`
|
||||
|
||||
### MsigPropose
|
||||
MsigPropose proposes a multisig message
|
||||
It takes the following params: <multisig address>, <recipient address>, <value to transfer>,
|
||||
@@ -1976,7 +2093,7 @@ Response:
|
||||
### MsigSwapApprove
|
||||
MsigSwapApprove approves a previously proposed SwapSigner
|
||||
It takes the following params: <multisig address>, <sender address of the approve msg>, <proposed message ID>,
|
||||
<proposer address>, <old signer> <new signer>
|
||||
<proposer address>, <old signer>, <new signer>
|
||||
|
||||
|
||||
Perms: sign
|
||||
@@ -2003,7 +2120,7 @@ Response:
|
||||
### MsigSwapCancel
|
||||
MsigSwapCancel cancels a previously proposed SwapSigner message
|
||||
It takes the following params: <multisig address>, <sender address of the cancel msg>, <proposed message ID>,
|
||||
<old signer> <new signer>
|
||||
<old signer>, <new signer>
|
||||
|
||||
|
||||
Perms: sign
|
||||
@@ -2029,7 +2146,7 @@ Response:
|
||||
### MsigSwapPropose
|
||||
MsigSwapPropose proposes swapping 2 signers in the multisig
|
||||
It takes the following params: <multisig address>, <sender address of the propose msg>,
|
||||
<old signer> <new signer>
|
||||
<old signer>, <new signer>
|
||||
|
||||
|
||||
Perms: sign
|
||||
@@ -2259,7 +2376,12 @@ There are not yet any comments for this method.
|
||||
|
||||
Perms: sign
|
||||
|
||||
Inputs: `null`
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
"t01234"
|
||||
]
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
@@ -2283,6 +2405,7 @@ Perms: sign
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
"t01234",
|
||||
"t01234"
|
||||
]
|
||||
```
|
||||
@@ -3519,7 +3642,12 @@ Response:
|
||||
"Open": 10101,
|
||||
"Close": 10101,
|
||||
"Challenge": 10101,
|
||||
"FaultCutoff": 10101
|
||||
"FaultCutoff": 10101,
|
||||
"WPoStPeriodDeadlines": 42,
|
||||
"WPoStProvingPeriod": 10101,
|
||||
"WPoStChallengeWindow": 10101,
|
||||
"WPoStChallengeLookback": 10101,
|
||||
"FaultDeclarationCutoff": 10101
|
||||
}
|
||||
```
|
||||
|
||||
@@ -3610,6 +3738,45 @@ Inputs:
|
||||
|
||||
Response: `null`
|
||||
|
||||
### StateMsgGasCost
|
||||
StateMsgGasCost searches for a message in the chain, and returns details of the messages gas costs, including the penalty and miner tip
|
||||
|
||||
|
||||
Perms: read
|
||||
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
[
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
{
|
||||
"/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve"
|
||||
}
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"Message": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"GasUsed": "0",
|
||||
"BaseFeeBurn": "0",
|
||||
"OverEstimationBurn": "0",
|
||||
"MinerPenalty": "0",
|
||||
"MinerTip": "0",
|
||||
"Refund": "0",
|
||||
"TotalCost": "0"
|
||||
}
|
||||
```
|
||||
|
||||
### StateNetworkName
|
||||
StateNetworkName returns the name of the network the node is synced to
|
||||
|
||||
|
||||
+1
Submodule extern/fil-blst added at 5f93488fc0
Vendored
+1
-1
Submodule extern/filecoin-ffi updated: 4056910460...f640612a1a
+1
Submodule extern/oni added at 8b7e7d438c
+51
-46
@@ -168,50 +168,34 @@ func (s *seal) unseal(t *testing.T, sb *Sealer, sp *basicfs.Provider, si abi.Sec
|
||||
}
|
||||
}
|
||||
|
||||
func post(t *testing.T, sealer *Sealer, seals ...seal) time.Time {
|
||||
/*randomness := abi.PoStRandomness{0, 9, 2, 7, 6, 5, 4, 3, 2, 1, 0, 9, 8, 7, 6, 45, 3, 2, 1, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 7}
|
||||
func post(t *testing.T, sealer *Sealer, skipped []abi.SectorID, seals ...seal) {
|
||||
randomness := abi.PoStRandomness{0, 9, 2, 7, 6, 5, 4, 3, 2, 1, 0, 9, 8, 7, 6, 45, 3, 2, 1, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 7}
|
||||
|
||||
sis := make([]abi.SectorInfo, len(seals))
|
||||
sis := make([]saproof.SectorInfo, len(seals))
|
||||
for i, s := range seals {
|
||||
sis[i] = abi.SectorInfo{
|
||||
RegisteredProof: sealProofType,
|
||||
SectorNumber: s.id.Number,
|
||||
SealedCID: s.cids.Sealed,
|
||||
sis[i] = saproof.SectorInfo{
|
||||
SealProof: sealProofType,
|
||||
SectorNumber: s.id.Number,
|
||||
SealedCID: s.cids.Sealed,
|
||||
}
|
||||
}
|
||||
|
||||
candidates, err := sealer.GenerateEPostCandidates(context.TODO(), seals[0].id.Miner, sis, randomness, []abi.SectorNumber{})
|
||||
if err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
}*/
|
||||
|
||||
fmt.Println("skipping post")
|
||||
|
||||
genCandidates := time.Now()
|
||||
|
||||
/*if len(candidates) != 1 {
|
||||
t.Fatal("expected 1 candidate")
|
||||
proofs, skp, err := sealer.GenerateWindowPoSt(context.TODO(), seals[0].id.Miner, sis, randomness)
|
||||
if len(skipped) > 0 {
|
||||
require.Error(t, err)
|
||||
require.EqualValues(t, skipped, skp)
|
||||
return
|
||||
}
|
||||
|
||||
candidatesPrime := make([]abi.PoStCandidate, len(candidates))
|
||||
for idx := range candidatesPrime {
|
||||
candidatesPrime[idx] = candidates[idx].Candidate
|
||||
}
|
||||
|
||||
proofs, err := sealer.ComputeElectionPoSt(context.TODO(), seals[0].id.Miner, sis, randomness, candidatesPrime)
|
||||
if err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
}
|
||||
|
||||
ePoStChallengeCount := ElectionPostChallengeCount(uint64(len(sis)), 0)
|
||||
|
||||
ok, err := ProofVerifier.VerifyElectionPost(context.TODO(), abi.PoStVerifyInfo{
|
||||
Randomness: randomness,
|
||||
Candidates: candidatesPrime,
|
||||
Proofs: proofs,
|
||||
EligibleSectors: sis,
|
||||
Prover: seals[0].id.Miner,
|
||||
ChallengeCount: ePoStChallengeCount,
|
||||
ok, err := ProofVerifier.VerifyWindowPoSt(context.TODO(), saproof.WindowPoStVerifyInfo{
|
||||
Randomness: randomness,
|
||||
Proofs: proofs,
|
||||
ChallengedSectors: sis,
|
||||
Prover: seals[0].id.Miner,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
@@ -219,8 +203,21 @@ func post(t *testing.T, sealer *Sealer, seals ...seal) time.Time {
|
||||
if !ok {
|
||||
t.Fatal("bad post")
|
||||
}
|
||||
*/
|
||||
return genCandidates
|
||||
}
|
||||
|
||||
func corrupt(t *testing.T, sealer *Sealer, id abi.SectorID) {
|
||||
paths, done, err := sealer.sectors.AcquireSector(context.Background(), id, stores.FTSealed, 0, stores.PathStorage)
|
||||
require.NoError(t, err)
|
||||
defer done()
|
||||
|
||||
log.Infof("corrupt %s", paths.Sealed)
|
||||
f, err := os.OpenFile(paths.Sealed, os.O_RDWR, 0664)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = f.WriteAt(bytes.Repeat([]byte{'d'}, 2048), 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, f.Close())
|
||||
}
|
||||
|
||||
func getGrothParamFileAndVerifyingKeys(s abi.SectorSize) {
|
||||
@@ -299,11 +296,11 @@ func TestSealAndVerify(t *testing.T) {
|
||||
|
||||
commit := time.Now()
|
||||
|
||||
genCandidiates := post(t, sb, s)
|
||||
post(t, sb, nil, s)
|
||||
|
||||
epost := time.Now()
|
||||
|
||||
post(t, sb, s)
|
||||
post(t, sb, nil, s)
|
||||
|
||||
if err := sb.FinalizeSector(context.TODO(), si, nil); err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
@@ -313,8 +310,7 @@ func TestSealAndVerify(t *testing.T) {
|
||||
|
||||
fmt.Printf("PreCommit: %s\n", precommit.Sub(start).String())
|
||||
fmt.Printf("Commit: %s\n", commit.Sub(precommit).String())
|
||||
fmt.Printf("GenCandidates: %s\n", genCandidiates.Sub(commit).String())
|
||||
fmt.Printf("EPoSt: %s\n", epost.Sub(genCandidiates).String())
|
||||
fmt.Printf("EPoSt: %s\n", epost.Sub(commit).String())
|
||||
}
|
||||
|
||||
func TestSealPoStNoCommit(t *testing.T) {
|
||||
@@ -370,16 +366,15 @@ func TestSealPoStNoCommit(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
genCandidiates := post(t, sb, s)
|
||||
post(t, sb, nil, s)
|
||||
|
||||
epost := time.Now()
|
||||
|
||||
fmt.Printf("PreCommit: %s\n", precommit.Sub(start).String())
|
||||
fmt.Printf("GenCandidates: %s\n", genCandidiates.Sub(precommit).String())
|
||||
fmt.Printf("EPoSt: %s\n", epost.Sub(genCandidiates).String())
|
||||
fmt.Printf("EPoSt: %s\n", epost.Sub(precommit).String())
|
||||
}
|
||||
|
||||
func TestSealAndVerify2(t *testing.T) {
|
||||
func TestSealAndVerify3(t *testing.T) {
|
||||
defer requireFDsClosed(t, openFDs(t))
|
||||
|
||||
if runtime.NumCPU() < 10 && os.Getenv("CI") == "" { // don't bother on slow hardware
|
||||
@@ -419,22 +414,32 @@ func TestSealAndVerify2(t *testing.T) {
|
||||
|
||||
si1 := abi.SectorID{Miner: miner, Number: 1}
|
||||
si2 := abi.SectorID{Miner: miner, Number: 2}
|
||||
si3 := abi.SectorID{Miner: miner, Number: 3}
|
||||
|
||||
s1 := seal{id: si1}
|
||||
s2 := seal{id: si2}
|
||||
s3 := seal{id: si3}
|
||||
|
||||
wg.Add(2)
|
||||
wg.Add(3)
|
||||
go s1.precommit(t, sb, si1, wg.Done) //nolint: staticcheck
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
go s2.precommit(t, sb, si2, wg.Done) //nolint: staticcheck
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
go s3.precommit(t, sb, si3, wg.Done) //nolint: staticcheck
|
||||
wg.Wait()
|
||||
|
||||
wg.Add(2)
|
||||
wg.Add(3)
|
||||
go s1.commit(t, sb, wg.Done) //nolint: staticcheck
|
||||
go s2.commit(t, sb, wg.Done) //nolint: staticcheck
|
||||
go s3.commit(t, sb, wg.Done) //nolint: staticcheck
|
||||
wg.Wait()
|
||||
|
||||
post(t, sb, s1, s2)
|
||||
post(t, sb, nil, s1, s2, s3)
|
||||
|
||||
corrupt(t, sb, si1)
|
||||
corrupt(t, sb, si2)
|
||||
|
||||
post(t, sb, []abi.SectorID{si1, si2}, s1, s2, s3)
|
||||
}
|
||||
|
||||
func BenchmarkWriteWithAlignment(b *testing.B) {
|
||||
|
||||
+15
-2
@@ -40,8 +40,21 @@ func (sb *Sealer) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, s
|
||||
}
|
||||
defer done()
|
||||
|
||||
proof, err := ffi.GenerateWindowPoSt(minerID, privsectors, randomness)
|
||||
return proof, skipped, err
|
||||
if len(skipped) > 0 {
|
||||
return nil, skipped, xerrors.Errorf("pubSectorToPriv skipped some sectors")
|
||||
}
|
||||
|
||||
proof, faulty, err := ffi.GenerateWindowPoSt(minerID, privsectors, randomness)
|
||||
|
||||
var faultyIDs []abi.SectorID
|
||||
for _, f := range faulty {
|
||||
faultyIDs = append(faultyIDs, abi.SectorID{
|
||||
Miner: minerID,
|
||||
Number: f,
|
||||
})
|
||||
}
|
||||
|
||||
return proof, faultyIDs, err
|
||||
}
|
||||
|
||||
func (sb *Sealer) pubSectorToPriv(ctx context.Context, mid abi.ActorID, sectorInfo []proof.SectorInfo, faults []abi.SectorNumber, rpt func(abi.RegisteredSealProof) (abi.RegisteredPoStProof, error)) (ffi.SortedPrivateSectorInfo, []abi.SectorID, func(), error) {
|
||||
|
||||
Vendored
+30
-14
@@ -203,25 +203,26 @@ func schedFetch(sector abi.SectorID, ft stores.SectorFileType, ptype stores.Path
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.SectorID, offset storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize, ticket abi.SealRandomness, unsealed cid.Cid) error {
|
||||
func (m *Manager) tryReadUnsealedPiece(ctx context.Context, sink io.Writer, sector abi.SectorID, offset storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize) (foundUnsealed bool, readOk bool, selector WorkerSelector, returnErr error) {
|
||||
|
||||
// acquire a lock purely for reading unsealed sectors
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := m.index.StorageLock(ctx, sector, stores.FTSealed|stores.FTCache, stores.FTUnsealed); err != nil {
|
||||
return xerrors.Errorf("acquiring sector lock: %w", err)
|
||||
if err := m.index.StorageLock(ctx, sector, stores.FTUnsealed, stores.FTNone); err != nil {
|
||||
returnErr = xerrors.Errorf("acquiring read sector lock: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
// passing 0 spt because we only need it when allowFetch is true
|
||||
best, err := m.index.StorageFindSector(ctx, sector, stores.FTUnsealed, 0, false)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("read piece: checking for already existing unsealed sector: %w", err)
|
||||
returnErr = xerrors.Errorf("read piece: checking for already existing unsealed sector: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
var readOk bool
|
||||
var selector WorkerSelector
|
||||
if len(best) == 0 { // new
|
||||
selector = newAllocSelector(m.index, stores.FTUnsealed, stores.PathSealing)
|
||||
} else { // append to existing
|
||||
foundUnsealed = len(best) > 0
|
||||
if foundUnsealed { // append to existing
|
||||
// There is unsealed sector, see if we can read from it
|
||||
|
||||
selector = newExistingSelector(m.index, sector, stores.FTUnsealed, false)
|
||||
@@ -231,12 +232,27 @@ func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.Sect
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("reading piece from sealed sector: %w", err)
|
||||
returnErr = xerrors.Errorf("reading piece from sealed sector: %w", err)
|
||||
}
|
||||
} else {
|
||||
selector = newAllocSelector(m.index, stores.FTUnsealed, stores.PathSealing)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if readOk {
|
||||
return nil
|
||||
}
|
||||
func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.SectorID, offset storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize, ticket abi.SealRandomness, unsealed cid.Cid) error {
|
||||
foundUnsealed, readOk, selector, err := m.tryReadUnsealedPiece(ctx, sink, sector, offset, size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if readOk {
|
||||
return nil
|
||||
}
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := m.index.StorageLock(ctx, sector, stores.FTSealed|stores.FTCache, stores.FTUnsealed); err != nil {
|
||||
return xerrors.Errorf("acquiring unseal sector lock: %w", err)
|
||||
}
|
||||
|
||||
unsealFetch := func(ctx context.Context, worker Worker) error {
|
||||
@@ -244,7 +260,7 @@ func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.Sect
|
||||
return xerrors.Errorf("copy sealed/cache sector data: %w", err)
|
||||
}
|
||||
|
||||
if len(best) > 0 {
|
||||
if foundUnsealed {
|
||||
if err := worker.Fetch(ctx, sector, stores.FTUnsealed, stores.PathSealing, stores.AcquireMove); err != nil {
|
||||
return xerrors.Errorf("copy unsealed sector data: %w", err)
|
||||
}
|
||||
|
||||
Vendored
+23
-3
@@ -66,8 +66,9 @@ const (
|
||||
)
|
||||
|
||||
type sectorState struct {
|
||||
pieces []cid.Cid
|
||||
failed bool
|
||||
pieces []cid.Cid
|
||||
failed bool
|
||||
corrupted bool
|
||||
|
||||
state int
|
||||
|
||||
@@ -251,6 +252,18 @@ func (mgr *SectorMgr) MarkFailed(sid abi.SectorID, failed bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mgr *SectorMgr) MarkCorrupted(sid abi.SectorID, corrupted bool) error {
|
||||
mgr.lk.Lock()
|
||||
defer mgr.lk.Unlock()
|
||||
ss, ok := mgr.sectors[sid]
|
||||
if !ok {
|
||||
return fmt.Errorf("no such sector in storage")
|
||||
}
|
||||
|
||||
ss.corrupted = corrupted
|
||||
return nil
|
||||
}
|
||||
|
||||
func opFinishWait(ctx context.Context) {
|
||||
val, ok := ctx.Value("opfinish").(chan struct{})
|
||||
if !ok {
|
||||
@@ -275,6 +288,8 @@ func (mgr *SectorMgr) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorI
|
||||
si := make([]proof.SectorInfo, 0, len(sectorInfo))
|
||||
var skipped []abi.SectorID
|
||||
|
||||
var err error
|
||||
|
||||
for _, info := range sectorInfo {
|
||||
sid := abi.SectorID{
|
||||
Miner: minerID,
|
||||
@@ -283,13 +298,18 @@ func (mgr *SectorMgr) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorI
|
||||
|
||||
_, found := mgr.sectors[sid]
|
||||
|
||||
if found && !mgr.sectors[sid].failed {
|
||||
if found && !mgr.sectors[sid].failed && !mgr.sectors[sid].corrupted {
|
||||
si = append(si, info)
|
||||
} else {
|
||||
skipped = append(skipped, sid)
|
||||
err = xerrors.Errorf("skipped some sectors")
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, skipped, err
|
||||
}
|
||||
|
||||
return generateFakePoSt(si, abi.RegisteredSealProof.RegisteredWindowPoStProof, randomness), skipped, nil
|
||||
}
|
||||
|
||||
|
||||
Vendored
+6
@@ -189,6 +189,12 @@ func (m *Sealing) plan(events []statemachine.Event, state *SectorInfo) (func(sta
|
||||
state.Log = append(state.Log, l)
|
||||
}
|
||||
|
||||
if m.notifee != nil {
|
||||
defer func(before SectorInfo) {
|
||||
m.notifee(before, *state)
|
||||
}(*state) // take safe-ish copy of the before state (except for nested pointers)
|
||||
}
|
||||
|
||||
p := fsmPlanners[state.State]
|
||||
if p == nil {
|
||||
return nil, 0, xerrors.Errorf("planner for state %s not found", state.State)
|
||||
|
||||
Vendored
+14
@@ -27,6 +27,7 @@ type test struct {
|
||||
}
|
||||
|
||||
func TestHappyPath(t *testing.T) {
|
||||
var notif []struct{ before, after SectorInfo }
|
||||
ma, _ := address.NewIDAddress(55151)
|
||||
m := test{
|
||||
s: &Sealing{
|
||||
@@ -34,6 +35,9 @@ func TestHappyPath(t *testing.T) {
|
||||
stats: SectorStats{
|
||||
bySector: map[abi.SectorID]statSectorState{},
|
||||
},
|
||||
notifee: func(before, after SectorInfo) {
|
||||
notif = append(notif, struct{ before, after SectorInfo }{before, after})
|
||||
},
|
||||
},
|
||||
t: t,
|
||||
state: &SectorInfo{State: Packing},
|
||||
@@ -68,6 +72,16 @@ func TestHappyPath(t *testing.T) {
|
||||
|
||||
m.planSingle(SectorFinalized{})
|
||||
require.Equal(m.t, m.state.State, Proving)
|
||||
|
||||
expected := []SectorState{Packing, PreCommit1, PreCommit2, PreCommitting, PreCommitWait, WaitSeed, Committing, SubmitCommit, CommitWait, FinalizeSector, Proving}
|
||||
for i, n := range notif {
|
||||
if n.before.State != expected[i] {
|
||||
t.Fatalf("expected before state: %s, got: %s", expected[i], n.before.State)
|
||||
}
|
||||
if n.after.State != expected[i+1] {
|
||||
t.Fatalf("expected after state: %s, got: %s", expected[i+1], n.after.State)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSeedRevert(t *testing.T) {
|
||||
|
||||
Vendored
+11
-2
@@ -28,6 +28,8 @@ import (
|
||||
|
||||
const SectorStorePrefix = "/sectors"
|
||||
|
||||
var ErrTooManySectorsSealing = xerrors.New("too many sectors sealing")
|
||||
|
||||
var log = logging.Logger("sectors")
|
||||
|
||||
type SectorLocation struct {
|
||||
@@ -59,6 +61,8 @@ type SealingAPI interface {
|
||||
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
|
||||
}
|
||||
|
||||
type SectorStateNotifee func(before, after SectorInfo)
|
||||
|
||||
type Sealing struct {
|
||||
api SealingAPI
|
||||
feeCfg FeeConfig
|
||||
@@ -77,6 +81,8 @@ type Sealing struct {
|
||||
upgradeLk sync.Mutex
|
||||
toUpgrade map[abi.SectorNumber]struct{}
|
||||
|
||||
notifee SectorStateNotifee
|
||||
|
||||
stats SectorStats
|
||||
|
||||
getConfig GetSealingConfigFunc
|
||||
@@ -99,7 +105,7 @@ type UnsealedSectorInfo struct {
|
||||
pieceSizes []abi.UnpaddedPieceSize
|
||||
}
|
||||
|
||||
func New(api SealingAPI, fc FeeConfig, events Events, maddr address.Address, ds datastore.Batching, sealer sectorstorage.SectorManager, sc SectorIDCounter, verif ffiwrapper.Verifier, pcp PreCommitPolicy, gc GetSealingConfigFunc) *Sealing {
|
||||
func New(api SealingAPI, fc FeeConfig, events Events, maddr address.Address, ds datastore.Batching, sealer sectorstorage.SectorManager, sc SectorIDCounter, verif ffiwrapper.Verifier, pcp PreCommitPolicy, gc GetSealingConfigFunc, notifee SectorStateNotifee) *Sealing {
|
||||
s := &Sealing{
|
||||
api: api,
|
||||
feeCfg: fc,
|
||||
@@ -116,6 +122,9 @@ func New(api SealingAPI, fc FeeConfig, events Events, maddr address.Address, ds
|
||||
},
|
||||
|
||||
toUpgrade: map[abi.SectorNumber]struct{}{},
|
||||
|
||||
notifee: notifee,
|
||||
|
||||
getConfig: gc,
|
||||
|
||||
stats: SectorStats{
|
||||
@@ -280,7 +289,7 @@ func (m *Sealing) newDealSector() (abi.SectorNumber, error) {
|
||||
|
||||
if cfg.MaxSealingSectorsForDeals > 0 {
|
||||
if m.stats.curSealing() > cfg.MaxSealingSectorsForDeals {
|
||||
return 0, xerrors.Errorf("too many sectors sealing")
|
||||
return 0, ErrTooManySectorsSealing
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@ func (m *Sealing) handleSealPrecommit2Failed(ctx statemachine.Context, sector Se
|
||||
return err
|
||||
}
|
||||
|
||||
if sector.PreCommit2Fails > 1 {
|
||||
if sector.PreCommit2Fails > 3 {
|
||||
return ctx.Send(SectorRetrySealPreCommit1{})
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -67,6 +67,8 @@ func (m *Sealing) tryUpgradeSector(ctx context.Context, params *miner.SectorPreC
|
||||
params.ReplaceSectorDeadline = loc.Deadline
|
||||
params.ReplaceSectorPartition = loc.Partition
|
||||
|
||||
log.Infof("replacing sector %d with %d", *replace, params.SectorNumber)
|
||||
|
||||
ri, err := m.api.StateSectorGetInfo(ctx, m.maddr, *replace, nil)
|
||||
if err != nil {
|
||||
log.Errorf("error calling StateSectorGetInfo for replaced sector: %+v", err)
|
||||
|
||||
@@ -2,8 +2,6 @@ module github.com/filecoin-project/lotus
|
||||
|
||||
go 1.14
|
||||
|
||||
replace github.com/supranational/blst => github.com/supranational/blst v0.1.2-alpha.1
|
||||
|
||||
require (
|
||||
contrib.go.opencensus.io/exporter/jaeger v0.1.0
|
||||
contrib.go.opencensus.io/exporter/prometheus v0.1.0
|
||||
@@ -15,10 +13,10 @@ require (
|
||||
github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129
|
||||
github.com/coreos/go-systemd/v22 v22.0.0
|
||||
github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e
|
||||
github.com/dgraph-io/badger/v2 v2.0.3
|
||||
github.com/dgraph-io/badger/v2 v2.2007.2
|
||||
github.com/docker/go-units v0.4.0
|
||||
github.com/drand/drand v1.0.3-0.20200714175734-29705eaf09d4
|
||||
github.com/drand/kyber v1.1.1
|
||||
github.com/drand/drand v1.1.2-0.20200905144319-79c957281b32
|
||||
github.com/drand/kyber v1.1.2
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/elastic/go-sysinfo v1.3.0
|
||||
github.com/fatih/color v1.8.0
|
||||
@@ -27,18 +25,18 @@ require (
|
||||
github.com/filecoin-project/go-bitfield v0.2.0
|
||||
github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2
|
||||
github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03
|
||||
github.com/filecoin-project/go-data-transfer v0.6.3
|
||||
github.com/filecoin-project/go-data-transfer v0.6.4
|
||||
github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f
|
||||
github.com/filecoin-project/go-fil-markets v0.6.0
|
||||
github.com/filecoin-project/go-fil-markets v0.6.1
|
||||
github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52
|
||||
github.com/filecoin-project/go-multistore v0.0.3
|
||||
github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20
|
||||
github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261
|
||||
github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df
|
||||
github.com/filecoin-project/go-state-types v0.0.0-20200911004822-964d6c679cfc
|
||||
github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370
|
||||
github.com/filecoin-project/go-statestore v0.1.0
|
||||
github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b
|
||||
github.com/filecoin-project/specs-actors v0.9.7
|
||||
github.com/filecoin-project/specs-actors v0.9.10
|
||||
github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796
|
||||
github.com/filecoin-project/test-vectors/schema v0.0.1
|
||||
github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1
|
||||
@@ -92,7 +90,7 @@ require (
|
||||
github.com/libp2p/go-libp2p-mplex v0.2.4
|
||||
github.com/libp2p/go-libp2p-noise v0.1.1
|
||||
github.com/libp2p/go-libp2p-peerstore v0.2.6
|
||||
github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200907103802-a3445b756fdb
|
||||
github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200910093904-f7f33e10cc18
|
||||
github.com/libp2p/go-libp2p-quic-transport v0.8.0
|
||||
github.com/libp2p/go-libp2p-record v0.1.3
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.2.3
|
||||
@@ -135,6 +133,8 @@ replace github.com/golangci/golangci-lint => github.com/golangci/golangci-lint v
|
||||
|
||||
replace github.com/filecoin-project/filecoin-ffi => ./extern/filecoin-ffi
|
||||
|
||||
replace github.com/dgraph-io/badger/v2 => github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794
|
||||
|
||||
replace github.com/filecoin-project/test-vectors => ./extern/test-vectors
|
||||
|
||||
replace github.com/supranational/blst => ./extern/fil-blst/blst
|
||||
|
||||
replace github.com/filecoin-project/fil-blst => ./extern/fil-blst
|
||||
|
||||
@@ -166,8 +166,10 @@ github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhY
|
||||
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
|
||||
github.com/dgraph-io/badger v1.6.1 h1:w9pSFNSdq/JPM1N12Fz/F/bzo993Is1W+Q7HjPzi7yg=
|
||||
github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU=
|
||||
github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794 h1:PIPH4SLjYXMMlX/cQqV7nIRatv7556yqUfWY+KBjrtQ=
|
||||
github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE=
|
||||
github.com/dgraph-io/badger/v2 v2.0.3/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32yw2j/9FUVnIM=
|
||||
github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k=
|
||||
github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE=
|
||||
github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
|
||||
github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
|
||||
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA=
|
||||
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
|
||||
@@ -179,12 +181,12 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/drand/bls12-381 v0.3.2 h1:RImU8Wckmx8XQx1tp1q04OV73J9Tj6mmpQLYDP7V1XE=
|
||||
github.com/drand/bls12-381 v0.3.2/go.mod h1:dtcLgPtYT38L3NO6mPDYH0nbpc5tjPassDqiniuAt4Y=
|
||||
github.com/drand/drand v1.0.3-0.20200714175734-29705eaf09d4 h1:+Rov3bfUriGWFR/lUVXnpimx+HMr9BXRC4by0BxuQ8k=
|
||||
github.com/drand/drand v1.0.3-0.20200714175734-29705eaf09d4/go.mod h1:SnqWL9jksIMK63UKkfmWI6f9PDN8ROoCgg+Z4zWk7hg=
|
||||
github.com/drand/drand v1.1.2-0.20200905144319-79c957281b32 h1:sU+51aQRaDxg0KnjQg19KuYRIxDBEUHffBAICSnBys8=
|
||||
github.com/drand/drand v1.1.2-0.20200905144319-79c957281b32/go.mod h1:0sQEVg+ngs1jaDPVIiEgY0lbENWJPaUlWxGHEaSmKVM=
|
||||
github.com/drand/kyber v1.0.1-0.20200110225416-8de27ed8c0e2/go.mod h1:UpXoA0Upd1N9l4TvRPHr1qAUBBERj6JQ/mnKI3BPEmw=
|
||||
github.com/drand/kyber v1.0.2/go.mod h1:x6KOpK7avKj0GJ4emhXFP5n7M7W7ChAPmnQh/OL6vRw=
|
||||
github.com/drand/kyber v1.1.1 h1:mwCY2XGRB+Qc1MPfrnRuVuXELkPhcq/r9yMoJIcDhHI=
|
||||
github.com/drand/kyber v1.1.1/go.mod h1:x6KOpK7avKj0GJ4emhXFP5n7M7W7ChAPmnQh/OL6vRw=
|
||||
github.com/drand/kyber v1.1.2 h1:faemqlaFyLrbBSjZGRzzu5SG/do+uTYpHlnrJIHbAhQ=
|
||||
github.com/drand/kyber v1.1.2/go.mod h1:x6KOpK7avKj0GJ4emhXFP5n7M7W7ChAPmnQh/OL6vRw=
|
||||
github.com/drand/kyber-bls12381 v0.1.0 h1:/P4C65VnyEwxzR5ZYYVMNzY1If+aYBrdUU5ukwh7LQw=
|
||||
github.com/drand/kyber-bls12381 v0.1.0/go.mod h1:N1emiHpm+jj7kMlxEbu3MUyOiooTgNySln564cgD9mk=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
@@ -220,12 +222,14 @@ github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 h1:a
|
||||
github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2/go.mod h1:pqTiPHobNkOVM5thSRsHYjyQfq7O5QSCMhvuu9JoDlg=
|
||||
github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 h1:2pMXdBnCiXjfCYx/hLqFxccPoqsSveQFxVLvNxy9bus=
|
||||
github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ=
|
||||
github.com/filecoin-project/go-data-transfer v0.6.3 h1:7TLwm8nuodHYD/uiwJjKc/PGRR+LwqM8jmlZqgWuUfY=
|
||||
github.com/filecoin-project/go-data-transfer v0.6.3/go.mod h1:PmBKVXkhh67/tnEdJXQwDHl5mT+7Tbcwe1NPninqhnM=
|
||||
github.com/filecoin-project/go-data-transfer v0.6.4 h1:Q08ABa+cOTOLoAyHeA94fPLcwu53p6eeAaxMxQb0m0A=
|
||||
github.com/filecoin-project/go-data-transfer v0.6.4/go.mod h1:PmBKVXkhh67/tnEdJXQwDHl5mT+7Tbcwe1NPninqhnM=
|
||||
github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1:GxJzR3oRIMTPtpZ0b7QF8FKPK6/iPAc7trhlL5k/g+s=
|
||||
github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ=
|
||||
github.com/filecoin-project/go-fil-markets v0.6.0 h1:gfxMweUHo4u+2BZh2Q7/7+cV0/ttikuJfhkkxLRsE2Q=
|
||||
github.com/filecoin-project/go-fil-markets v0.6.0/go.mod h1:LhSFYLkjaoe0vFRKABGYyw1Jz+9jCpF1sPA7yOftLTw=
|
||||
github.com/filecoin-project/go-fil-markets v0.6.1 h1:qCFLcVkUCbxwEfH/6EcqTuQvibXt/TXZr+vh8tWv/BQ=
|
||||
github.com/filecoin-project/go-fil-markets v0.6.1/go.mod h1:dBJl59dAyl8+cGVb/ONPlEQW4+YzhjI3d6bxLfHVpX0=
|
||||
github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM=
|
||||
github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24=
|
||||
github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 h1:FXtCp0ybqdQL9knb3OGDpkNTaBbPxgkqPeWKotUwkH0=
|
||||
github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4=
|
||||
github.com/filecoin-project/go-multistore v0.0.3 h1:vaRBY4YiA2UZFPK57RNuewypB8u0DzzQwqsL0XarpnI=
|
||||
@@ -236,8 +240,9 @@ github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261 h
|
||||
github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc=
|
||||
github.com/filecoin-project/go-state-types v0.0.0-20200903145444-247639ffa6ad/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I=
|
||||
github.com/filecoin-project/go-state-types v0.0.0-20200904021452-1883f36ca2f4/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I=
|
||||
github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df h1:m2esXSuGBkuXlRyCsl1a/7/FkFam63o1OzIgzaHtOfI=
|
||||
github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I=
|
||||
github.com/filecoin-project/go-state-types v0.0.0-20200911004822-964d6c679cfc h1:1vr/LoqGq5m5g37Q3sNSAjfwF1uJY0zmiHcvnxY6hik=
|
||||
github.com/filecoin-project/go-state-types v0.0.0-20200911004822-964d6c679cfc/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g=
|
||||
github.com/filecoin-project/go-statemachine v0.0.0-20200714194326-a77c3ae20989/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig=
|
||||
github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370 h1:Jbburj7Ih2iaJ/o5Q9A+EAeTabME6YII7FLi9SKUf5c=
|
||||
github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig=
|
||||
@@ -246,8 +251,9 @@ github.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZO
|
||||
github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b h1:fkRZSPrYpk42PV3/lIXiL0LHetxde7vyYYvSsttQtfg=
|
||||
github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8=
|
||||
github.com/filecoin-project/specs-actors v0.9.4/go.mod h1:BStZQzx5x7TmCkLv0Bpa07U6cPKol6fd3w9KjMPZ6Z4=
|
||||
github.com/filecoin-project/specs-actors v0.9.7 h1:7PAZ8kdqwBdmgf/23FCkQZLCXcVu02XJrkpkhBikiA8=
|
||||
github.com/filecoin-project/specs-actors v0.9.7/go.mod h1:wM2z+kwqYgXn5Z7scV1YHLyd1Q1cy0R8HfTIWQ0BFGU=
|
||||
github.com/filecoin-project/specs-actors v0.9.10 h1:gU0TrRhgkCsBEOP42sGDE7RQuR0Cov9hJhBqq+RJmjU=
|
||||
github.com/filecoin-project/specs-actors v0.9.10/go.mod h1:czlvLQGEX0fjLLfdNHD7xLymy6L3n7aQzRWzsYGf+ys=
|
||||
github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 h1:dJsTPWpG2pcTeojO2pyn0c6l+x/3MZYCBgo/9d11JEk=
|
||||
github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g=
|
||||
github.com/filecoin-project/test-vectors/schema v0.0.1 h1:5fNF76nl4qolEvcIsjc0kUADlTMVHO73tW4kXXPnsus=
|
||||
@@ -497,7 +503,6 @@ github.com/ipfs/go-fs-lock v0.0.6/go.mod h1:OTR+Rj9sHiRubJh3dRhD15Juhd/+w6VPOY28
|
||||
github.com/ipfs/go-graphsync v0.1.0/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE=
|
||||
github.com/ipfs/go-graphsync v0.1.2 h1:25Ll9kIXCE+DY0dicvfS3KMw+U5sd01b/FJbA7KAbhg=
|
||||
github.com/ipfs/go-graphsync v0.1.2/go.mod h1:sLXVXm1OxtE2XYPw62MuXCdAuNwkAdsbnfrmos5odbA=
|
||||
github.com/ipfs/go-hamt-ipld v0.1.1 h1:0IQdvwnAAUKmDE+PMJa5y1QiwOPHpI9+eAbQEEEYthk=
|
||||
github.com/ipfs/go-hamt-ipld v0.1.1/go.mod h1:1EZCr2v0jlCnhpa+aZ0JZYp8Tt2w16+JJOAVz17YcDk=
|
||||
github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08=
|
||||
github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw=
|
||||
@@ -843,8 +848,8 @@ github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1
|
||||
github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk=
|
||||
github.com/libp2p/go-libp2p-pubsub v0.1.1/go.mod h1:ZwlKzRSe1eGvSIdU5bD7+8RZN/Uzw0t1Bp9R1znpR/Q=
|
||||
github.com/libp2p/go-libp2p-pubsub v0.3.2-0.20200527132641-c0712c6e92cf/go.mod h1:TxPOBuo1FPdsTjFnv+FGZbNbWYsp74Culx+4ViQpato=
|
||||
github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200907103802-a3445b756fdb h1:0jm9ZSDkteX9XRjZqZwG5X0wuR+e0zAJ6ZEnqo2vcb0=
|
||||
github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200907103802-a3445b756fdb/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI=
|
||||
github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200910093904-f7f33e10cc18 h1:+ae7vHSv/PJ4xGXwLV6LKGj32zjyB8ttJHtyV4TXal0=
|
||||
github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200910093904-f7f33e10cc18/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI=
|
||||
github.com/libp2p/go-libp2p-quic-transport v0.1.1/go.mod h1:wqG/jzhF3Pu2NrhJEvE+IE0NTHNXslOPn9JQzyCAxzU=
|
||||
github.com/libp2p/go-libp2p-quic-transport v0.5.0/go.mod h1:IEcuC5MLxvZ5KuHKjRu+dr3LjCT1Be3rcD/4d8JrX8M=
|
||||
github.com/libp2p/go-libp2p-quic-transport v0.8.0 h1:mHA94K2+TD0e9XtjWx/P5jGGZn0GdQ4OFYwNllagv4E=
|
||||
@@ -1316,8 +1321,6 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
||||
github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/supranational/blst v0.1.2-alpha.1 h1:v0UqVlvbRNZIaSeMPr+T01kvTUq1h0EZuZ6gnDR1Mlg=
|
||||
github.com/supranational/blst v0.1.2-alpha.1/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
|
||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
@@ -1747,7 +1750,6 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200617041141-9a465503579e/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
package journal
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
)
|
||||
|
||||
const RFC3339nocolon = "2006-01-02T150405Z0700"
|
||||
|
||||
// fsJournal is a basic journal backed by files on a filesystem.
|
||||
type fsJournal struct {
|
||||
EventTypeRegistry
|
||||
|
||||
dir string
|
||||
sizeLimit int64
|
||||
|
||||
fi *os.File
|
||||
fSize int64
|
||||
|
||||
incoming chan *Event
|
||||
|
||||
closing chan struct{}
|
||||
closed chan struct{}
|
||||
}
|
||||
|
||||
// OpenFSJournal constructs a rolling filesystem journal, with a default
|
||||
// per-file size limit of 1GiB.
|
||||
func OpenFSJournal(lr repo.LockedRepo, disabled DisabledEvents) (Journal, error) {
|
||||
dir := filepath.Join(lr.Path(), "journal")
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return nil, fmt.Errorf("failed to mk directory %s for file journal: %w", dir, err)
|
||||
}
|
||||
|
||||
f := &fsJournal{
|
||||
EventTypeRegistry: NewEventTypeRegistry(disabled),
|
||||
dir: dir,
|
||||
sizeLimit: 1 << 30,
|
||||
incoming: make(chan *Event, 32),
|
||||
closing: make(chan struct{}),
|
||||
closed: make(chan struct{}),
|
||||
}
|
||||
|
||||
if err := f.rollJournalFile(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go f.runLoop()
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (f *fsJournal) RecordEvent(evtType EventType, supplier func() interface{}) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Warnf("recovered from panic while recording journal event; type=%s, err=%v", evtType, r)
|
||||
}
|
||||
}()
|
||||
|
||||
if !evtType.Enabled() {
|
||||
return
|
||||
}
|
||||
|
||||
je := &Event{
|
||||
EventType: evtType,
|
||||
Timestamp: build.Clock.Now(),
|
||||
Data: supplier(),
|
||||
}
|
||||
select {
|
||||
case f.incoming <- je:
|
||||
case <-f.closing:
|
||||
log.Warnw("journal closed but tried to log event", "event", je)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *fsJournal) Close() error {
|
||||
close(f.closing)
|
||||
<-f.closed
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fsJournal) putEvent(evt *Event) error {
|
||||
b, err := json.Marshal(evt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n, err := f.fi.Write(append(b, '\n'))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.fSize += int64(n)
|
||||
|
||||
if f.fSize >= f.sizeLimit {
|
||||
_ = f.rollJournalFile()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fsJournal) rollJournalFile() error {
|
||||
if f.fi != nil {
|
||||
_ = f.fi.Close()
|
||||
}
|
||||
|
||||
nfi, err := os.Create(filepath.Join(f.dir, fmt.Sprintf("lotus-journal-%s.ndjson", build.Clock.Now().Format(RFC3339nocolon))))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to open journal file: %w", err)
|
||||
}
|
||||
|
||||
f.fi = nfi
|
||||
f.fSize = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fsJournal) runLoop() {
|
||||
defer close(f.closed)
|
||||
|
||||
for {
|
||||
select {
|
||||
case je := <-f.incoming:
|
||||
if err := f.putEvent(je); err != nil {
|
||||
log.Errorw("failed to write out journal event", "event", je, "err", err)
|
||||
}
|
||||
case <-f.closing:
|
||||
_ = f.fi.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package journal
|
||||
|
||||
var (
|
||||
// J is a globally accessible Journal. It starts being NilJournal, and early
|
||||
// during the Lotus initialization routine, it is reset to whichever Journal
|
||||
// is configured (by default, the filesystem journal). Components can safely
|
||||
// record in the journal by calling: journal.J.RecordEvent(...).
|
||||
J Journal = NilJournal() // nolint
|
||||
)
|
||||
@@ -1,152 +0,0 @@
|
||||
package journal
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
logging "github.com/ipfs/go-log"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
)
|
||||
|
||||
func InitializeSystemJournal(dir string) error {
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
j, err := OpenFSJournal(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentJournal = j
|
||||
return nil
|
||||
}
|
||||
|
||||
func Add(sys string, val interface{}) {
|
||||
if currentJournal == nil {
|
||||
log.Warn("no journal configured")
|
||||
return
|
||||
}
|
||||
currentJournal.AddEntry(sys, val)
|
||||
}
|
||||
|
||||
var log = logging.Logger("journal")
|
||||
|
||||
var currentJournal Journal
|
||||
|
||||
type Journal interface {
|
||||
AddEntry(system string, obj interface{})
|
||||
Close() error
|
||||
}
|
||||
|
||||
// fsJournal is a basic journal backed by files on a filesystem
|
||||
type fsJournal struct {
|
||||
fi *os.File
|
||||
fSize int64
|
||||
|
||||
journalDir string
|
||||
|
||||
incoming chan *JournalEntry
|
||||
journalSizeLimit int64
|
||||
|
||||
closing chan struct{}
|
||||
}
|
||||
|
||||
func OpenFSJournal(dir string) (Journal, error) {
|
||||
fsj := &fsJournal{
|
||||
journalDir: dir,
|
||||
incoming: make(chan *JournalEntry, 32),
|
||||
journalSizeLimit: 1 << 30,
|
||||
closing: make(chan struct{}),
|
||||
}
|
||||
|
||||
if err := fsj.rollJournalFile(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go fsj.runLoop()
|
||||
|
||||
return fsj, nil
|
||||
}
|
||||
|
||||
type JournalEntry struct {
|
||||
System string
|
||||
Timestamp time.Time
|
||||
Val interface{}
|
||||
}
|
||||
|
||||
func (fsj *fsJournal) putEntry(je *JournalEntry) error {
|
||||
b, err := json.Marshal(je)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n, err := fsj.fi.Write(append(b, '\n'))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fsj.fSize += int64(n)
|
||||
|
||||
if fsj.fSize >= fsj.journalSizeLimit {
|
||||
return fsj.rollJournalFile()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const RFC3339nocolon = "2006-01-02T150405Z0700"
|
||||
|
||||
func (fsj *fsJournal) rollJournalFile() error {
|
||||
if fsj.fi != nil {
|
||||
err := fsj.fi.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
nfi, err := os.Create(filepath.Join(fsj.journalDir, fmt.Sprintf("lotus-journal-%s.ndjson", build.Clock.Now().Format(RFC3339nocolon))))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to open journal file: %w", err)
|
||||
}
|
||||
|
||||
fsj.fi = nfi
|
||||
fsj.fSize = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fsj *fsJournal) runLoop() {
|
||||
for {
|
||||
select {
|
||||
case je := <-fsj.incoming:
|
||||
if err := fsj.putEntry(je); err != nil {
|
||||
log.Errorw("failed to write out journal entry", "entry", je, "err", err)
|
||||
}
|
||||
case <-fsj.closing:
|
||||
if err := fsj.fi.Close(); err != nil {
|
||||
log.Errorw("failed to close journal", "err", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (fsj *fsJournal) AddEntry(system string, obj interface{}) {
|
||||
je := &JournalEntry{
|
||||
System: system,
|
||||
Timestamp: build.Clock.Now(),
|
||||
Val: obj,
|
||||
}
|
||||
select {
|
||||
case fsj.incoming <- je:
|
||||
case <-fsj.closing:
|
||||
log.Warnw("journal closed but tried to log event", "entry", je)
|
||||
}
|
||||
}
|
||||
|
||||
func (fsj *fsJournal) Close() error {
|
||||
close(fsj.closing)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package journal
|
||||
|
||||
type nilJournal struct{}
|
||||
|
||||
// nilj is a singleton nil journal.
|
||||
var nilj Journal = &nilJournal{}
|
||||
|
||||
func NilJournal() Journal {
|
||||
return nilj
|
||||
}
|
||||
|
||||
func (n *nilJournal) RegisterEventType(_, _ string) EventType { return EventType{} }
|
||||
|
||||
func (n *nilJournal) RecordEvent(_ EventType, _ func() interface{}) {}
|
||||
|
||||
func (n *nilJournal) Close() error { return nil }
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user