Compare commits

...
471 Commits
Author SHA1 Message Date
Whyrusleeping 1ad725a04c Merge pull request #1284 from filecoin-project/version-bump-0-2-8
bump version to 0.2.8
2020-02-20 15:45:39 -08:00
Travis Person a898b18fd6 bump version to 0.2.8 2020-02-20 21:48:17 +00:00
Łukasz Magiera 0fa362cc23 Merge pull request #1280 from filecoin-project/asr/fix
Fix #1278: debug_advance should have its API calls updated
2020-02-19 18:17:39 +01:00
Aayush Rajasekaran 61401e5e82 Fix #1278: debug_advance should have its API calls updated
- This was forgotten in commit 6097000
2020-02-18 23:14:08 -05:00
Whyrusleeping 6afeb2e72b Merge pull request #1268 from filecoin-project/feat/simple-spam-protection
basic gossip spam protection logic
2020-02-18 10:39:36 -08:00
Whyrusleeping b5d50f2b52 Merge pull request #1272 from filecoin-project/misc/add-gofmt-to-golangcilint
Add gofmt to golangci-lint
2020-02-18 09:23:55 -08:00
Whyrusleeping 7e0be91cfd Merge pull request #1263 from filecoin-project/asr/state-api
Re: #1250: API methods should receive TipSetKeys, not TipSets, as input
2020-02-18 09:22:33 -08:00
whyrusleeping 4f6ec225cf mark peer for disconnection in connmgr 2020-02-18 09:20:17 -08:00
Jakub Sztandera b2a0ad68dd Add gofmt to golangci-lint
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-02-18 13:19:04 +01:00
Aayush Rajasekaran 60970008c8 Re: #1250: API methods should receive TipSetKeys, not TipSets, as input 2020-02-17 19:53:43 -05:00
Whyrusleeping 4750f32ab6 Merge pull request #1253 from filecoin-project/feat/bad-ts-cache-reasons
mark down reason for block inclusion in bad tipset cache
2020-02-17 12:20:20 -08:00
Whyrusleeping 1c9072bf6e Merge pull request #1235 from filecoin-project/feat/tls
Prefer tls
2020-02-17 11:26:50 -08:00
Whyrusleeping 656c022ed6 Merge pull request #1260 from filecoin-project/doc/miner-wallet-bls
docs: Provide clearer instructions around bls wallets for miners
2020-02-17 11:17:32 -08:00
Jakub Sztandera 4d5af19b9d Merge pull request #1258 from filecoin-project/feat/expose-jet-permission-error
Expose JWT permission error
2020-02-17 20:16:12 +01:00
Whyrusleeping fc227561ba Merge pull request #1254 from filecoin-project/feat/no-ffi-in-types
Remove ffi from types package
2020-02-17 11:13:56 -08:00
Whyrusleeping ca0bed47c4 Merge pull request #1261 from filecoin-project/asr/faucet
Faucet: Provide more info when a user tries to create a miner with a non-BLS address
2020-02-17 11:00:11 -08:00
Whyrusleeping 4f4f18482a Merge pull request #1266 from filecoin-project/feat/cmd-log
cmd: add log command
2020-02-17 10:39:56 -08:00
whyrusleeping 1dafcf24f1 basic gossip spam protection logic 2020-02-16 21:51:18 -08:00
Travis Person d6cf76a91a cmd: add log command
Add a log command to the common api which allows for listing all
initialized golog subsystems, and setting their log level during
runtime.

Command description also adds golog environment variable documentation.
2020-02-15 06:04:55 +00:00
Jim a34537ae9f Merge pull request #1264 from filecoin-project/asr/docs
Docs: Add a Lotus-only FAQs section to the Lotus website.
2020-02-14 19:21:40 -08:00
Aayush Rajasekaran 85c7864f78 Docs: Add a Lotus-only FAQs section to the Lotus website. 2020-02-14 18:38:14 -08:00
Aayush Rajasekaran f24d947388 Faucet: Provide more info when a user tries to create a miner with a non-BLS address 2020-02-12 18:41:23 -08:00
Travis Person 78c0c9b21a docs: Provide clearer instructions around bls wallets for miners 2020-02-12 23:36:56 +00:00
Oggy Nots 6bf87e28e9 create and publish github release (#1216)
* create and publish github release

* creates a tarball of 'lotus', 'lotus-storage-miner' and
'lotus-seal-worker' for darwin and linux
* computes and saves IPFS CID and sha512sum for each architecture
* creates a github release and uploads all artifacts
* triggered by tags matching regex /^v\d+\.\d+\.\d+$/ ie. v0.1.0

* add licenses and readme
2020-02-12 16:28:37 -05:00
Jakub Sztandera 49167cc55f Expose JWT permission error
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-02-12 21:25:29 +01:00
Łukasz Magiera a2b6aa8e67 Merge pull request #1257 from filecoin-project/feat/expand-repo-log
Expand "repo" string before logging
2020-02-12 21:05:36 +01:00
Jakub Sztandera c7ffaad763 Expand "repo" string before logging
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-02-12 21:00:07 +01:00
Jakub Sztandera 14580b6144 Import go-systemd properly
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-02-12 20:44:35 +01:00
Jakub Sztandera 5c3ed4d91a Remove ffi from types package
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-02-12 18:41:35 +01:00
whyrusleeping 243b295559 expose bad block cache reasons through api/cli 2020-02-11 23:44:55 -08:00
whyrusleeping 0661a1bbfc mark down reason for block inclusion in bad tipset cache 2020-02-11 23:21:11 -08:00
Whyrusleeping 5133ff16ba Merge pull request #1247 from filecoin-project/fix/lotus-shed-keyinfo
lotus-shed: add back support for bls and secp after sig changes
2020-02-11 13:40:42 -08:00
Łukasz Magiera 201eb3bab8 Merge pull request #1251 from filecoin-project/asr/lotus-docs
Use HTTPS for links to the dashboard
2020-02-11 21:04:14 +01:00
Aayush Rajasekaran c4b790a910 Use HTTPS for links to the dashboard
- The link doesn't reliably work without HTTPS specified
2020-02-11 11:51:11 -08:00
Jim dbcf2c3cf5 Merge pull request #1248 from filecoin-project/@jimmylee/small-docs-update
documentation: adds file name length limit
2020-02-10 23:00:09 -08:00
jimmylee a9cb1d6543 documentation: adds file name length limit 2020-02-10 22:31:45 -08:00
Łukasz Magiera e326a444b1 Merge pull request #1222 from filecoin-project/feat/support-multi-storage-miner-init
Support multi storage directories in miner init
2020-02-11 02:16:55 +01:00
Travis Person bc15d5234e lotus-shed: add back support for bls and secp after sig changes 2020-02-11 01:04:50 +00:00
Łukasz Magiera 05c262eb9f Merge pull request #1246 from filecoin-project/feat/msg-wait-cmd
expose StateWaitMsg through the cli
2020-02-11 01:50:52 +01:00
whyrusleeping 1e1668e949 expose StateWaitMsg through the cli 2020-02-10 16:38:02 -08:00
Jakub Sztandera 352fb9f9ea Prefer tls
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-02-07 14:04:47 +01:00
Łukasz Magiera fc46938383 Merge pull request #1234 from filecoin-project/fix/signature-tests
add proper signature imports to tests
2020-02-07 08:15:43 +01:00
whyrusleeping 0309e2332c add proper signature imports to tests 2020-02-06 23:01:37 -08:00
Łukasz Magiera 17c3d158d2 Merge pull request #1233 from filecoin-project/fix/mark-bad
mark bad should be respected for every incoming tipset
2020-02-07 07:42:01 +01:00
whyrusleeping d4338047af mark bad should be respected for every incoming tipset 2020-02-06 22:39:24 -08:00
Łukasz Magiera 44c1e3a347 Merge pull request #1228 from steven004/statepower
better power show
2020-02-06 19:34:46 +01:00
steven004 709fd12b7f better power show 2020-02-06 14:25:30 +08:00
Jakub Sztandera 21a603ed8f Merge pull request #1226 from filecoin-project/fix/dbg-errcheck
debug: Check error in AdvanceBlockCmd
2020-02-06 07:05:57 +01:00
Łukasz Magiera 85f91a1114 debug: Check error in AdvanceBlockCmd 2020-02-06 03:09:52 +01:00
Łukasz Magiera e7a1be4dde Merge pull request #1217 from filecoin-project/feat/worker-prefetch
worker: Prefetch data in background
2020-02-05 03:09:24 +01:00
Travis Person e9470d873e Update usage 2020-02-05 00:07:44 +00:00
Travis Person cf8e90fa3e Load sectorbuilder config during storage miner init 2020-02-05 00:07:44 +00:00
Travis Person 62146b7bb3 Add pre-sealed-metadata flag to miner init
Metadata for presealed sectors now must be specified
2020-02-04 23:16:10 +00:00
Łukasz Magiera 575e962d16 Merge pull request #1220 from filecoin-project/fix/other-commands
Fix lotus-seed with sigs changes
2020-02-04 23:53:51 +01:00
Jakub Sztandera 70da3e124a Fix lotus-seed with sigs changes
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-02-04 23:49:10 +01:00
Łukasz Magiera 4bd6d7be1a storageminer: Work around broken fastPledgeCommitment 2020-02-04 21:46:31 +01:00
Łukasz Magiera 63af9f2a9e worker: Paramfetch once 2020-02-04 20:17:18 +01:00
Łukasz Magiera 1a9c775407 worker: Prefetch data in background 2020-02-04 20:09:08 +01:00
Whyrusleeping 955b86deea Merge pull request #1188 from filecoin-project/feat/sigs-standalone
Don't depend on ffi
2020-02-04 10:45:21 -08:00
Łukasz Magiera 6eb342b8ee Merge pull request #1212 from filecoin-project/fix/remote-put-commit
remote: Fix put in commit
2020-02-04 18:22:12 +01:00
Jakub Sztandera 5bc1cb2aa3 Fix CheckBlockSignature, add docks
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-02-04 15:12:10 +01:00
Jakub Sztandera cb05001e5a mod tidy
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-02-04 15:12:10 +01:00
Jakub Sztandera ad9e4db3d6 Reduce sig import locations
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-02-04 15:12:10 +01:00
Jakub Sztandera 5e6ab42cb8 Don't depend on ffi
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-02-04 15:12:04 +01:00
Łukasz Magiera 63ee6b6791 remote: Fix put in commit 2020-02-04 08:01:13 +01:00
Łukasz Magiera f837cb5513 Merge pull request #1184 from filecoin-project/feat/chain-bisect
chain: bisect cmd
2020-02-04 04:43:31 +01:00
Łukasz Magiera b7ff44485a bisect: Allow any command 2020-02-04 04:40:49 +01:00
Łukasz Magiera 9935e3acfc Merge pull request #1191 from filecoin-project/feat/new-sb-fs
Sectorbuilder FS refactor
2020-02-04 04:19:39 +01:00
Łukasz Magiera 90ecfbe0e4 Merge branch 'master' into feat/new-sb-fs 2020-02-04 04:15:25 +01:00
Łukasz Magiera 0ca349033d Merge pull request #1205 from filecoin-project/fix/readme
drop 'experimental' from readme description
2020-02-04 03:53:06 +01:00
Łukasz Magiera 5cc089be12 Merge pull request #1207 from filecoin-project/feat/api-bstore
api-backed blockstore
2020-02-04 03:52:01 +01:00
Łukasz Magiera a8d18c8ac9 api-backed blockstore 2020-02-04 03:47:59 +01:00
whyrusleeping cc0635335c drop 'experimental' from readme description 2020-02-03 17:52:46 -08:00
Łukasz Magiera 65d8769002 Merge pull request #1203 from filecoin-project/feat/split-post-scheduler-from-storage-miner
split PoSt scheduler from Miner in preparation for extraction
2020-02-04 02:13:12 +01:00
laser d8f5330c29 don't consume short-lived context 2020-02-03 15:48:11 -08:00
laser ea2f53745e split FPoStScheduler from Miner
Rationale: Nodes want to handle scheduling of PoSts. Splitting the 
FPoStScheduler from the Miner allows nodes to reuse the Miner w/out 
having to reuse the PoSt scheduler.
2020-02-03 15:48:11 -08:00
Łukasz Magiera c9bd682c33 Merge pull request #1178 from filecoin-project/feat/multisig-balance-rpc
add a method to query available multisig balance
2020-02-04 00:43:08 +01:00
Łukasz Magiera 04c8bca073 Merge pull request #1195 from filecoin-project/test/fork-height-activation
add a test to ensure there are no off-by-one errors in fork activatio…
2020-02-03 23:26:56 +01:00
Whyrusleeping 7f1335a8dd Merge pull request #1196 from filecoin-project/fix/slash-blocks
Fix slash blocks
2020-02-03 10:17:43 -08:00
Łukasz Magiera ff77198a08 Update sectorbuilder with later cache mkdir 2020-02-03 18:37:40 +01:00
Łukasz Magiera 8da64d710e sealing: Work around broken remote sector put 2020-02-03 04:48:56 +01:00
Łukasz Magiera e453a38865 sealing: fix finalize with cache only 2020-02-02 20:36:15 +01:00
Jakub Sztandera ce7be477ce Fix slash blocks
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-31 17:07:37 -08:00
whyrusleeping 01b6ddbbd3 add a test to ensure there are no off-by-one errors in fork activation logic 2020-01-31 15:52:39 -08:00
Łukasz Magiera 37929ff75f sealing: more logging in pledge sector flow 2020-01-31 20:22:31 +01:00
Łukasz Magiera b6ba0ed47c fix pledgeReader with small sectors 2020-01-31 20:07:20 +01:00
Łukasz Magiera 87f7315f5a mod tidy 2020-01-31 19:57:28 +01:00
Łukasz Magiera 1b6ad6d2a1 worker: Fix transfer urls 2020-01-31 19:56:48 +01:00
Łukasz Magiera a62572bb76 Merge remote-tracking branch 'origin/master' into feat/new-sb-fs 2020-01-31 08:36:47 +01:00
Whyrusleeping f752770a47 Merge pull request #1185 from filecoin-project/fork/snowball
WIP, fork, fix slashing power calc
2020-01-30 21:31:37 -08:00
whyrusleeping d117cb61b6 change withUpdates to match fork height logic 2020-01-30 21:20:57 -08:00
whyrusleeping c071b2dc47 move back fork point, set new version 2020-01-30 21:15:00 -08:00
whyrusleeping d70ebd2ba5 some code review 2020-01-30 21:10:37 -08:00
whyrusleeping cda7f08b76 use less than, not equals 2020-01-30 21:05:41 -08:00
whyrusleeping 19a65319ee test and fix fork, add bigint parsing to lotus shed 2020-01-30 18:14:20 -08:00
WhyrusleepingandŁukasz Magiera 7402b14df3 Update chain/actors/actor_miner2.go
Co-Authored-By: Łukasz Magiera <magik6k@users.noreply.github.com>
2020-01-30 17:51:19 -08:00
whyrusleeping 0622eb7634 put miner changes behind a fork switch 2020-01-30 17:36:33 -08:00
Łukasz Magiera 95f344540e Fix tests 2020-01-31 02:27:38 +01:00
Łukasz Magiera ee9060aa14 Update sectorbuilder 2020-01-31 02:18:48 +01:00
Jakub Sztandera c6fd45727d Add state fork logic
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-30 17:17:34 -08:00
Jakub Sztandera cd27f5a4bc Merge pull request #1186 from filecoin-project/feat/lazy-param-box
build: Lazy ParametersJson
2020-01-30 16:37:38 -08:00
whyrusleeping 8ad8fa902d extra careful power checks on slashing 2020-01-30 16:36:18 -08:00
Jakub Sztandera 7861b5e6cb Merge pull request #1189 from filecoin-project/revert/rle-fix
Revert "Fix small bug in RLE"
2020-01-30 16:15:06 -08:00
Jakub Sztandera 70aaa8fc92 Revert "Fix small bug in RLE"
This reverts commit 6ed57ede6a.

Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-30 16:14:32 -08:00
Jakub Sztandera e441b48ea7 Merge pull request #1187 from filecoin-project/fix/rle-bitcap
Fix small bug in RLE
2020-01-30 15:49:38 -08:00
Jakub Sztandera 6ed57ede6a Fix small bug in RLE
Thanks @frrist

Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-30 15:18:54 -08:00
Łukasz Magiera aefc463586 build: Lazy ParametersJson 2020-01-30 23:50:24 +01:00
Jakub Sztandera f2340579a5 Fix power calculations
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-30 14:01:47 -08:00
Łukasz Magiera de5577ca70 chain: bisect cmd 2020-01-30 22:32:59 +01:00
Łukasz Magiera 316b11445e storageminer: Print fault data in info 2020-01-30 19:38:03 +01:00
Łukasz Magiera b42e481600 Merge pull request #1182 from zhy2006/master
fix:a bug of the power percentage in lotus-storage-miner info
2020-01-30 08:18:49 +01:00
Yang e5a48800ab fix:a bug of the power percentage in lotus-storage-miner info 2020-01-30 15:02:50 +08:00
Łukasz Magiera db50d01db9 Merge remote-tracking branch 'origin/master' into feat/new-sb-fs 2020-01-30 07:46:47 +01:00
Łukasz Magiera cec2085790 sealing: Fix pledgeReader 2020-01-30 07:41:30 +01:00
Łukasz Magiera 75ee71e35a Merge branch 'master' into feat/new-sb-fs 2020-01-30 07:39:52 +01:00
Whyrusleeping 7f9a3ac584 Merge pull request #1175 from filecoin-project/feat/fake-mine
Intoroduce advance-block command
2020-01-29 17:36:22 -08:00
Jakub Sztandera 1e9f293994 Return errors
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-29 17:35:32 -08:00
whyrusleeping b5f9a385ae add a method to query available multisig balance 2020-01-29 17:23:16 -08:00
Whyrusleeping f1114d3852 Merge pull request #1177 from filecoin-project/fix/fastpledge-math
Fix fast pledge math
2020-01-29 17:06:20 -08:00
Łukasz Magiera d27187b1de Fix fast pledge math 2020-01-30 02:01:10 +01:00
Łukasz Magiera 4aaa758543 fpost: better fault checks 2020-01-30 01:50:58 +01:00
Łukasz Magiera 03f07042ff fpost: print message apply result 2020-01-29 23:47:28 +01:00
Jakub Sztandera bcbfc931ba Intoroduce advance-block command
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-29 14:40:19 -08:00
Łukasz Magiera e2b2026fa5 actually call finalizeSector 2020-01-29 23:37:31 +01:00
Łukasz Magiera 4b8b79dbe0 sealing: FinalizeSector step 2020-01-29 22:25:06 +01:00
Whyrusleeping 9e5cc46638 Merge pull request #1158 from filecoin-project/feat/par-pledge
sealing: Parallel CommP calc in pledge sector
2020-01-29 12:15:22 -08:00
Łukasz Magiera ba542cf67a test fastPledgeCommitment 2020-01-29 21:01:20 +01:00
Łukasz Magiera 3f58ffe572 storageminer: New storage config 2020-01-29 20:53:45 +01:00
Łukasz Magiera 25f544f3db sealing: round parts in fastPledgeCommitment 2020-01-29 20:12:27 +01:00
Jim df747c8216 Merge pull request #1171 from filecoin-project/@jimmylee/docs-update-2
documentation: updates library schema with fedora instructions
2020-01-29 01:06:54 -08:00
jimmylee 53da298c4f documentation: updates library schema with fedora instructions 2020-01-29 01:04:43 -08:00
Jim 73c7f40ce3 Merge pull request #1170 from filecoin-project/@jimmylee/docs-update
lotus client list-deals
2020-01-29 00:52:53 -08:00
jimmylee 66bfadb71a documentation: adds lotus client list-deals for checking the status of a deal 2020-01-29 00:51:05 -08:00
Łukasz Magiera 5af64c53b6 initial sectorbuilder FS refactor integration 2020-01-29 00:08:02 +01:00
Łukasz Magiera b60860456d Merge pull request #1168 from filecoin-project/bugs/invalid-state-transition
planCommitting must handle SectorCommitFailed
2020-01-28 23:32:42 +01:00
Whyrusleeping 095a309aef Merge pull request #1160 from terorie/docker-more-binaries
Dockerfile: more binaries
2020-01-28 14:11:09 -08:00
Whyrusleeping 834383b7e5 Merge pull request #1159 from jsign/fixdocker
Dockerfile: fixes
2020-01-28 14:10:27 -08:00
laser 1cdf29244c write basic test affirming state change 2020-01-28 12:39:07 -08:00
laser cb665caf9e planCommitting must handle SectorCommitFailed
The SectorCommitFailed struct can be created from within Sealing#handleCommitting, and is created if actors.SerializeParams(params) produces an error or if m.api.MpoolPushMessage(ctx.Context(), msg) produces an error.
2020-01-28 11:46:26 -08:00
Jakub Sztandera eb4b85aea5 Merge pull request #1161 from filecoin-project/feat/chainwatch-challe
Add all challenges to chainwatch
2020-01-27 20:32:41 -08:00
Whyrusleeping 9c6c5aef5d Merge pull request #1162 from filecoin-project/feat/show-where-you-run
Add log to show where is the lotus running
2020-01-27 17:16:36 -08:00
Jakub Sztandera 050d552b9d Add log to show where is the lotus running
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-27 13:39:35 -08:00
Jakub Sztandera cf86bc6e23 fix insert
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-27 13:10:13 -08:00
Jakub Sztandera af61dfd8cd Fix order
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-27 13:09:00 -08:00
Jakub Sztandera 2a2a18a163 Add candidate
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-27 13:07:32 -08:00
Jakub Sztandera 29f3d6aa28 fix typo
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-27 13:03:09 -08:00
Jakub Sztandera 4379ff60f6 Create them table
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-27 13:01:24 -08:00
Jakub Sztandera a55a37c17b Pass the error
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-27 13:00:13 -08:00
Jakub Sztandera 5532093d58 Commit only once
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-27 12:59:07 -08:00
Jakub Sztandera 752be27815 Add all challenges to chainwatch
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-27 12:16:08 -08:00
Richard Patel 80903e86fa Dockerfile: more binaries 2020-01-27 20:02:56 +01:00
jsign dc076c6441 remove Dockerfile in base
Signed-off-by: jsign <jsign.uy@gmail.com>
2020-01-27 15:14:24 -03:00
jsign c6e63db7b4 rebase and reapply
Signed-off-by: jsign <jsign.uy@gmail.com>
2020-01-27 15:08:08 -03:00
jsign dff6e87ce9 Dockerfile: fixes
Signed-off-by: jsign <jsign.uy@gmail.com>
2020-01-27 15:06:41 -03:00
Whyrusleeping c765289da9 Merge pull request #1154 from eshon/misc/docker-directory
Create a directory for Docker files, merge ldoublewood's Docker
2020-01-27 10:04:10 -08:00
Whyrusleeping 2841edfb96 Merge pull request #1157 from filecoin-project/feat/cli/stategetdeal
cli: state get-deal
2020-01-25 10:17:49 -08:00
Łukasz Magiera c9c437cb3b sealing: Parallel CommP calc in pledge sector 2020-01-25 12:15:28 +01:00
Łukasz Magiera c0e317f829 cli: state get-deal 2020-01-25 11:41:17 +01:00
eshon 63a5124f57 Moving lotus PR 745 into a tools/dockers/ directory and adding some other examples 2020-01-24 23:24:54 +01:00
ldoublewood eda726ec34 restore Makefile 2020-01-24 23:24:54 +01:00
ldoublewood bab23aa7b1 add docker support 2020-01-24 23:24:54 +01:00
Whyrusleeping 7b258eddc4 Merge pull request #975 from filecoin-project/feat/cli-slashing
chain slash-consensus command
2020-01-24 14:14:03 -08:00
Jakub Sztandera 3bf0bd6ce9 Merge pull request #1153 from filecoin-project/feat/version-bump
Bump version following blocksync bugfixes
2020-01-24 14:10:17 -08:00
whyrusleeping 0ed981be19 Bump version following blocksync bugfixes 2020-01-24 13:58:57 -08:00
Łukasz Magiera 77113844a2 chain slash-consensus command 2020-01-24 13:58:06 -08:00
Whyrusleeping 9da4296e21 Merge pull request #745 from filcloud/fix/pr-docker
add docker support
2020-01-24 13:48:30 -08:00
Łukasz Magiera 9fc5f0cd9d Merge pull request #1124 from filecoin-project/feat/sector-recovery
sealing: Implement some common error states
2020-01-24 21:25:03 +01:00
Łukasz Magiera 2f2e7be12a sealing: docstrings for sanity-checks 2020-01-24 21:15:02 +01:00
Whyrusleeping 9892bf4379 Merge pull request #1147 from filecoin-project/upd/badger
Update badger
2020-01-24 11:49:36 -08:00
Whyrusleeping 351a683812 Merge pull request #1151 from filecoin-project/lotus-health-v2
refactor lotus-health agent for robustness
2020-01-24 11:44:47 -08:00
ognots 445b7f3388 refactor lotus-health agent for robustness
add retry logic when calls to API fail.
if API reconnects fail, restart lotus-daemon as it means lotus-daemon is likely unhealthy.

wait for lotus node's chain to sync during each check cycle, to avoid restarting lotus-daemon if needing to sync.

handle SIGTERM properly.

general cleanup and refactor of code, getting ready of unnecessary channels
2020-01-24 11:46:47 -05:00
Łukasz Magiera 9e95372e5d Merge pull request #1149 from filecoin-project/fix/peermgr-ts
make expand peers thread safe
2020-01-24 17:38:35 +01:00
Łukasz Magiera b5660b58b3 Merge remote-tracking branch 'origin/master' into feat/sector-recovery 2020-01-24 01:53:58 +01:00
Jakub Sztandera b472ea371a Merge pull request #1150 from filecoin-project/feat/sync-dashboard
Sync dashboard to what we have on stats.testnet.filecoin.io
2020-01-23 16:21:11 -08:00
Travis Person 6703bd2c71 Sync dashboard to what we have on stats.testnet.filecoin.io 2020-01-24 00:13:15 +00:00
Jakub Sztandera 36388de4e1 make expand peers thread safe
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-23 15:40:17 -08:00
Jakub Sztandera 10159ba1bb Merge pull request #1145 from filecoin-project/fix/blocksync-spam
limit blocksync response sizes
2020-01-23 15:21:01 -08:00
Jakub Sztandera 792a2cad82 limit blocksync response sizes
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-23 14:24:52 -08:00
Jakub Sztandera 7f1b12d29e Merge pull request #1137 from filecoin-project/feat/chainwatch-active-deals
chainwatch: Track deal activations
2020-01-23 13:21:39 -08:00
Jakub Sztandera 23b46a05f7 Update badger
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-23 12:46:32 -08:00
Jakub Sztandera cd14a5eb40 Merge pull request #1142 from filecoin-project/feat/bs2
Add incremental timeouts to blocksync fetching
2020-01-23 12:44:08 -08:00
Jakub Sztandera 2256e62648 Improve warning
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-23 12:39:23 -08:00
Jakub Sztandera 6b42a78c3f Cleanup
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-23 12:35:57 -08:00
Łukasz Magiera 6b2b22782b sealing: PreCommitFailed can go to SealFailed 2020-01-23 18:45:57 +01:00
Łukasz Magiera de52d3cadd sealing: Handlef for PreCommitFailed 2020-01-23 18:34:04 +01:00
Łukasz Magiera 7e43c40529 storageminer: Use tabwriter in sectors list 2020-01-23 17:15:45 +01:00
Łukasz Magiera df9dfa9d0c sealing: Don't infinite-loop on fatal errors 2020-01-23 17:11:58 +01:00
Łukasz Magiera 08a2e0f82c sealing: Errors are hard 2020-01-23 17:02:55 +01:00
Łukasz Magiera 01dc9c767e sealing: Error types that can actually be checked 2020-01-23 16:57:50 +01:00
Łukasz Magiera 67b441838b sealing: Actually call handleSealFailed 2020-01-23 16:47:33 +01:00
Łukasz Magiera 94f2948020 sealing: implement handler for sealFailed 2020-01-23 16:38:10 +01:00
Łukasz Magiera f5540195de worker: Fix progress bars 2020-01-23 15:38:36 +01:00
Łukasz Magiera 558e4c7669 Fix tests after sectorbuilder update 2020-01-23 15:33:28 +01:00
Łukasz Magiera c3a5da8586 storageminer: log flag for sector status 2020-01-23 15:18:05 +01:00
Łukasz Magiera 02c8ab7839 sealing: Check ticket expiration 2020-01-23 15:05:44 +01:00
Łukasz Magiera 8414569428 Merge remote-tracking branch 'origin/master' into feat/sector-recovery 2020-01-23 14:29:44 +01:00
Łukasz Magiera bd97eb98c5 Merge pull request #1141 from filecoin-project/fix/no-cgo
Make it buld without cgo
2020-01-23 14:10:56 +01:00
Łukasz Magiera e67fbda305 mod tidy 2020-01-23 13:29:43 +01:00
Łukasz Magiera 26e6bc32ee sealing: check deal expiration 2020-01-23 13:17:45 +01:00
Łukasz Magiera 11a6bff416 miner: Handle stop signal when sleeping 2020-01-23 11:10:42 +01:00
Łukasz Magiera e67ee227a3 sealing: Nonzero exit on commit isn't fatal 2020-01-23 11:02:20 +01:00
Łukasz Magiera f8ec1d9d22 Merge remote-tracking branch 'origin/master' into feat/sector-recovery 2020-01-23 10:52:10 +01:00
Łukasz Magiera 7fb3360d6f storage: Fix handing stop call 2020-01-23 10:46:46 +01:00
Jakub Sztandera cb35625a53 Remove log
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-22 16:04:33 -08:00
Jakub Sztandera 26870501a7 mod tidy
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-22 16:04:13 -08:00
Jakub Sztandera f5d061f34f Add incremental timeouts to blocksync fetching
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-22 15:57:42 -08:00
Jakub Sztandera 362fbbf913 Add blockheader_cgo file
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-22 15:55:52 -08:00
Jakub Sztandera f8d5f610b6 Merge pull request #1140 from filecoin-project/feat/profiling-work
wire up tracing into state tree flush, add pprof flag
2020-01-22 15:47:19 -08:00
Łukasz Magiera e43174f2af sealing: Not getting seal ticket isn't fatal 2020-01-22 22:16:45 +01:00
whyrusleeping 16523c2ef9 fixup tests 2020-01-22 12:56:40 -08:00
Łukasz Magiera d3a9006272 sealing: Wire up sector event log 2020-01-22 21:29:19 +01:00
Jakub Sztandera a404d535ee Make it buld without cgo
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-22 12:03:12 -08:00
whyrusleeping dcd01df2d3 wire up tracing into state tree flush, add pprof flag 2020-01-22 11:53:06 -08:00
Łukasz Magiera ba5a5d1248 sealing: wire up checkPieces and checkSeal 2020-01-22 20:47:29 +01:00
Łukasz Magiera 052b090bbf sealing: Fix planOne for global events 2020-01-22 19:30:56 +01:00
Łukasz Magiera 4654d9c192 chainwatch: Util routines / views 2020-01-22 16:12:47 +01:00
Łukasz Magiera 1e877eae86 sealing: Add Log field to SectorInfo 2020-01-22 03:41:39 +01:00
Łukasz Magiera 3c934ea21f Merge branch 'master' into feat/sector-recovery 2020-01-22 03:27:11 +01:00
Łukasz Magiera 52718e514c chainwatch: Track deal activations 2020-01-22 03:22:12 +01:00
Łukasz Magiera 4310cc23ce Merge pull request #1135 from filecoin-project/feat/listmsgs-cids
cli: state: --cids flag for list-messages
2020-01-22 00:33:53 +01:00
Łukasz Magiera bfb1cc6379 cli: state: --cids flag for list-messages 2020-01-21 23:54:01 +01:00
Jakub Sztandera cbfc675f4f Merge pull request #1120 from dtynn/fix/current_commit_flag
fix CurrentCommit in Makefile
2020-01-21 13:42:43 -08:00
Jakub Sztandera e7b5d678a9 rearange quotes
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-21 13:40:30 -08:00
ognots effacec817 range over right index to prevent bounds errors
the test scenario 'healthyHeadCheckWindow5' was causing index out of bounds errors.
the second range function in checkWindow was iterating over the incorrect slice of cids.
should be comparing latest items in slices first
2020-01-21 16:07:53 -05:00
Łukasz Magiera 3a89388039 Merge pull request #1134 from filecoin-project/feat/multisig-cli
add a CLI for multisig wallets
2020-01-21 21:05:41 +01:00
WhyrusleepingandŁukasz Magiera 3366c02a36 Update cli/multisig.go
Co-Authored-By: Łukasz Magiera <magik6k@users.noreply.github.com>
2020-01-21 11:52:59 -08:00
WhyrusleepingandŁukasz Magiera a26cc96a49 Update cli/multisig.go
Co-Authored-By: Łukasz Magiera <magik6k@users.noreply.github.com>
2020-01-21 11:52:50 -08:00
whyrusleeping 6d9ac84359 add a CLI for multisig wallets 2020-01-21 11:02:51 -08:00
Łukasz Magiera 882507e915 Merge pull request #1133 from filecoin-project/fix/build
Fix master build
2020-01-21 19:58:08 +01:00
Łukasz Magiera 08e1b52281 Fix master build 2020-01-21 19:51:17 +01:00
Łukasz Magiera cf153f89df Merge pull request #1131 from filecoin-project/feat/soft-map-cbg
cbor-gen: Soft struct-map unmarshaling
2020-01-21 19:44:39 +01:00
Łukasz Magiera d2401bc339 Update cbor-gen, error on unknown fields 2020-01-21 17:28:55 +01:00
Łukasz Magiera fd0bfc8777 Merge pull request #1089 from filecoin-project/feat/state-call-cmd
implement state call command for easy method calling
2020-01-21 17:16:54 +01:00
Łukasz Magiera 7b295d7bb0 Merge pull request #1115 from filecoin-project/feat/chainwatch-json-states
chainwatch: Store json states
2020-01-21 17:15:33 +01:00
Łukasz Magiera b6563ffc29 Merge pull request #1123 from filecoin-project/fix/jsonrpc-chclose-panic
jsonrpc: Fix channel closing race
2020-01-21 17:14:55 +01:00
Jakub Sztandera 2594ff6233 Merge pull request #1121 from filecoin-project/fix/mpool-stat-errs
mpool stat: Don't exit on StateGetActor error
2020-01-21 17:13:57 +01:00
Jakub Sztandera 807d803a81 Merge pull request #1130 from filecoin-project/fix/fpost-no-candidates
fpost: More logging
2020-01-21 17:07:22 +01:00
Łukasz Magiera 2076cb106d cobr-gen: Soft struct-map unmarshaling 2020-01-21 17:05:10 +01:00
Łukasz Magiera 5b304fa20a fpost: More logging 2020-01-21 16:01:42 +01:00
Łukasz Magiera fbc0330fa8 jsonrpc: Fix channel registration deadlock 2020-01-21 14:48:17 +01:00
Łukasz Magiera f5bfaff003 Merge pull request #1128 from filecoin-project/feat/chain-export-2
Implement chain import and exporting
2020-01-21 03:35:24 +01:00
Łukasz Magiera eac17a8328 mod tidy 2020-01-21 03:35:03 +01:00
Łukasz Magiera f9c9316990 Merge pull request #1127 from filecoin-project/bug/lotus-health
fixes health agent bug
2020-01-21 03:29:51 +01:00
whyrusleeping d9f5f6e2c6 add flag to halt after chain importing 2020-01-20 17:58:58 -08:00
whyrusleeping 955b755055 wire up importing 2020-01-20 17:53:55 -08:00
ognots 0c6e4c6c40 fixes health agent bug
was passing wrong variable to updateWindow function argument.
also updates duplicate function comment
2020-01-20 20:34:13 -05:00
whyrusleeping 57812fc61d chain export should work now 2020-01-20 15:51:28 -08:00
whyrusleeping 62f05d4c14 WIP: chain export 2020-01-20 15:51:28 -08:00
Łukasz Magiera e4de5c55ac sealing: Some state renaming 2020-01-20 23:04:46 +01:00
Łukasz Magiera efaf2c720b sealing: WIP SectorInfo sanity checks 2020-01-20 23:04:27 +01:00
Łukasz Magiera d1f419c9d1 jsonrpc: Fix channel closing race 2020-01-20 19:21:16 +01:00
Łukasz Magiera c5ece2a892 Merge pull request #1119 from dtynn/fix/some_sealing_problems
small fixes
2020-01-20 17:05:14 +01:00
Łukasz Magiera 7712d97270 mpool stat: Don't exit on StateGetActor error 2020-01-20 16:18:02 +01:00
dtynn 8e90d5fb17 fix CurrentCommit in Makefile 2020-01-20 18:22:42 +08:00
dtynn b2fcca87ff small fixes 2020-01-20 16:23:56 +08:00
Łukasz Magiera a46a9bb42e chainwatch: Store deals 2020-01-20 01:49:52 +01:00
Łukasz Magiera 62d661f898 chainwatch: Store json states 2020-01-19 22:48:19 +01:00
Łukasz Magiera 4436148fa1 Merge pull request #1117 from filecoin-project/fix/dont-override-loglvl
lotuslog: Don't override log levels
2020-01-19 21:38:36 +01:00
Łukasz Magiera 3886e050b0 lotuslog: don't override log levels 2020-01-19 21:18:35 +01:00
Łukasz Magiera ff4b0c8f5d Merge pull request #1110 from filecoin-project/fix/nil-newts-fpost-panic
fpost: Don't panic with nil new tipset
2020-01-19 21:17:51 +01:00
Łukasz Magiera f82ee0a2a7 Merge pull request #1116 from filecoin-project/fix/v0.2.5
Correctly update proving set & sector set with amt2
2020-01-19 17:53:59 +01:00
Łukasz Magiera b5d603dd46 Cleaner fork logic in onSuccessfulPoSt2 2020-01-19 17:44:44 +01:00
Łukasz Magiera 0b8ae006d3 Schedule the fork at 11000 2020-01-19 17:37:28 +01:00
Łukasz Magiera 55fd0a4e60 stmgr: Exetute miner amt after correctly switching to amt2 in miner code 2020-01-19 17:27:43 +01:00
Łukasz Magiera 3c4acbc6cb Merge pull request #1107 from dtynn/feat/bootybay-fork
correctly update proving set & sector set with amt2
2020-01-19 17:22:23 +01:00
Jakub Sztandera 8224aab851 Merge pull request #1112 from zhy2006/master
fix: calculate expected cost for sorting peers
2020-01-19 16:00:48 +01:00
Jakub Sztandera 28604f5a4c Merge pull request #1114 from filecoin-project/feat/bench-nits
bench: Don't print unseal results when unsealing is skipped
2020-01-19 15:58:38 +01:00
Łukasz Magiera 533081454a bench: Don't print unseal results when unsealing is skipped 2020-01-19 15:56:37 +01:00
Łukasz Magiera e94e64652b Merge pull request #1054 from filecoin-project/feat/event-states
Sector state machine changes
2020-01-19 15:53:07 +01:00
Yang 489ecef47b fix: calculate expected cost for sorting peers 2020-01-19 13:48:15 +08:00
dtynn 8b42ca76f8 add onSuccessfulPoSt2 2020-01-19 08:22:12 +08:00
Łukasz Magiera be2d138aac fpost: Don't panic with nil new tipset 2020-01-18 16:00:22 +01:00
Łukasz Magiera 1e782b3de2 Merge branch 'master' into feat/event-states 2020-01-18 14:40:59 +01:00
dtynn 8bd62165f5 RemoveFromSectorSet2 is declared but never used, remove redclared one 2020-01-18 20:08:44 +08:00
dtynn ae8a9a93bf correctly update proving set & sector set with amt2 after some fork height 2020-01-18 19:41:34 +08:00
Łukasz Magiera f7ab2103ce Merge pull request #1106 from terorie/debug-trust-params
params_debug.go: remove $TRUST_PARAMS override
2020-01-18 12:26:37 +01:00
Richard Patel c3d5a9848b params_debug.go: remove $TRUST_PARAMS override 2020-01-18 10:38:51 +01:00
Whyrusleeping 6d6d82a304 Merge pull request #1104 from filecoin-project/feat/frigid-fork
Catch cases where new old miners with bad code were getting made
2020-01-17 22:11:09 -08:00
whyrusleeping bc83c0221b bump that version 2020-01-17 21:45:51 -08:00
whyrusleeping c6bf252a21 use right fork trigger height 2020-01-17 21:35:45 -08:00
whyrusleeping f9ea6969c3 Catch cases where new old miners with bad code were getting made 2020-01-17 21:20:56 -08:00
whyrusleeping 9e956ff9f4 handle integers and peer IDs 2020-01-17 18:27:29 -08:00
whyrusleeping 0a45e97699 implement state call command for easy method calling 2020-01-17 18:27:29 -08:00
Whyrusleeping 3962d4204b Merge pull request #1096 from filecoin-project/fix/msgset-add-error
Add missing fields to duplicate message error
2020-01-17 16:22:20 -08:00
Jakub Sztandera fd76216652 Merge pull request #1101 from filecoin-project/patch/faulty-declare
fixup bitfield serialization in manual faulty sector handler
2020-01-17 18:19:35 +01:00
whyrusleeping 2a7dcb6e17 fixup bitfield serialization in manual faulty sector handler 2020-01-17 00:13:00 -08:00
Whyrusleeping b02eaee0d4 Merge pull request #1100 from filecoin-project/feat/blizzar-fork
The Blizzard Fork
2020-01-16 23:28:01 -08:00
whyrusleeping 6ccf24ce6c Fix miner tests, push back fork time 2020-01-16 23:10:47 -08:00
whyrusleeping c6186a03f1 quick mechanism to prevent miners from submitting slashable blocks 2020-01-16 22:58:10 -08:00
whyrusleeping ee4f503e10 Set fork height 2020-01-16 22:47:27 -08:00
whyrusleeping 0c227e89b2 fix last miner test, go mod tidy 2020-01-16 22:39:23 -08:00
whyrusleeping 128933a655 fix slashing test 2020-01-16 22:27:56 -08:00
whyrusleeping 055b215bc7 don't allow slashing with old blocks 2020-01-16 22:14:00 -08:00
whyrusleeping 611dd77442 properly filter messages during compute state 2020-01-16 19:36:54 -08:00
whyrusleeping fb173c058e WIP: blizzard fork changes and test utilities 2020-01-16 18:33:43 -08:00
whyrusleeping 2edb32979f move fork constant and tag fork branch with comment 2020-01-16 15:11:08 -08:00
whyrusleeping e3bed8d12a Catch passing duplicate block to arbitrate consensus fault 2020-01-16 15:11:08 -08:00
Jakub Sztandera 84de47377c Intoroduce AMT v2 and amtFsck
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-16 23:21:16 +01:00
Travis Person 06c99d0e18 Add missing fields to duplicate message error 2020-01-16 17:13:00 +00:00
Łukasz Magiera 0aebec6697 Merge branch 'master' into feat/event-states 2020-01-16 03:59:14 +01:00
Łukasz Magiera d4c50b8ea0 sealing: gofmt 2020-01-16 03:54:57 +01:00
Łukasz Magiera cc424d64fe sealing: Handle events based on current state 2020-01-16 03:53:59 +01:00
Jakub Sztandera 48ea36d37f Merge pull request #1092 from filecoin-project/feat/fountain-additional-pledge-collateral
Add more collateral to CreateStorageMiner call in fountain
2020-01-16 02:32:12 +01:00
Łukasz Magiera ffdd436b52 sealing: Handle seed changes more correctly 2020-01-16 02:25:49 +01:00
Travis Person ec9286eb4b Add more collateral to CreateStorageMiner call in fountain 2020-01-16 01:04:04 +00:00
Travis Person 68f8d60323 Adding fields to warning in vm ApplyMessage (#1090)
* Adding fields to warning in vm ApplyMessage
2020-01-16 01:36:16 +01:00
Jakub Sztandera 5cabb068c0 Merge pull request #1091 from filecoin-project/fix/fountain-rice
Fix fountain rice command
2020-01-16 01:35:01 +01:00
Travis Person 01079b0815 Fix fountain rice command 2020-01-16 00:29:23 +00:00
Whyrusleeping 7e15aa243e Merge pull request #1084 from jsign/resolveforks
new api to calculate arbitrary forks revert and applys
2020-01-15 12:55:14 -08:00
Łukasz Magiera e9ca6c0871 sealing: More cleanup 2020-01-15 21:53:14 +01:00
Łukasz Magiera 604bf64ef6 Move miner sealing logic into a separate package 2020-01-15 21:49:11 +01:00
Łukasz Magiera 925e057acb Some sector fsm tests 2020-01-15 21:04:02 +01:00
Jakub Sztandera c47e96ca45 Merge pull request #1088 from jiaruihuang/master
a bit more than the minimum collateral at the time of miner creation
2020-01-15 18:53:34 +01:00
Jiarui.Huang 6354a8ce03 So we should pass a bit more than the minimum collateral at the time of miner creation
Even 0.1% more would be enough# Please enter the commit message for your changes. Lines starting
2020-01-16 01:30:01 +08:00
Jakub Sztandera 85ec972abb Merge pull request #1087 from terorie/fix-go-flags
Makefile: fix $GOFLAGS
2020-01-15 15:29:23 +01:00
Richard Patel a8d38ad82f Makefile: fix $GOFLAGS 2020-01-15 14:56:53 +01:00
Łukasz Magiera be6badc6a5 Merge pull request #1086 from filecoin-project/fix/worker-cleanup-sealed
worker: Remove staging sectors in PreCommit
2020-01-15 02:50:21 +01:00
Łukasz Magiera cf9275a2a2 worker: Remove staging sectors in PreCommit 2020-01-15 02:37:37 +01:00
Łukasz Magiera 66f707c243 Merge pull request #1085 from filecoin-project/fix/worker-cleanup-sealed
worker: Cleanup sealed sector data in commit
2020-01-15 02:29:14 +01:00
Łukasz Magiera 1163e46622 worker: Cleanup sealed sector data in commit 2020-01-15 02:24:13 +01:00
jsign 08b99ff413 new api to calculate arbitrary forks revert and applys
Signed-off-by: jsign <jsign.uy@gmail.com>
2020-01-14 21:24:08 -03:00
Łukasz Magiera 23472aa4f2 statemachine: don't force users to see reflect 2020-01-15 01:08:20 +01:00
Łukasz Magiera 05edf50931 Merge branch 'master' into feat/event-states 2020-01-15 00:35:52 +01:00
Łukasz Magiera a8e39962d0 Merge pull request #1053 from filecoin-project/lotus-health
health agent to monitor lotus
2020-01-14 18:41:51 +01:00
ognots 5a42bb166e add rice for good health
allows lotus-health to be compiled and distributed properly
2020-01-14 12:18:45 -05:00
ognots 3953227702 use lotus cli and GetFullNodeAPI
also some other minor bug fixes
2020-01-14 12:18:45 -05:00
ognots d8d8ce7526 health agent to monitor lotus
watch if chain head changes in a given window of api polls
allows setting a threshold of how many times the chain head can remain
unchanged before failing health check
also can set interval for polling chain head
on failure, restarts systemd unit
2020-01-14 12:18:45 -05:00
Jakub Sztandera 95e754601e Merge pull request #1080 from filecoin-project/fix/nil-sigs
Fix nil signature verification
2020-01-14 17:15:45 +01:00
Łukasz Magiera 5e11da7316 build: bump version 2020-01-14 16:53:05 +01:00
Łukasz Magiera 24e36852af Fix nil signature verification 2020-01-14 16:52:01 +01:00
Łukasz Magiera 458acbf33d mod tidy 2020-01-14 16:39:25 +01:00
Łukasz Magiera 8a9707788c Merge branch 'master' into feat/event-states 2020-01-14 16:31:10 +01:00
Jakub Sztandera e9351135bc Merge pull request #1078 from filecoin-project/fix/seselctmsgs-softfail
miner: Don't fail on actor not found in selectMessages
2020-01-14 16:17:14 +01:00
Łukasz Magiera 1bb9cfee53 gofmt 2020-01-14 16:12:42 +01:00
Łukasz Magiera 7da41f0fdc miner: Don't fail on actor not found in selectMessages 2020-01-14 16:12:26 +01:00
Łukasz Magiera f22e933ab1 Merge pull request #1077 from filecoin-project/fix/chainwatch-append-params
chainmatch: Append params rice box
2020-01-14 15:27:45 +01:00
Łukasz Magiera affa4c1b07 chainmatch: Append params rice box 2020-01-14 15:24:46 +01:00
Łukasz Magiera 0011c321e2 Merge pull request #1071 from filecoin-project/feat/chainwatch-pg
Use postgres in chainwatch
2020-01-14 14:14:02 +01:00
Jakub Sztandera 1924eb1471 Merge pull request #1075 from filecoin-project/fix/acf-check
Add additional checks to ACF
2020-01-14 13:42:33 +01:00
Jakub Sztandera ce8c2fd656 Bump version
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-14 13:37:20 +01:00
Jakub Sztandera c2fdca470d Add additional checks to ACF
Fixes https://github.com/filecoin-project/lotus/issues/1074

Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-14 13:22:41 +01:00
Jakub Sztandera 4f1bead0de Merge pull request #1070 from filecoin-project/fix/drop-1g-faucet
Drop 1g sector option from faucet
2020-01-14 12:43:47 +01:00
Łukasz Magiera 2dc2e0ba56 Drop 1g sector option from faucet 2020-01-14 06:23:10 +01:00
Łukasz Magiera 14128819de Correctly handle multi parent blocks 2020-01-14 06:17:31 +01:00
Łukasz Magiera a1e2a4452c Merge remote-tracking branch 'origin/master' into feat/chainwatch-pg 2020-01-14 06:09:30 +01:00
Whyrusleeping 3b34eba612 Merge pull request #997 from filecoin-project/feat/testnet2
Testnet2
2020-01-13 19:48:34 -08:00
Łukasz Magiera 11ac026b62 Merge branch 'feat/testnet2' into feat/chainwatch-pg 2020-01-14 04:20:39 +01:00
Łukasz Magiera 05970ffadd Merge pull request #1068 from filecoin-project/feat/testnet2-new-genesis
New testnet2 genesis
2020-01-14 04:15:11 +01:00
Travis Person 488a156e6f New testnet2 genesis 2020-01-14 03:10:31 +00:00
Łukasz Magiera a0f2bb0755 Increase block delay for TestAPIDealFlowReal 2020-01-14 03:51:14 +01:00
Whyrusleeping 9fded49470 Merge pull request #1067 from filecoin-project/feat/mock-sb-verif
Deal tests with mock sectorbuilder
2020-01-13 18:40:10 -08:00
Łukasz Magiera 69752b419d Update sectorbuilder 2020-01-14 03:09:34 +01:00
Łukasz Magiera 3d3e85c52d mod tidy 2020-01-14 03:05:46 +01:00
Łukasz Magiera 94a21e3aeb Update deps 2020-01-14 03:05:46 +01:00
Łukasz Magiera 2ca0c152ba Deal tests on mock sectorbuilder 2020-01-14 03:05:46 +01:00
Łukasz Magiera a2bcc1fec2 Mostly functional mock sectorbuilder 2020-01-14 03:05:35 +01:00
Łukasz Magiera 6cdac5df4f Merge pull request #1066 from filecoin-project/docs/1k-params-debug
note that you need to manually download params when building in debug
2020-01-14 02:17:27 +01:00
whyrusleeping 92357b3a8b note that you need to manually download params when building in debug mode 2020-01-13 17:15:42 -08:00
Łukasz Magiera 872ee5b7e7 Merge pull request #1065 from filecoin-project/bug/more-rice
Add rice calls to stats and lotus-shed
2020-01-14 01:53:57 +01:00
Travis Person 4d30ab77be Add rice calls to stats and lotus-shed 2020-01-14 00:50:48 +00:00
Łukasz Magiera 85f0f0bf81 mod tidy 2020-01-14 00:38:08 +01:00
Łukasz Magiera d6174292b3 Merge pull request #1064 from filecoin-project/fix/drop-th-pnet
Drop pnet from townhall
2020-01-14 00:37:29 +01:00
Łukasz Magiera 0bf41bcd10 Drop pnet from townhall 2020-01-14 00:36:05 +01:00
Łukasz Magiera 027a0e805b Merge pull request #1063 from filecoin-project/feat/no-more-pnet
remove private network and put dht into a sub namespace
2020-01-14 00:31:11 +01:00
whyrusleeping fefd21ad9c remove private network and put dht into a sub namespace 2020-01-13 15:29:06 -08:00
Łukasz Magiera d9c803ea9e Merge pull request #1062 from filecoin-project/feat/no-more-1gb-sectors
remove support for 1gb sectors
2020-01-14 00:21:21 +01:00
whyrusleeping 0414e99fe7 remove support for 1gb sectors 2020-01-13 15:18:26 -08:00
Łukasz Magiera 0fb51a95cc Merge pull request #1061 from filecoin-project/feat/testnet2-network
Add bootstrap peers and genesis
2020-01-13 23:13:39 +01:00
Travis Person 9298d183bf Add bootstrap peers and genesis 2020-01-13 22:08:11 +00:00
Łukasz Magiera 0402abe36b Fix tests 2020-01-13 21:59:21 +01:00
Łukasz Magiera 44112da971 Merge pull request #1060 from filecoin-project/feat/reserve-sector-states
Revesve some sector states
2020-01-13 21:56:13 +01:00
Łukasz Magiera 2ed89f496f Revesve some sector states 2020-01-13 21:54:28 +01:00
Łukasz Magiera 2fecf3a8f1 Fix tests 2020-01-13 21:51:34 +01:00
Łukasz Magiera 2ef8c1ae0c statemachine: Better naming 2020-01-13 18:44:59 +01:00
Łukasz Magiera 2fea9433d8 sectors: Correctly set CommitMessage 2020-01-13 18:18:52 +01:00
Łukasz Magiera e06c19b51c update deps 2020-01-13 17:39:54 +01:00
Łukasz Magiera 34abc3d023 Merge branch 'feat/testnet2' into feat/event-states 2020-01-13 15:52:43 +01:00
Łukasz Magiera d78a5e0a9f Decimal types for some miner columns 2020-01-13 14:01:11 +01:00
Łukasz Magiera 719171faa3 Set smaller batch size 2020-01-13 00:46:54 +01:00
Łukasz Magiera a896b30039 gofmt 2020-01-10 20:55:58 +01:00
Łukasz Magiera 50bac00329 Merge branch 'master' into feat/testnet2 2020-01-10 20:55:40 +01:00
Łukasz Magiera b6fda30719 Merge pull request #1057 from filecoin-project/feat/markets-extraction
Markets Extraction
2020-01-10 20:49:09 +01:00
Whyrusleeping fd4af3f7a9 Merge pull request #1056 from filecoin-project/fix/candidate-dupe
check for duplicate candidates in block headers
2020-01-10 11:24:46 -08:00
Łukasz Magiera f6d41ee77d Port sector state maching to evtsm 2020-01-10 20:24:15 +01:00
hannahhoward 0ce1bf706b refactor(markets): reorg file structure 2020-01-10 10:33:26 -08:00
hannahhoward 56653eeca6 fix(storagemarket): fix compile errors 2020-01-10 10:01:48 -08:00
whyrusleeping 83605dfd95 check for duplicate candidates in block headers 2020-01-10 09:57:58 -08:00
hannahhoward 353f93fddf fix(storagemarketadapter): minor fix for test 2020-01-10 09:49:41 -08:00
hannahhoward 65ecb33630 feat(storagemarket): extract storage market
remove all shared components, point at go-fil-components repo
2020-01-10 09:49:07 -08:00
hannahhoward 0a4eeb7cb1 refactor(retrievalmarket): switch to go-fil-markets repo
Switch go-fil-components to go-fil-markets
2020-01-10 09:13:12 -08:00
Łukasz Magiera 469136ee86 Merge pull request #1040 from filecoin-project/feat/fork-signaling
Add fork signaling to blockheader
2020-01-10 13:33:29 +01:00
hannahhoward ccf359d057 feat(retrieval): extract retrievalmarket
Extract retrieval market and modify shared types
2020-01-09 19:46:07 -08:00
Łukasz Magiera d6b0648610 Merge pull request #951 from filecoin-project/feat/storage-market-skeleton
Storage Market: Draw clean interfaces and node boundaries around storage market
2020-01-10 03:58:39 +01:00
hannahhoward da4528932a feat(storagemarket): initial extraction
Types for storage market

Modify deals.Provider to implement storagemarket.StorageProvider

Inject storagemarket.StorageProvider

Storage Provider interfaces

Storage Client interfaces

Add ValidatePublishedDeal to ClientNodeAdapter

Remove FundManager from client

Remove Wallet from client

Remove StateManager, Events, Wallet from client

Rebasing

- Copy types.BigInt, use TokenAmount/BigInt for token amounts
- Remove auto-imported log package
- Move `checkAskSignature` to a client file.
- Plumb contexts through

fix(storagemarket): use publish cids

Switch back to publish message cids to reduce the dependency surface area
2020-01-10 03:29:46 +01:00
Łukasz Magiera 5f460b380d Merge pull request #1045 from filecoin-project/feat/mock-sectorbuilder
WIP: implement mock sectorbuilder for easier storage miner testing
2020-01-10 01:33:43 +01:00
Łukasz Magiera 55f76f19d3 Merge pull request #1051 from filecoin-project/feat/self-deal-no-sig
don't require signatures for self deals
2020-01-10 01:25:06 +01:00
Łukasz Magiera 0bafc00b52 Merge pull request #1052 from filecoin-project/feat/coverage-integration
Renable codecov, improve CI
2020-01-10 01:21:53 +01:00
Jakub Sztandera d309b56ad6 Codecov ignore cbor gen
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-09 23:52:44 +01:00
whyrusleeping 6c9289df0a don't require signatures for self deals 2020-01-09 14:18:06 -08:00
Jakub Sztandera a82a0769fa Disable buildall on macos (it takes forever)
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-09 23:13:07 +01:00
Jakub Sztandera 61849ef7ea Enable codecov
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-09 23:12:33 +01:00
Jakub Sztandera 960b6012c2 Count coverage of integration tests
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-09 22:53:41 +01:00
Łukasz Magiera da2a11ed76 Event-based state machine 2020-01-09 22:23:31 +01:00
Łukasz Magiera f0f8d83980 Merge pull request #826 from filecoin-project/feat/retrieval-market-skeleton
Retrieval Market Cleanup W/ Node Interfaces
2020-01-09 22:06:46 +01:00
whyrusleeping 45e576addf mod tidy 2020-01-09 12:59:37 -08:00
whyrusleeping 7534ac1e1a add ability to control seal operations completion time 2020-01-09 12:50:45 -08:00
whyrusleeping bda85e4097 more features, better locking 2020-01-09 11:23:42 -08:00
whyrusleeping 5e16aab51b fix tests, expand interfaces a little 2020-01-09 10:28:14 -08:00
Jakub Sztandera f572d9735d Merge pull request #1049 from filecoin-project/fix/sb-ds-prefix
Pass correct datastore into sectorbuilder
2020-01-09 15:33:15 +01:00
Łukasz Magiera fac47bfc54 Pass correct datastore into sectorbuilder 2020-01-09 14:23:44 +01:00
whyrusleeping cc56389dbb attempt to fix the DI loading, still not working 2020-01-08 20:51:18 -08:00
whyrusleeping 60969c69a7 implement a mocked out sectorbuilder, probably not useful yet 2020-01-08 20:27:14 -08:00
hannahhoward 99309ec0dc fix(retrievalmarket): add mutex for subscribers
Add a mutex to protect access to the subscriber list for retrieval market
2020-01-08 19:46:11 -08:00
whyrusleeping d08898ef37 make storage miner acccept an interface to the sectorbuilder 2020-01-08 17:10:17 -08:00
Łukasz Magiera b7e35ae3ed Merge pull request #1042 from filecoin-project/feat/limit-seal-proof-lookback
Set hard limit on maximum randomness lookback for seal proof submissions
2020-01-09 01:14:46 +01:00
whyrusleeping 7ba34535b7 Set hard limit on maximum randomness lookback for seal proof submissions 2020-01-08 14:43:03 -08:00
Łukasz Magiera 8cbcbbd7a4 Merge branch 'feat/testnet2' of github.com:filecoin-project/go-lotus into feat/testnet2 2020-01-08 22:44:54 +01:00
Łukasz Magiera 36a5c7d8f5 Merge branch 'master' into feat/testnet2 2020-01-08 22:38:45 +01:00
hannahhoward 5b74a71dd3 feat(retrievalmarket): extract skeleton interfaces
Define all types to spec, modify interfaces, wrap old code

fix(builder): use client blockstore for retrieval

feat(retrieval): add node implementations

add node adapters for client & provider so that retrieval can be extracted
2020-01-08 12:45:43 -08:00
Łukasz Magiera 716b2a4bcb Merge pull request #1041 from filecoin-project/fix/paramsjson-embed
paramfetch: bring parameters.json back to this repo
2020-01-08 21:41:32 +01:00
Łukasz Magiera 13c8fe3fb3 mod tidy 2020-01-08 21:31:44 +01:00
Łukasz Magiera da38822dfd paramfetch: bring parameters.json back to this repo 2020-01-08 21:31:35 +01:00
Łukasz Magiera f36d81070b mod tidy 2020-01-08 21:15:55 +01:00
Jakub Sztandera 959b725ab6 Merge pull request #1038 from filecoin-project/feat/new-golog
Update go-log to v2
2020-01-08 20:41:55 +01:00
Łukasz Magiera 3891f015d7 Merge pull request #1039 from filecoin-project/feat/secpk-default
switch default key type to secp256k1
2020-01-08 20:40:08 +01:00
Jakub Sztandera 8cfb4aafcd Add fork signaling to blockheader
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-08 20:31:08 +01:00
whyrusleeping 6ce9a7f225 switch default key type to secp256k1 2020-01-08 11:24:18 -08:00
Jakub Sztandera 1ed62628a7 Update go-log to v2
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-08 20:22:31 +01:00
Jakub Sztandera b5328d01cf Update to go-log v1.0.1
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-08 20:20:56 +01:00
Jakub Sztandera 72a62d49b3 Merge pull request #1037 from filecoin-project/feat/badger2
Update to badger v2
2020-01-08 20:20:11 +01:00
Jakub Sztandera 886898b137 Update to badger v2
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-08 19:56:45 +01:00
Łukasz Magiera a9ca6d4065 Merge branch 'master' into feat/chainwatch-pg 2020-01-08 18:50:58 +01:00
Łukasz Magiera 79028397ad chainwatch: sync in batches 2020-01-08 17:29:46 +01:00
Łukasz Magiera 1b5e1c4753 gofmt 2020-01-08 15:18:30 +01:00
Łukasz Magiera 855fb26a81 mod tidy 2020-01-08 15:18:13 +01:00
Łukasz Magiera ab922ed1ba Merge remote-tracking branch 'origin/master' into feat/chainwatch-pg 2020-01-08 15:08:34 +01:00
Łukasz Magiera f198e81af1 Merge pull request #1032 from filecoin-project/feat/drop-most-fatal-errors
reduce most vm errors to non-fatal, explicitly mark disk issues as fatal
2020-01-08 14:58:35 +01:00
Łukasz Magiera 9fd183e74f Merge pull request #500 from filecoin-project/feat/dt-implementation
Extract Data Transfer Implementation
2020-01-08 14:52:01 +01:00
Łukasz Magiera bf9aa4465b mod tidy 2020-01-08 14:20:43 +01:00
hannahhoward 5312340bf9 refactor(datatransfer): use independent repo
Use independent repo for go-data-transfer
2020-01-08 14:20:31 +01:00
hannahhoward 61e2568b8d feat(datatransfer): implement and extract
feat(datatransfer): setup implementation path

Sets up a path to implementation, offering both the dagservice implementation and a future graphsync
implement, establishes message interfaces and network layer, and isolates the datatransfer module
from the app

WIP using CBOR encoding for dataxfermsg

* Bring cbor-gen stuff into datatransfer package
* make transferRequest private struct
* add transferResponse + funcs
* Rename VoucherID to VoucherType
* more tests passing

WIP trying out some stuff
* Embed request/response in message so all the interfaces work AND the CBOR unmarshaling works: this is more like the spec anyway
* get rid of pb stuff

all message tests passing, some others in datatransfer

Some cleanup for PR

Cleanup for PR, clarifying and additional comments

mod tidy

Respond to PR comments:
* Make DataTransferRequest/Response be returned in from Net
* Regenerate cbor_gen and fix the generator caller so it works better
* Please the linters

Fix tests

Initiate push and pull requests (#536)

* add issue link for data TransferID generation
* comment out failing but not relevant tests
* finish voucher rename from Identifier --> Type

tests passing

cleanup for PR

remove unused fmt import in graphsync_test

a better reflection

send data transfer response

other tests passing

feat(datatransfer): milestone 2 infrastructure

Setup test path for all tickets for milestone 2

responses alert subscribers when request is not accepted (#607)

Graphsync response is scheduled when a valid push request is received (#625)

fix(datatransfer): fix tests

fix an error with read buffers in tests

fix(deps): fix go.sum

Feat/dt graphsync pullreqs (#627)

* graphsync responses to pull requests

Feat/dt initiator cleanup (#645)

* ChannelID.To --> ChannelID.Initiator
* We now store our peer ID (from host.ID()) so it can be used when creating ChannelIDs.
* InProgressChannels returns all of impl.channels, currently just for testing
* Implements go-data-transfer issue
* Some assertions were changed based on the above.
* Renamed some variables and added some assertions based on the new understanding
* Updated SHA for graphsync module
* Updated fakeGraphSync test structs to use new interfaces from new SHA above

Techdebt/dt split graphsync impl receiver (#651)

* Split up graphsyncImpl and graphsyncReceiver
* rename graphsync to utils

DTM sends data over graphsync for validated push requests (#665)

* create channels when a request is received. register push request hook with graphsync. fix tests.
* better NewReaders
* use mutex lock around impl.channels access
* fix(datatransfer): fix test uncertainty
* fix a data race and also don't use random bytes in basic block which can fail
* privatize 3 funcs

with @hannahhoward

Feat/dt gs pullrequests (#693)

* Implements DTM Sends Data Over Graphsync For Validated Pull Requests
* rename a field in a test struct
* refactor a couple of private functions (one was refactored out of existence)

Feat/dt subscribe, file Xfer round trip (#720)

Implements the rest of Subscriber Is Notified When Request Completed #24:
* send a graphsync message within a go func and consume responses until error or transfer is complete.
* notify subscribers of results.
* Rename datatransfer.Event to EventCode.
* datatransfer.Event is now a struct that includes a message and a timestamp as well as the Event.Code int, formerly Event, update all uses
* Add extension data to graphsync request hook, gsReq
* rename sendRequest to sendDtRequest, to distinguish it from sendGsRequest, where Dt = datatransfer, Gs = graphsync
* use a mutex lock for last transfer ID
* obey the linter

Don't respond with error in gsReqRcdHook when we can't find the datatransfer extension. (#754)

* update to correct graphsync version, update tests & code to call the new graphsync hooks
* getExtensionData returns an empty struct + nil if we can't find our extension
* Don't respond with error when we can't find the extension.
* Test for same
* mod tidy

minor fix to go.sum

feat(datatransfer): switch to graphsync implementation

Move over to real graphsync implementation of data transfer, add constructors for graphsync
instances on client and miner side

fix(datatransfer): Fix validators

Validators were checking payload cid against commP -- which are not the same any more. Added a
payloadCid to client deal to maintain the record, fixed validator logic

Feat/dt extraction use go-fil-components/datatransfer (#770)

* Initial commit after changing to go-fil-components/datatransfer
* blow away the datatransfer dir
* use go-fil-components master after its PR #1 was merged
* go mod tidy

use a package

updates after rebase with master
2020-01-08 14:19:28 +01:00
Łukasz Magiera 1392dcc273 Merge remote-tracking branch 'origin/master' into feat/testnet2 2020-01-08 13:53:01 +01:00
Jakub Sztandera d213bd1fee Merge pull request #1025 from filecoin-project/fix/faults-counting
Fix faults handling
2020-01-08 11:03:14 +01:00
whyrusleeping 3965e1053e fix build 2020-01-07 21:05:45 -08:00
whyrusleeping e41dbdad90 reduce most vm errors to non-fatal, explicitly mark disk issues as fatal 2020-01-07 19:46:55 -08:00
Jakub Sztandera 64496690bb go mod tidy
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-07 23:09:46 +01:00
Jakub Sztandera f572cdea47 Fix logic, improve tests
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-07 23:03:58 +01:00
Jakub Sztandera 5e775929be Cleanup handing and add tests
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-07 23:03:58 +01:00
Jakub Sztandera 65724133ea Add tests
,
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-07 23:03:58 +01:00
Jakub Sztandera a63c34a902 Handle faults in ss and pss correctly
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-07 23:03:18 +01:00
Jakub Sztandera dbc729d049 Validate length of RLE
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-07 22:54:43 +01:00
Łukasz Magiera 7b134b8317 Merge pull request #1031 from filecoin-project/feat/block-message-limit
introduce a limit on the number of messages a block can have
2020-01-07 21:48:57 +01:00
Łukasz Magiera 22e9815928 Merge remote-tracking branch 'origin/master' into feat/testnet2 2020-01-07 21:45:30 +01:00
whyrusleeping a109ae1490 introduce a limit on the number of messages a block can have 2020-01-07 12:41:26 -08:00
Łukasz Magiera 97ae184d0a Merge remote-tracking branch 'origin/master' into feat/testnet2 2020-01-07 15:06:35 +01:00
Łukasz Magiera 605562467d Flatten fork code for testnet2 2020-01-06 19:39:57 +01:00
Łukasz Magiera 97cf3f70a5 chainwatch: sub to mpool/blocks afetr initial sync 2019-12-13 15:47:51 +01:00
Łukasz Magiera 2e9655a4e0 More fixes 2019-12-13 14:42:01 +01:00
Łukasz Magiera 3d666b3992 Merge branch 'feat/chainwatch-stuff' into feat/chainwatch-pg 2019-12-13 12:57:59 +01:00
Łukasz Magiera a246be587e chainwatch: fix ui queries 2019-12-13 12:48:42 +01:00
Łukasz Magiera f2ea12571f Optimise mpool update processing 2019-12-13 12:04:24 +01:00
Łukasz Magiera 165ac1d556 Merge remote-tracking branch 'origin/master' into feat/chainwatch-pg 2019-12-13 10:34:24 +01:00
Łukasz Magiera 1018999096 WIP fixing queries 2019-12-13 10:30:51 +01:00
Łukasz Magiera 04691a13da chainwatch: Fix postgres data import 2019-12-12 19:34:28 +01:00
Łukasz Magiera e34e5b27ba Merge branch 'master' into feat/chainwatch-pg 2019-12-12 17:57:35 +01:00
Łukasz Magiera 66ee9d209d wip 2019-12-11 23:17:44 +01:00
Łukasz Magiera 830f2cbdd3 Merge branch 'master' into feat/chainwatch-pg 2019-12-11 22:13:08 +01:00
Łukasz Magiera b6b06f67dc chainwatch: Postgres 2019-12-11 00:42:36 +01:00
Łukasz Magiera 3edc93f117 wip chainwatch ui 2019-12-07 23:44:45 +01:00
ldoublewood 86f078dbea restore Makefile 2019-12-05 14:47:23 +08:00
ldoublewood f739b7e377 add docker support 2019-12-05 11:31:32 +08:00
252 changed files with 13307 additions and 8303 deletions
+98 -8
View File
@@ -7,6 +7,9 @@ executors:
docker:
- image: circleci/golang:1.13
resource_class: 2xlarge
ubuntu:
docker:
- image: ubuntu:19.10
commands:
install-deps:
@@ -24,6 +27,8 @@ commands:
description: is a darwin build environment?
type: boolean
steps:
- checkout
- git_fetch_all_tags
- checkout
- when:
condition: << parameters.linux >>
@@ -46,7 +51,27 @@ commands:
key: 'v20-1k-lotus-params'
paths:
- /var/tmp/filecoin-proof-parameters/
install_ipfs:
steps:
- run: |
apt update
apt install -y wget
wget https://github.com/ipfs/go-ipfs/releases/download/v0.4.22/go-ipfs_v0.4.22_linux-amd64.tar.gz
wget https://github.com/ipfs/go-ipfs/releases/download/v0.4.22/go-ipfs_v0.4.22_linux-amd64.tar.gz.sha512
if [ "$(sha512sum go-ipfs_v0.4.22_linux-amd64.tar.gz)" != "$(cat go-ipfs_v0.4.22_linux-amd64.tar.gz.sha512)" ]
then
echo "ipfs failed checksum check"
exit 1
fi
tar -xf go-ipfs_v0.4.22_linux-amd64.tar.gz
mv go-ipfs/ipfs /usr/local/bin/ipfs
chmod +x /usr/local/bin/ipfs
git_fetch_all_tags:
steps:
- run:
name: fetch all tags
command: |
git fetch --all
jobs:
mod-tidy-check:
@@ -74,6 +99,13 @@ jobs:
path: lotus
- store_artifacts:
path: lotus-storage-miner
- store_artifacts:
path: lotus-seal-worker
- run: mkdir linux && mv lotus lotus-storage-miner lotus-seal-worker linux/
- persist_to_workspace:
root: "."
paths:
- linux
test: &test
description: |
@@ -100,7 +132,7 @@ jobs:
description: gotestsum format. https://github.com/gotestyourself/gotestsum#format
coverage:
type: string
default: -coverprofile=coverage.txt
default: -coverprofile=coverage.txt -coverpkg=github.com/filecoin-project/lotus/...
description: Coverage flag. Set to the empty string to disable.
codecov-upload:
type: boolean
@@ -153,7 +185,7 @@ jobs:
- "~/go/src/github.com"
- "~/go/src/golang.org"
test-short:
test-short:
<<: *test
build-macos:
@@ -190,12 +222,19 @@ jobs:
- install-deps
- go/mod-download
- run:
command: make buildall
command: make build
no_output_timeout: 30m
- store_artifacts:
path: lotus
- store_artifacts:
path: lotus-storage-miner
- store_artifacts:
path: lotus-seal-worker
- run: mkdir darwin && mv lotus lotus-storage-miner lotus-seal-worker darwin/
- persist_to_workspace:
root: "."
paths:
- darwin
- save_cache:
name: save cargo cache
key: v3-go-deps-{{ arch }}-{{ checksum "~/go/src/github.com/filecoin-project/lotus/go.sum" }}
@@ -246,6 +285,26 @@ jobs:
lint-all:
<<: *lint
publish:
description: publish binary artifacts
executor: ubuntu
steps:
- run:
name: Install git jq curl
command: apt update && apt install -y git jq curl
- checkout
- git_fetch_all_tags
- checkout
- install_ipfs
- attach_workspace:
at: "."
- run:
name: Create bundles
command: ./scripts/build-bundle.sh
- run:
name: Publish release
command: ./scripts/publish-release.sh
workflows:
version: 2.1
@@ -253,9 +312,40 @@ workflows:
jobs:
- lint-changes:
args: "--new-from-rev origin/master"
- test
- test:
codecov-upload: true
- mod-tidy-check
- test-short:
go-test-flags: "--timeout 10m --short"
- mod-tidy-check
- build-all
- build-macos
filters:
tags:
only:
- /^v\d+\.\d+\.\d+$/
- build-all:
requires:
- test-short
filters:
tags:
only:
- /^v\d+\.\d+\.\d+$/
- build-macos:
requires:
- test-short
filters:
branches:
ignore:
- /.*/
tags:
only:
- /^v\d+\.\d+\.\d+$/
- publish:
requires:
- build-all
- build-macos
filters:
branches:
ignore:
- /.*/
tags:
only:
- /^v\d+\.\d+\.\d+$/
+2
View File
@@ -1 +1,3 @@
comment: off
ignore:
- "cbor_gen.go"
+1
View File
@@ -0,0 +1 @@
.gitignore
+4
View File
@@ -2,6 +2,7 @@
/lotus-storage-miner
/lotus-seal-worker
/lotus-seed
/lotus-health
/pond
/townhall
/fountain
@@ -25,6 +26,9 @@ build/paramfetch.sh
/blocks.svg
/chainwatch
/chainwatch.db
/bundle
/darwin
/linux
*-fuzz.zip
/chain/types/work_msg/
+2 -1
View File
@@ -1,7 +1,8 @@
linters:
disable-all: true
enable:
- vet
- gofmt
- govet
- goimports
- misspell
- goconst
+13 -3
View File
@@ -14,7 +14,7 @@ MODULES:=
CLEAN:=
BINS:=
GOFLAGS+=-ldflags="-X "github.com/filecoin-project/lotus/build".CurrentCommit=+git$(subst -,.,$(shell git describe --always --match=NeVeRmAtCh --dirty 2>/dev/null || git rev-parse --short HEAD 2>/dev/null))"
GOFLAGS+=-ldflags=-X="github.com/filecoin-project/lotus/build".CurrentCommit="+git$(subst -,.,$(shell git describe --always --match=NeVeRmAtCh --dirty 2>/dev/null || git rev-parse --short HEAD 2>/dev/null))"
## FFI
@@ -76,6 +76,7 @@ BINS+=lotus-seal-worker
lotus-shed: $(BUILD_DEPS)
rm -f lotus-shed
go build $(GOFLAGS) -o lotus-shed ./cmd/lotus-shed
go run github.com/GeertJohan/go.rice/rice append --exec lotus-shed -i ./build
.PHONY: lotus-seal-worker
BINS+=lotus-seal-worker
@@ -123,14 +124,14 @@ BINS+=townhall
fountain:
rm -f fountain
go build -o fountain ./cmd/lotus-fountain
go run github.com/GeertJohan/go.rice/rice append --exec fountain -i ./cmd/lotus-fountain
go run github.com/GeertJohan/go.rice/rice append --exec fountain -i ./cmd/lotus-fountain -i ./build
.PHONY: fountain
BINS+=fountain
chainwatch:
rm -f chainwatch
go build -o chainwatch ./cmd/lotus-chainwatch
go run github.com/GeertJohan/go.rice/rice append --exec chainwatch -i ./cmd/lotus-chainwatch
go run github.com/GeertJohan/go.rice/rice append --exec chainwatch -i ./cmd/lotus-chainwatch -i ./build
.PHONY: chainwatch
BINS+=chainwatch
@@ -144,9 +145,18 @@ BINS+=bench
stats:
rm -f stats
go build -o stats ./tools/stats
go run github.com/GeertJohan/go.rice/rice append --exec stats -i ./build
.PHONY: stats
BINS+=stats
health:
rm -f lotus-health
go build -o lotus-health ./cmd/lotus-health
go run github.com/GeertJohan/go.rice/rice append --exec lotus-health -i ./build
.PHONY: health
BINS+=health
# MISC
buildall: $(BINS)
+1 -1
View File
@@ -2,7 +2,7 @@
# Project Lotus - 莲
Lotus is an experimental implementation of the Filecoin Distributed Storage Network. For more details about Filecoin, check out the [Filecoin Spec](https://github.com/filecoin-project/specs).
Lotus is an implementation of the Filecoin Distributed Storage Network. For more details about Filecoin, check out the [Filecoin Spec](https://github.com/filecoin-project/specs).
## Development
+3
View File
@@ -29,6 +29,9 @@ type Common interface {
// Version provides information about API provider
Version(context.Context) (Version, error)
LogList(context.Context) ([]string, error)
LogSetLevel(context.Context, string, string) error
}
// Version provides various build-time information
+41 -28
View File
@@ -4,11 +4,11 @@ import (
"context"
"time"
"github.com/filecoin-project/go-address"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-filestore"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
@@ -30,22 +30,26 @@ type FullNode interface {
ChainGetBlockMessages(context.Context, cid.Cid) (*BlockMessages, error)
ChainGetParentReceipts(context.Context, cid.Cid) ([]*types.MessageReceipt, error)
ChainGetParentMessages(context.Context, cid.Cid) ([]Message, error)
ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error)
ChainGetTipSetByHeight(context.Context, uint64, types.TipSetKey) (*types.TipSet, error)
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
ChainSetHead(context.Context, *types.TipSet) error
ChainHasObj(context.Context, cid.Cid) (bool, error)
ChainSetHead(context.Context, types.TipSetKey) error
ChainGetGenesis(context.Context) (*types.TipSet, error)
ChainTipSetWeight(context.Context, *types.TipSet) (types.BigInt, error)
ChainTipSetWeight(context.Context, types.TipSetKey) (types.BigInt, error)
ChainGetNode(ctx context.Context, p string) (interface{}, error)
ChainGetMessage(context.Context, cid.Cid) (*types.Message, error)
ChainGetPath(ctx context.Context, from types.TipSetKey, to types.TipSetKey) ([]*store.HeadChange, error)
ChainExport(context.Context, types.TipSetKey) (<-chan []byte, error)
// syncer
SyncState(context.Context) (*SyncState, error)
SyncSubmitBlock(ctx context.Context, blk *types.BlockMsg) error
SyncIncomingBlocks(ctx context.Context) (<-chan *types.BlockHeader, error)
SyncMarkBad(ctx context.Context, bcid cid.Cid) error
SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error)
// messages
MpoolPending(context.Context, *types.TipSet) ([]*types.SignedMessage, error)
MpoolPending(context.Context, types.TipSetKey) ([]*types.SignedMessage, error)
MpoolPush(context.Context, *types.SignedMessage) (cid.Cid, error)
MpoolPushMessage(context.Context, *types.Message) (*types.SignedMessage, error) // get nonce, sign, push
MpoolGetNonce(context.Context, address.Address) (uint64, error)
@@ -55,7 +59,7 @@ type FullNode interface {
// miner
MinerCreateBlock(context.Context, address.Address, *types.TipSet, *types.Ticket, *types.EPostProof, []*types.SignedMessage, uint64, uint64) (*types.BlockMsg, error)
MinerCreateBlock(context.Context, address.Address, types.TipSetKey, *types.Ticket, *types.EPostProof, []*types.SignedMessage, uint64, uint64) (*types.BlockMsg, error)
// // UX ?
@@ -93,31 +97,35 @@ type FullNode interface {
//ClientListAsks() []Ask
// if tipset is nil, we'll use heaviest
StateCall(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error)
StateReplay(context.Context, *types.TipSet, cid.Cid) (*ReplayResults, error)
StateGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error)
StateReadState(ctx context.Context, act *types.Actor, ts *types.TipSet) (*ActorState, error)
StateListMessages(ctx context.Context, match *types.Message, ts *types.TipSet, toht uint64) ([]cid.Cid, error)
StateCall(context.Context, *types.Message, types.TipSetKey) (*MethodCall, error)
StateReplay(context.Context, types.TipSetKey, cid.Cid) (*ReplayResults, error)
StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error)
StateReadState(ctx context.Context, act *types.Actor, tsk types.TipSetKey) (*ActorState, error)
StateListMessages(ctx context.Context, match *types.Message, tsk types.TipSetKey, toht uint64) ([]cid.Cid, error)
StateMinerSectors(context.Context, address.Address, *types.TipSet) ([]*ChainSectorInfo, error)
StateMinerProvingSet(context.Context, address.Address, *types.TipSet) ([]*ChainSectorInfo, error)
StateMinerPower(context.Context, address.Address, *types.TipSet) (MinerPower, error)
StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error)
StateMinerPeerID(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error)
StateMinerElectionPeriodStart(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error)
StateMinerSectorSize(context.Context, address.Address, *types.TipSet) (uint64, error)
StatePledgeCollateral(context.Context, *types.TipSet) (types.BigInt, error)
StateMinerSectors(context.Context, address.Address, types.TipSetKey) ([]*ChainSectorInfo, error)
StateMinerProvingSet(context.Context, address.Address, types.TipSetKey) ([]*ChainSectorInfo, error)
StateMinerPower(context.Context, address.Address, types.TipSetKey) (MinerPower, error)
StateMinerWorker(context.Context, address.Address, types.TipSetKey) (address.Address, error)
StateMinerPeerID(ctx context.Context, m address.Address, tsk types.TipSetKey) (peer.ID, error)
StateMinerElectionPeriodStart(ctx context.Context, actor address.Address, tsk types.TipSetKey) (uint64, error)
StateMinerSectorSize(context.Context, address.Address, types.TipSetKey) (uint64, error)
StateMinerFaults(context.Context, address.Address, types.TipSetKey) ([]uint64, error)
StatePledgeCollateral(context.Context, types.TipSetKey) (types.BigInt, error)
StateWaitMsg(context.Context, cid.Cid) (*MsgWait, error)
StateListMiners(context.Context, *types.TipSet) ([]address.Address, error)
StateListActors(context.Context, *types.TipSet) ([]address.Address, error)
StateMarketBalance(context.Context, address.Address, *types.TipSet) (actors.StorageParticipantBalance, error)
StateMarketParticipants(context.Context, *types.TipSet) (map[string]actors.StorageParticipantBalance, error)
StateMarketDeals(context.Context, *types.TipSet) (map[string]actors.OnChainDeal, error)
StateMarketStorageDeal(context.Context, uint64, *types.TipSet) (*actors.OnChainDeal, error)
StateLookupID(context.Context, address.Address, *types.TipSet) (address.Address, error)
StateListMiners(context.Context, types.TipSetKey) ([]address.Address, error)
StateListActors(context.Context, types.TipSetKey) ([]address.Address, error)
StateMarketBalance(context.Context, address.Address, types.TipSetKey) (actors.StorageParticipantBalance, error)
StateMarketParticipants(context.Context, types.TipSetKey) (map[string]actors.StorageParticipantBalance, error)
StateMarketDeals(context.Context, types.TipSetKey) (map[string]actors.OnChainDeal, error)
StateMarketStorageDeal(context.Context, uint64, types.TipSetKey) (*actors.OnChainDeal, error)
StateLookupID(context.Context, address.Address, types.TipSetKey) (address.Address, error)
StateChangedActors(context.Context, cid.Cid, cid.Cid) (map[string]types.Actor, error)
StateGetReceipt(context.Context, cid.Cid, *types.TipSet) (*types.MessageReceipt, error)
StateMinerSectorCount(context.Context, address.Address, *types.TipSet) (MinerSectors, error)
StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error)
StateMinerSectorCount(context.Context, address.Address, types.TipSetKey) (MinerSectors, error)
StateCompute(context.Context, uint64, []*types.Message, types.TipSetKey) (cid.Cid, error)
MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
MarketEnsureAvailable(context.Context, address.Address, types.BigInt) error
// MarketFreeBalance
@@ -268,6 +276,11 @@ type ReplayResults struct {
Error string
}
type MethodCall struct {
types.MessageReceipt
Error string
}
type ActiveSync struct {
Base *types.TipSet
Target *types.TipSet
+38 -5
View File
@@ -13,22 +13,42 @@ type SectorState = uint64
const (
UndefinedSectorState SectorState = iota
Empty // TODO: Is this useful
// happy path
Empty
Packing // sector not in sealStore, and not on chain
Unsealed // sealing / queued
PreCommitting // on chain pre-commit
PreCommitted // waiting for seed
WaitSeed // waiting for seed
Committing
CommitWait // waiting for message to land on chain
FinalizeSector
Proving
_ // reserved
_
_
// recovery handling
// Reseal
_
_
_
_
_
_
_
// error modes
FailedUnrecoverable
SealFailed
PreCommitFailed
SealCommitFailed
CommitFailed
FailedUnrecoverable
PackingFailed
_
_
_
Faulty // sector is corrupted or gone for some reason
FaultReported // sector has been declared as a fault on chain
@@ -41,15 +61,17 @@ var SectorStates = []string{
Packing: "Packing",
Unsealed: "Unsealed",
PreCommitting: "PreCommitting",
PreCommitted: "PreCommitted",
WaitSeed: "WaitSeed",
Committing: "Committing",
CommitWait: "CommitWait",
FinalizeSector: "FinalizeSector",
Proving: "Proving",
SealFailed: "SealFailed",
PreCommitFailed: "PreCommitFailed",
SealCommitFailed: "SealCommitFailed",
CommitFailed: "CommitFailed",
PackingFailed: "PackingFailed",
FailedUnrecoverable: "FailedUnrecoverable",
@@ -87,6 +109,15 @@ type StorageMiner interface {
WorkerDone(ctx context.Context, task uint64, res sectorbuilder.SealRes) error
}
type SectorLog struct {
Kind string
Timestamp uint64
Trace string
Message string
}
type SectorInfo struct {
SectorID uint64
State SectorState
@@ -99,6 +130,8 @@ type SectorInfo struct {
Retries uint64
LastErr string
Log []SectorLog
}
type SealedRef struct {
+61
View File
@@ -0,0 +1,61 @@
package apibstore
import (
"context"
blocks "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
blockstore "github.com/ipfs/go-ipfs-blockstore"
"golang.org/x/xerrors"
)
type ChainIO interface {
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
ChainHasObj(context.Context, cid.Cid) (bool, error)
}
type apiBStore struct {
api ChainIO
}
func (a *apiBStore) DeleteBlock(cid.Cid) error {
return xerrors.New("not supported")
}
func (a *apiBStore) Has(c cid.Cid) (bool, error) {
return a.api.ChainHasObj(context.TODO(), c)
}
func (a *apiBStore) Get(c cid.Cid) (blocks.Block, error) {
bb, err := a.api.ChainReadObj(context.TODO(), c)
if err != nil {
return nil, err
}
return blocks.NewBlockWithCid(bb, c)
}
func (a *apiBStore) GetSize(c cid.Cid) (int, error) {
bb, err := a.api.ChainReadObj(context.TODO(), c)
if err != nil {
return 0, err
}
return len(bb), nil
}
func (a *apiBStore) Put(blocks.Block) error {
return xerrors.New("not supported")
}
func (a *apiBStore) PutMany([]blocks.Block) error {
return xerrors.New("not supported")
}
func (a *apiBStore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) {
return nil, xerrors.New("not supported")
}
func (a *apiBStore) HashOnRead(enabled bool) {
return
}
var _ blockstore.Blockstore = &apiBStore{}
+139 -92
View File
@@ -32,6 +32,9 @@ type CommonStruct struct {
ID func(context.Context) (peer.ID, error) `perm:"read"`
Version func(context.Context) (api.Version, error) `perm:"read"`
LogList func(context.Context) ([]string, error) `perm:"write"`
LogSetLevel func(context.Context, string, string) error `perm:"write"`
}
}
@@ -40,34 +43,38 @@ type FullNodeStruct struct {
CommonStruct
Internal struct {
ChainNotify func(context.Context) (<-chan []*store.HeadChange, error) `perm:"read"`
ChainHead func(context.Context) (*types.TipSet, error) `perm:"read"`
ChainGetRandomness func(context.Context, types.TipSetKey, int64) ([]byte, error) `perm:"read"`
ChainGetBlock func(context.Context, cid.Cid) (*types.BlockHeader, error) `perm:"read"`
ChainGetTipSet func(context.Context, types.TipSetKey) (*types.TipSet, error) `perm:"read"`
ChainGetBlockMessages func(context.Context, cid.Cid) (*api.BlockMessages, error) `perm:"read"`
ChainGetParentReceipts func(context.Context, cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"`
ChainGetParentMessages func(context.Context, cid.Cid) ([]api.Message, error) `perm:"read"`
ChainGetTipSetByHeight func(context.Context, uint64, *types.TipSet) (*types.TipSet, error) `perm:"read"`
ChainReadObj func(context.Context, cid.Cid) ([]byte, error) `perm:"read"`
ChainSetHead func(context.Context, *types.TipSet) error `perm:"admin"`
ChainGetGenesis func(context.Context) (*types.TipSet, error) `perm:"read"`
ChainTipSetWeight func(context.Context, *types.TipSet) (types.BigInt, error) `perm:"read"`
ChainGetNode func(ctx context.Context, p string) (interface{}, error) `perm:"read"`
ChainGetMessage func(context.Context, cid.Cid) (*types.Message, error) `perm:"read"`
ChainNotify func(context.Context) (<-chan []*store.HeadChange, error) `perm:"read"`
ChainHead func(context.Context) (*types.TipSet, error) `perm:"read"`
ChainGetRandomness func(context.Context, types.TipSetKey, int64) ([]byte, error) `perm:"read"`
ChainGetBlock func(context.Context, cid.Cid) (*types.BlockHeader, error) `perm:"read"`
ChainGetTipSet func(context.Context, types.TipSetKey) (*types.TipSet, error) `perm:"read"`
ChainGetBlockMessages func(context.Context, cid.Cid) (*api.BlockMessages, error) `perm:"read"`
ChainGetParentReceipts func(context.Context, cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"`
ChainGetParentMessages func(context.Context, cid.Cid) ([]api.Message, error) `perm:"read"`
ChainGetTipSetByHeight func(context.Context, uint64, types.TipSetKey) (*types.TipSet, error) `perm:"read"`
ChainReadObj func(context.Context, cid.Cid) ([]byte, error) `perm:"read"`
ChainHasObj func(context.Context, cid.Cid) (bool, error) `perm:"read"`
ChainSetHead func(context.Context, types.TipSetKey) error `perm:"admin"`
ChainGetGenesis func(context.Context) (*types.TipSet, error) `perm:"read"`
ChainTipSetWeight func(context.Context, types.TipSetKey) (types.BigInt, error) `perm:"read"`
ChainGetNode func(ctx context.Context, p string) (interface{}, error) `perm:"read"`
ChainGetMessage func(context.Context, cid.Cid) (*types.Message, error) `perm:"read"`
ChainGetPath func(context.Context, types.TipSetKey, types.TipSetKey) ([]*store.HeadChange, error) `perm:"read"`
ChainExport func(context.Context, types.TipSetKey) (<-chan []byte, error) `perm:"read"`
SyncState func(context.Context) (*api.SyncState, error) `perm:"read"`
SyncSubmitBlock func(ctx context.Context, blk *types.BlockMsg) error `perm:"write"`
SyncIncomingBlocks func(ctx context.Context) (<-chan *types.BlockHeader, error) `perm:"read"`
SyncMarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"`
SyncCheckBad func(ctx context.Context, bcid cid.Cid) (string, error) `perm:"read"`
MpoolPending func(context.Context, *types.TipSet) ([]*types.SignedMessage, error) `perm:"read"`
MpoolPending func(context.Context, types.TipSetKey) ([]*types.SignedMessage, error) `perm:"read"`
MpoolPush func(context.Context, *types.SignedMessage) (cid.Cid, error) `perm:"write"`
MpoolPushMessage func(context.Context, *types.Message) (*types.SignedMessage, error) `perm:"sign"`
MpoolGetNonce func(context.Context, address.Address) (uint64, error) `perm:"read"`
MpoolSub func(context.Context) (<-chan api.MpoolUpdate, error) `perm:"read"`
MinerCreateBlock func(context.Context, address.Address, *types.TipSet, *types.Ticket, *types.EPostProof, []*types.SignedMessage, uint64, uint64) (*types.BlockMsg, error) `perm:"write"`
MinerCreateBlock func(context.Context, address.Address, types.TipSetKey, *types.Ticket, *types.EPostProof, []*types.SignedMessage, uint64, uint64) (*types.BlockMsg, error) `perm:"write"`
WalletNew func(context.Context, string) (address.Address, error) `perm:"write"`
WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"`
@@ -90,30 +97,34 @@ type FullNodeStruct struct {
ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, path string) error `perm:"admin"`
ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*types.SignedStorageAsk, error) `perm:"read"`
StateMinerSectors func(context.Context, address.Address, *types.TipSet) ([]*api.ChainSectorInfo, error) `perm:"read"`
StateMinerProvingSet func(context.Context, address.Address, *types.TipSet) ([]*api.ChainSectorInfo, error) `perm:"read"`
StateMinerPower func(context.Context, address.Address, *types.TipSet) (api.MinerPower, error) `perm:"read"`
StateMinerWorker func(context.Context, address.Address, *types.TipSet) (address.Address, error) `perm:"read"`
StateMinerPeerID func(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) `perm:"read"`
StateMinerElectionPeriodStart func(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) `perm:"read"`
StateMinerSectorSize func(context.Context, address.Address, *types.TipSet) (uint64, error) `perm:"read"`
StateCall func(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error) `perm:"read"`
StateReplay func(context.Context, *types.TipSet, cid.Cid) (*api.ReplayResults, error) `perm:"read"`
StateGetActor func(context.Context, address.Address, *types.TipSet) (*types.Actor, error) `perm:"read"`
StateReadState func(context.Context, *types.Actor, *types.TipSet) (*api.ActorState, error) `perm:"read"`
StatePledgeCollateral func(context.Context, *types.TipSet) (types.BigInt, error) `perm:"read"`
StateMinerSectors func(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"`
StateMinerProvingSet func(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"`
StateMinerPower func(context.Context, address.Address, types.TipSetKey) (api.MinerPower, error) `perm:"read"`
StateMinerWorker func(context.Context, address.Address, types.TipSetKey) (address.Address, error) `perm:"read"`
StateMinerPeerID func(ctx context.Context, m address.Address, tsk types.TipSetKey) (peer.ID, error) `perm:"read"`
StateMinerElectionPeriodStart func(ctx context.Context, actor address.Address, tsk types.TipSetKey) (uint64, error) `perm:"read"`
StateMinerSectorSize func(context.Context, address.Address, types.TipSetKey) (uint64, error) `perm:"read"`
StateMinerFaults func(context.Context, address.Address, types.TipSetKey) ([]uint64, error) `perm:"read"`
StateCall func(context.Context, *types.Message, types.TipSetKey) (*api.MethodCall, error) `perm:"read"`
StateReplay func(context.Context, types.TipSetKey, cid.Cid) (*api.ReplayResults, error) `perm:"read"`
StateGetActor func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) `perm:"read"`
StateReadState func(context.Context, *types.Actor, types.TipSetKey) (*api.ActorState, error) `perm:"read"`
StatePledgeCollateral func(context.Context, types.TipSetKey) (types.BigInt, error) `perm:"read"`
StateWaitMsg func(context.Context, cid.Cid) (*api.MsgWait, error) `perm:"read"`
StateListMiners func(context.Context, *types.TipSet) ([]address.Address, error) `perm:"read"`
StateListActors func(context.Context, *types.TipSet) ([]address.Address, error) `perm:"read"`
StateMarketBalance func(context.Context, address.Address, *types.TipSet) (actors.StorageParticipantBalance, error) `perm:"read"`
StateMarketParticipants func(context.Context, *types.TipSet) (map[string]actors.StorageParticipantBalance, error) `perm:"read"`
StateMarketDeals func(context.Context, *types.TipSet) (map[string]actors.OnChainDeal, error) `perm:"read"`
StateMarketStorageDeal func(context.Context, uint64, *types.TipSet) (*actors.OnChainDeal, error) `perm:"read"`
StateLookupID func(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) `perm:"read"`
StateListMiners func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
StateListActors func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
StateMarketBalance func(context.Context, address.Address, types.TipSetKey) (actors.StorageParticipantBalance, error) `perm:"read"`
StateMarketParticipants func(context.Context, types.TipSetKey) (map[string]actors.StorageParticipantBalance, error) `perm:"read"`
StateMarketDeals func(context.Context, types.TipSetKey) (map[string]actors.OnChainDeal, error) `perm:"read"`
StateMarketStorageDeal func(context.Context, uint64, types.TipSetKey) (*actors.OnChainDeal, error) `perm:"read"`
StateLookupID func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) `perm:"read"`
StateChangedActors func(context.Context, cid.Cid, cid.Cid) (map[string]types.Actor, error) `perm:"read"`
StateGetReceipt func(context.Context, cid.Cid, *types.TipSet) (*types.MessageReceipt, error) `perm:"read"`
StateMinerSectorCount func(context.Context, address.Address, *types.TipSet) (api.MinerSectors, error) `perm:"read"`
StateListMessages func(ctx context.Context, match *types.Message, ts *types.TipSet, toht uint64) ([]cid.Cid, error) `perm:"read"`
StateGetReceipt func(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error) `perm:"read"`
StateMinerSectorCount func(context.Context, address.Address, types.TipSetKey) (api.MinerSectors, error) `perm:"read"`
StateListMessages func(ctx context.Context, match *types.Message, tsk types.TipSetKey, toht uint64) ([]cid.Cid, error) `perm:"read"`
StateCompute func(context.Context, uint64, []*types.Message, types.TipSetKey) (cid.Cid, error) `perm:"read"`
MsigGetAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
MarketEnsureAvailable func(context.Context, address.Address, types.BigInt) error `perm:"sign"`
@@ -133,8 +144,8 @@ type FullNodeStruct struct {
}
}
func (c *FullNodeStruct) StateMinerSectorCount(ctx context.Context, addr address.Address, ts *types.TipSet) (api.MinerSectors, error) {
return c.Internal.StateMinerSectorCount(ctx, addr, ts)
func (c *FullNodeStruct) StateMinerSectorCount(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MinerSectors, error) {
return c.Internal.StateMinerSectorCount(ctx, addr, tsk)
}
type StorageMinerStruct struct {
@@ -196,6 +207,14 @@ func (c *CommonStruct) Version(ctx context.Context) (api.Version, error) {
return c.Internal.Version(ctx)
}
func (c *CommonStruct) LogList(ctx context.Context) ([]string, error) {
return c.Internal.LogList(ctx)
}
func (c *CommonStruct) LogSetLevel(ctx context.Context, group, level string) error {
return c.Internal.LogSetLevel(ctx, group, level)
}
func (c *FullNodeStruct) ClientListImports(ctx context.Context) ([]api.Import, error) {
return c.Internal.ClientListImports(ctx)
}
@@ -231,8 +250,8 @@ func (c *FullNodeStruct) ClientQueryAsk(ctx context.Context, p peer.ID, miner ad
return c.Internal.ClientQueryAsk(ctx, p, miner)
}
func (c *FullNodeStruct) MpoolPending(ctx context.Context, ts *types.TipSet) ([]*types.SignedMessage, error) {
return c.Internal.MpoolPending(ctx, ts)
func (c *FullNodeStruct) MpoolPending(ctx context.Context, tsk types.TipSetKey) ([]*types.SignedMessage, error) {
return c.Internal.MpoolPending(ctx, tsk)
}
func (c *FullNodeStruct) MpoolPush(ctx context.Context, smsg *types.SignedMessage) (cid.Cid, error) {
@@ -247,7 +266,7 @@ func (c *FullNodeStruct) MpoolSub(ctx context.Context) (<-chan api.MpoolUpdate,
return c.Internal.MpoolSub(ctx)
}
func (c *FullNodeStruct) MinerCreateBlock(ctx context.Context, addr address.Address, base *types.TipSet, ticket *types.Ticket, eproof *types.EPostProof, msgs []*types.SignedMessage, height, ts uint64) (*types.BlockMsg, error) {
func (c *FullNodeStruct) MinerCreateBlock(ctx context.Context, addr address.Address, base types.TipSetKey, ticket *types.Ticket, eproof *types.EPostProof, msgs []*types.SignedMessage, height, ts uint64) (*types.BlockMsg, error) {
return c.Internal.MinerCreateBlock(ctx, addr, base, ticket, eproof, msgs, height, ts)
}
@@ -259,8 +278,8 @@ func (c *FullNodeStruct) ChainGetRandomness(ctx context.Context, pts types.TipSe
return c.Internal.ChainGetRandomness(ctx, pts, round)
}
func (c *FullNodeStruct) ChainGetTipSetByHeight(ctx context.Context, h uint64, ts *types.TipSet) (*types.TipSet, error) {
return c.Internal.ChainGetTipSetByHeight(ctx, h, ts)
func (c *FullNodeStruct) ChainGetTipSetByHeight(ctx context.Context, h uint64, tsk types.TipSetKey) (*types.TipSet, error) {
return c.Internal.ChainGetTipSetByHeight(ctx, h, tsk)
}
func (c *FullNodeStruct) WalletNew(ctx context.Context, typ string) (address.Address, error) {
@@ -335,16 +354,20 @@ func (c *FullNodeStruct) ChainReadObj(ctx context.Context, obj cid.Cid) ([]byte,
return c.Internal.ChainReadObj(ctx, obj)
}
func (c *FullNodeStruct) ChainSetHead(ctx context.Context, ts *types.TipSet) error {
return c.Internal.ChainSetHead(ctx, ts)
func (c *FullNodeStruct) ChainHasObj(ctx context.Context, o cid.Cid) (bool, error) {
return c.Internal.ChainHasObj(ctx, o)
}
func (c *FullNodeStruct) ChainSetHead(ctx context.Context, tsk types.TipSetKey) error {
return c.Internal.ChainSetHead(ctx, tsk)
}
func (c *FullNodeStruct) ChainGetGenesis(ctx context.Context) (*types.TipSet, error) {
return c.Internal.ChainGetGenesis(ctx)
}
func (c *FullNodeStruct) ChainTipSetWeight(ctx context.Context, ts *types.TipSet) (types.BigInt, error) {
return c.Internal.ChainTipSetWeight(ctx, ts)
func (c *FullNodeStruct) ChainTipSetWeight(ctx context.Context, tsk types.TipSetKey) (types.BigInt, error) {
return c.Internal.ChainTipSetWeight(ctx, tsk)
}
func (c *FullNodeStruct) ChainGetNode(ctx context.Context, p string) (interface{}, error) {
@@ -355,6 +378,14 @@ func (c *FullNodeStruct) ChainGetMessage(ctx context.Context, mc cid.Cid) (*type
return c.Internal.ChainGetMessage(ctx, mc)
}
func (c *FullNodeStruct) ChainGetPath(ctx context.Context, from types.TipSetKey, to types.TipSetKey) ([]*store.HeadChange, error) {
return c.Internal.ChainGetPath(ctx, from, to)
}
func (c *FullNodeStruct) ChainExport(ctx context.Context, tsk types.TipSetKey) (<-chan []byte, error) {
return c.Internal.ChainExport(ctx, tsk)
}
func (c *FullNodeStruct) SyncState(ctx context.Context) (*api.SyncState, error) {
return c.Internal.SyncState(ctx)
}
@@ -371,95 +402,111 @@ func (c *FullNodeStruct) SyncMarkBad(ctx context.Context, bcid cid.Cid) error {
return c.Internal.SyncMarkBad(ctx, bcid)
}
func (c *FullNodeStruct) StateMinerSectors(ctx context.Context, addr address.Address, ts *types.TipSet) ([]*api.ChainSectorInfo, error) {
return c.Internal.StateMinerSectors(ctx, addr, ts)
func (c *FullNodeStruct) SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error) {
return c.Internal.SyncCheckBad(ctx, bcid)
}
func (c *FullNodeStruct) StateMinerProvingSet(ctx context.Context, addr address.Address, ts *types.TipSet) ([]*api.ChainSectorInfo, error) {
return c.Internal.StateMinerProvingSet(ctx, addr, ts)
func (c *FullNodeStruct) StateMinerSectors(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) {
return c.Internal.StateMinerSectors(ctx, addr, tsk)
}
func (c *FullNodeStruct) StateMinerPower(ctx context.Context, a address.Address, ts *types.TipSet) (api.MinerPower, error) {
return c.Internal.StateMinerPower(ctx, a, ts)
func (c *FullNodeStruct) StateMinerProvingSet(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) {
return c.Internal.StateMinerProvingSet(ctx, addr, tsk)
}
func (c *FullNodeStruct) StateMinerWorker(ctx context.Context, m address.Address, ts *types.TipSet) (address.Address, error) {
return c.Internal.StateMinerWorker(ctx, m, ts)
func (c *FullNodeStruct) StateMinerPower(ctx context.Context, a address.Address, tsk types.TipSetKey) (api.MinerPower, error) {
return c.Internal.StateMinerPower(ctx, a, tsk)
}
func (c *FullNodeStruct) StateMinerPeerID(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) {
return c.Internal.StateMinerPeerID(ctx, m, ts)
func (c *FullNodeStruct) StateMinerWorker(ctx context.Context, m address.Address, tsk types.TipSetKey) (address.Address, error) {
return c.Internal.StateMinerWorker(ctx, m, tsk)
}
func (c *FullNodeStruct) StateMinerElectionPeriodStart(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) {
return c.Internal.StateMinerElectionPeriodStart(ctx, actor, ts)
func (c *FullNodeStruct) StateMinerPeerID(ctx context.Context, m address.Address, tsk types.TipSetKey) (peer.ID, error) {
return c.Internal.StateMinerPeerID(ctx, m, tsk)
}
func (c *FullNodeStruct) StateMinerSectorSize(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) {
return c.Internal.StateMinerSectorSize(ctx, actor, ts)
func (c *FullNodeStruct) StateMinerElectionPeriodStart(ctx context.Context, actor address.Address, tsk types.TipSetKey) (uint64, error) {
return c.Internal.StateMinerElectionPeriodStart(ctx, actor, tsk)
}
func (c *FullNodeStruct) StateCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) {
return c.Internal.StateCall(ctx, msg, ts)
func (c *FullNodeStruct) StateMinerSectorSize(ctx context.Context, actor address.Address, tsk types.TipSetKey) (uint64, error) {
return c.Internal.StateMinerSectorSize(ctx, actor, tsk)
}
func (c *FullNodeStruct) StateReplay(ctx context.Context, ts *types.TipSet, mc cid.Cid) (*api.ReplayResults, error) {
return c.Internal.StateReplay(ctx, ts, mc)
func (c *FullNodeStruct) StateMinerFaults(ctx context.Context, actor address.Address, tsk types.TipSetKey) ([]uint64, error) {
return c.Internal.StateMinerFaults(ctx, actor, tsk)
}
func (c *FullNodeStruct) StateGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error) {
return c.Internal.StateGetActor(ctx, actor, ts)
func (c *FullNodeStruct) StateCall(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (*api.MethodCall, error) {
return c.Internal.StateCall(ctx, msg, tsk)
}
func (c *FullNodeStruct) StateReadState(ctx context.Context, act *types.Actor, ts *types.TipSet) (*api.ActorState, error) {
return c.Internal.StateReadState(ctx, act, ts)
func (c *FullNodeStruct) StateReplay(ctx context.Context, tsk types.TipSetKey, mc cid.Cid) (*api.ReplayResults, error) {
return c.Internal.StateReplay(ctx, tsk, mc)
}
func (c *FullNodeStruct) StatePledgeCollateral(ctx context.Context, ts *types.TipSet) (types.BigInt, error) {
return c.Internal.StatePledgeCollateral(ctx, ts)
func (c *FullNodeStruct) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) {
return c.Internal.StateGetActor(ctx, actor, tsk)
}
func (c *FullNodeStruct) StateReadState(ctx context.Context, act *types.Actor, tsk types.TipSetKey) (*api.ActorState, error) {
return c.Internal.StateReadState(ctx, act, tsk)
}
func (c *FullNodeStruct) StatePledgeCollateral(ctx context.Context, tsk types.TipSetKey) (types.BigInt, error) {
return c.Internal.StatePledgeCollateral(ctx, tsk)
}
func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid) (*api.MsgWait, error) {
return c.Internal.StateWaitMsg(ctx, msgc)
}
func (c *FullNodeStruct) StateListMiners(ctx context.Context, ts *types.TipSet) ([]address.Address, error) {
return c.Internal.StateListMiners(ctx, ts)
func (c *FullNodeStruct) StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) {
return c.Internal.StateListMiners(ctx, tsk)
}
func (c *FullNodeStruct) StateListActors(ctx context.Context, ts *types.TipSet) ([]address.Address, error) {
return c.Internal.StateListActors(ctx, ts)
func (c *FullNodeStruct) StateListActors(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) {
return c.Internal.StateListActors(ctx, tsk)
}
func (c *FullNodeStruct) StateMarketBalance(ctx context.Context, addr address.Address, ts *types.TipSet) (actors.StorageParticipantBalance, error) {
return c.Internal.StateMarketBalance(ctx, addr, ts)
func (c *FullNodeStruct) StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (actors.StorageParticipantBalance, error) {
return c.Internal.StateMarketBalance(ctx, addr, tsk)
}
func (c *FullNodeStruct) StateMarketParticipants(ctx context.Context, ts *types.TipSet) (map[string]actors.StorageParticipantBalance, error) {
return c.Internal.StateMarketParticipants(ctx, ts)
func (c *FullNodeStruct) StateMarketParticipants(ctx context.Context, tsk types.TipSetKey) (map[string]actors.StorageParticipantBalance, error) {
return c.Internal.StateMarketParticipants(ctx, tsk)
}
func (c *FullNodeStruct) StateMarketDeals(ctx context.Context, ts *types.TipSet) (map[string]actors.OnChainDeal, error) {
return c.Internal.StateMarketDeals(ctx, ts)
func (c *FullNodeStruct) StateMarketDeals(ctx context.Context, tsk types.TipSetKey) (map[string]actors.OnChainDeal, error) {
return c.Internal.StateMarketDeals(ctx, tsk)
}
func (c *FullNodeStruct) StateMarketStorageDeal(ctx context.Context, dealid uint64, ts *types.TipSet) (*actors.OnChainDeal, error) {
return c.Internal.StateMarketStorageDeal(ctx, dealid, ts)
func (c *FullNodeStruct) StateMarketStorageDeal(ctx context.Context, dealid uint64, tsk types.TipSetKey) (*actors.OnChainDeal, error) {
return c.Internal.StateMarketStorageDeal(ctx, dealid, tsk)
}
func (c *FullNodeStruct) StateLookupID(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
return c.Internal.StateLookupID(ctx, addr, ts)
func (c *FullNodeStruct) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
return c.Internal.StateLookupID(ctx, addr, tsk)
}
func (c *FullNodeStruct) StateChangedActors(ctx context.Context, olnstate cid.Cid, newstate cid.Cid) (map[string]types.Actor, error) {
return c.Internal.StateChangedActors(ctx, olnstate, newstate)
}
func (c *FullNodeStruct) StateGetReceipt(ctx context.Context, msg cid.Cid, ts *types.TipSet) (*types.MessageReceipt, error) {
return c.Internal.StateGetReceipt(ctx, msg, ts)
func (c *FullNodeStruct) StateGetReceipt(ctx context.Context, msg cid.Cid, tsk types.TipSetKey) (*types.MessageReceipt, error) {
return c.Internal.StateGetReceipt(ctx, msg, tsk)
}
func (c *FullNodeStruct) StateListMessages(ctx context.Context, match *types.Message, ts *types.TipSet, toht uint64) ([]cid.Cid, error) {
return c.Internal.StateListMessages(ctx, match, ts, toht)
func (c *FullNodeStruct) StateListMessages(ctx context.Context, match *types.Message, tsk types.TipSetKey, toht uint64) ([]cid.Cid, error) {
return c.Internal.StateListMessages(ctx, match, tsk, toht)
}
func (c *FullNodeStruct) StateCompute(ctx context.Context, height uint64, msgs []*types.Message, tsk types.TipSetKey) (cid.Cid, error) {
return c.Internal.StateCompute(ctx, height, msgs, tsk)
}
func (c *FullNodeStruct) MsigGetAvailableBalance(ctx context.Context, a address.Address, tsk types.TipSetKey) (types.BigInt, error) {
return c.Internal.MsigGetAvailableBalance(ctx, a, tsk)
}
func (c *FullNodeStruct) MarketEnsureAvailable(ctx context.Context, addr address.Address, amt types.BigInt) error {
+191 -186
View File
@@ -23,6 +23,10 @@ func (t *PaymentInfo) MarshalCBOR(w io.Writer) error {
}
// t.Channel (address.Address) (struct)
if len("Channel") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"Channel\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("Channel")))); err != nil {
return err
}
@@ -35,6 +39,10 @@ func (t *PaymentInfo) MarshalCBOR(w io.Writer) error {
}
// t.ChannelMessage (cid.Cid) (struct)
if len("ChannelMessage") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"ChannelMessage\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("ChannelMessage")))); err != nil {
return err
}
@@ -53,6 +61,10 @@ func (t *PaymentInfo) MarshalCBOR(w io.Writer) error {
}
// t.Vouchers ([]*types.SignedVoucher) (slice)
if len("Vouchers") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"Vouchers\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("Vouchers")))); err != nil {
return err
}
@@ -60,6 +72,10 @@ func (t *PaymentInfo) MarshalCBOR(w io.Writer) error {
return err
}
if len(t.Vouchers) > cbg.MaxLength {
return xerrors.Errorf("Slice value in field t.Vouchers was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Vouchers)))); err != nil {
return err
}
@@ -82,114 +98,95 @@ func (t *PaymentInfo) UnmarshalCBOR(r io.Reader) error {
return fmt.Errorf("cbor input should be of type map")
}
if extra != 3 {
return fmt.Errorf("cbor input had wrong number of fields")
if extra > cbg.MaxLength {
return fmt.Errorf("PaymentInfo: map struct too large (%d)", extra)
}
var name string
n := extra
// t.Channel (address.Address) (struct)
for i := uint64(0); i < n; i++ {
{
sval, err := cbg.ReadString(br)
if err != nil {
return err
}
name = string(sval)
}
if name != "Channel" {
return fmt.Errorf("expected struct map entry %s to be Channel", name)
}
{
if err := t.Channel.UnmarshalCBOR(br); err != nil {
return err
}
}
// t.ChannelMessage (cid.Cid) (struct)
{
sval, err := cbg.ReadString(br)
if err != nil {
return err
}
name = string(sval)
}
if name != "ChannelMessage" {
return fmt.Errorf("expected struct map entry %s to be ChannelMessage", name)
}
{
pb, err := br.PeekByte()
if err != nil {
return err
}
if pb == cbg.CborNull[0] {
var nbuf [1]byte
if _, err := br.Read(nbuf[:]); err != nil {
{
sval, err := cbg.ReadString(br)
if err != nil {
return err
}
} else {
c, err := cbg.ReadCid(br)
name = string(sval)
}
switch name {
// t.Channel (address.Address) (struct)
case "Channel":
{
if err := t.Channel.UnmarshalCBOR(br); err != nil {
return err
}
}
// t.ChannelMessage (cid.Cid) (struct)
case "ChannelMessage":
{
pb, err := br.PeekByte()
if err != nil {
return err
}
if pb == cbg.CborNull[0] {
var nbuf [1]byte
if _, err := br.Read(nbuf[:]); err != nil {
return err
}
} else {
c, err := cbg.ReadCid(br)
if err != nil {
return xerrors.Errorf("failed to read cid field t.ChannelMessage: %w", err)
}
t.ChannelMessage = &c
}
}
// t.Vouchers ([]*types.SignedVoucher) (slice)
case "Vouchers":
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return xerrors.Errorf("failed to read cid field t.ChannelMessage: %w", err)
return err
}
t.ChannelMessage = &c
if extra > cbg.MaxLength {
return fmt.Errorf("t.Vouchers: array too large (%d)", extra)
}
if maj != cbg.MajArray {
return fmt.Errorf("expected cbor array")
}
if extra > 0 {
t.Vouchers = make([]*types.SignedVoucher, extra)
}
for i := 0; i < int(extra); i++ {
var v types.SignedVoucher
if err := v.UnmarshalCBOR(br); err != nil {
return err
}
t.Vouchers[i] = &v
}
default:
return fmt.Errorf("unknown struct field %d: '%s'", i, name)
}
}
// t.Vouchers ([]*types.SignedVoucher) (slice)
{
sval, err := cbg.ReadString(br)
if err != nil {
return err
}
name = string(sval)
}
if name != "Vouchers" {
return fmt.Errorf("expected struct map entry %s to be Vouchers", name)
}
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if extra > cbg.MaxLength {
return fmt.Errorf("t.Vouchers: array too large (%d)", extra)
}
if maj != cbg.MajArray {
return fmt.Errorf("expected cbor array")
}
if extra > 0 {
t.Vouchers = make([]*types.SignedVoucher, extra)
}
for i := 0; i < int(extra); i++ {
var v types.SignedVoucher
if err := v.UnmarshalCBOR(br); err != nil {
return err
}
t.Vouchers[i] = &v
}
return nil
}
func (t *SealedRef) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
@@ -200,6 +197,10 @@ func (t *SealedRef) MarshalCBOR(w io.Writer) error {
}
// t.SectorID (uint64) (uint64)
if len("SectorID") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"SectorID\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("SectorID")))); err != nil {
return err
}
@@ -212,6 +213,10 @@ func (t *SealedRef) MarshalCBOR(w io.Writer) error {
}
// t.Offset (uint64) (uint64)
if len("Offset") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"Offset\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("Offset")))); err != nil {
return err
}
@@ -224,6 +229,10 @@ func (t *SealedRef) MarshalCBOR(w io.Writer) error {
}
// t.Size (uint64) (uint64)
if len("Size") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"Size\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("Size")))); err != nil {
return err
}
@@ -248,84 +257,66 @@ func (t *SealedRef) UnmarshalCBOR(r io.Reader) error {
return fmt.Errorf("cbor input should be of type map")
}
if extra != 3 {
return fmt.Errorf("cbor input had wrong number of fields")
if extra > cbg.MaxLength {
return fmt.Errorf("SealedRef: map struct too large (%d)", extra)
}
var name string
n := extra
// t.SectorID (uint64) (uint64)
for i := uint64(0); i < n; i++ {
{
sval, err := cbg.ReadString(br)
if err != nil {
return err
{
sval, err := cbg.ReadString(br)
if err != nil {
return err
}
name = string(sval)
}
name = string(sval)
}
switch name {
// t.SectorID (uint64) (uint64)
case "SectorID":
if name != "SectorID" {
return fmt.Errorf("expected struct map entry %s to be SectorID", name)
}
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.SectorID = uint64(extra)
// t.Offset (uint64) (uint64)
case "Offset":
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.SectorID = uint64(extra)
// t.Offset (uint64) (uint64)
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.Offset = uint64(extra)
// t.Size (uint64) (uint64)
case "Size":
{
sval, err := cbg.ReadString(br)
if err != nil {
return err
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.Size = uint64(extra)
default:
return fmt.Errorf("unknown struct field %d: '%s'", i, name)
}
name = string(sval)
}
if name != "Offset" {
return fmt.Errorf("expected struct map entry %s to be Offset", name)
}
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.Offset = uint64(extra)
// t.Size (uint64) (uint64)
{
sval, err := cbg.ReadString(br)
if err != nil {
return err
}
name = string(sval)
}
if name != "Size" {
return fmt.Errorf("expected struct map entry %s to be Size", name)
}
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.Size = uint64(extra)
return nil
}
func (t *SealedRefs) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
@@ -336,6 +327,10 @@ func (t *SealedRefs) MarshalCBOR(w io.Writer) error {
}
// t.Refs ([]api.SealedRef) (slice)
if len("Refs") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"Refs\" was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len("Refs")))); err != nil {
return err
}
@@ -343,6 +338,10 @@ func (t *SealedRefs) MarshalCBOR(w io.Writer) error {
return err
}
if len(t.Refs) > cbg.MaxLength {
return xerrors.Errorf("Slice value in field t.Refs was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Refs)))); err != nil {
return err
}
@@ -365,50 +364,56 @@ func (t *SealedRefs) UnmarshalCBOR(r io.Reader) error {
return fmt.Errorf("cbor input should be of type map")
}
if extra != 1 {
return fmt.Errorf("cbor input had wrong number of fields")
if extra > cbg.MaxLength {
return fmt.Errorf("SealedRefs: map struct too large (%d)", extra)
}
var name string
n := extra
// t.Refs ([]api.SealedRef) (slice)
for i := uint64(0); i < n; i++ {
{
sval, err := cbg.ReadString(br)
if err != nil {
return err
{
sval, err := cbg.ReadString(br)
if err != nil {
return err
}
name = string(sval)
}
name = string(sval)
}
switch name {
// t.Refs ([]api.SealedRef) (slice)
case "Refs":
if name != "Refs" {
return fmt.Errorf("expected struct map entry %s to be Refs", name)
}
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if extra > cbg.MaxLength {
return fmt.Errorf("t.Refs: array too large (%d)", extra)
}
if extra > cbg.MaxLength {
return fmt.Errorf("t.Refs: array too large (%d)", extra)
}
if maj != cbg.MajArray {
return fmt.Errorf("expected cbor array")
}
if extra > 0 {
t.Refs = make([]SealedRef, extra)
}
for i := 0; i < int(extra); i++ {
if maj != cbg.MajArray {
return fmt.Errorf("expected cbor array")
}
if extra > 0 {
t.Refs = make([]SealedRef, extra)
}
for i := 0; i < int(extra); i++ {
var v SealedRef
if err := v.UnmarshalCBOR(br); err != nil {
return err
}
var v SealedRef
if err := v.UnmarshalCBOR(br); err != nil {
return err
t.Refs[i] = v
}
default:
return fmt.Errorf("unknown struct field %d: '%s'", i, name)
}
t.Refs[i] = v
}
return nil
+3 -4
View File
@@ -11,7 +11,7 @@ import (
"testing"
"time"
logging "github.com/ipfs/go-log"
logging "github.com/ipfs/go-log/v2"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
@@ -24,7 +24,7 @@ func init() {
build.InsecurePoStValidation = true
}
func TestDealFlow(t *testing.T, b APIBuilder) {
func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
os.Setenv("BELLMAN_NO_GPU", "1")
ctx := context.Background()
@@ -64,8 +64,7 @@ func TestDealFlow(t *testing.T, b APIBuilder) {
go func() {
defer close(done)
for mine {
time.Sleep(time.Second)
fmt.Println("mining a block now")
time.Sleep(blocktime)
if err := sn[0].MineOne(ctx); err != nil {
t.Error(err)
}
+6 -6
View File
@@ -1,6 +1,6 @@
/dns4/lotus-bootstrap-0.dfw.fil-test.net/tcp/1347/p2p/12D3KooWHwGBSiLR5ts7KW9MgH4BMzC2iXe18kwAQ8Ee3LUd1jeR
/dns4/lotus-bootstrap-1.dfw.fil-test.net/tcp/1347/p2p/12D3KooWCLFaawdhLGcSpiqg43DtZ9QzPQ6HcB8Vvyu2Cnta8UWc
/dns4/lotus-bootstrap-0.fra.fil-test.net/tcp/1347/p2p/12D3KooWMmaL7eaUCF6tVAghVmgozxz4uztbuFUQv6dyFpHRarHR
/dns4/lotus-bootstrap-1.fra.fil-test.net/tcp/1347/p2p/12D3KooWLLpNYoKdf9NgcWudBhXLdTcXncqAsTzozw1scMMu6nS5
/dns4/lotus-bootstrap-0.sin.fil-test.net/tcp/1347/p2p/12D3KooWCNL9vXaXwNs3Bu8uRAJK4pxpCyPeM7jZLSDpJma1wrV8
/dns4/lotus-bootstrap-1.sin.fil-test.net/tcp/1347/p2p/12D3KooWNGGxFda1eC5U2YKAgs4ypoFHn3Z3xHCsjmFdrCcytoxm
/dns4/lotus-bootstrap-0.sin.fil-test.net/tcp/1347/p2p/12D3KooWLZs8BWtEzRTYET4yR4jzDtPamaA1YsyPQJq6cf2RfxBD
/dns4/lotus-bootstrap-1.sin.fil-test.net/tcp/1347/p2p/12D3KooWGvrgjWw4Yqo4AFWqYp4g37FpUvUCQBkNWudZVSwR9tY1
/dns4/lotus-bootstrap-0.fra.fil-test.net/tcp/1347/p2p/12D3KooWSfNcrD1cs5Cj5eSHbK6nHCqJLffAuPqvRMBRgvUdqQhX
/dns4/lotus-bootstrap-1.fra.fil-test.net/tcp/1347/p2p/12D3KooWNkXyVPspUnrHUiSC3VJPMcXvHuNdy3BTCLTPPnDgwwTT
/dns4/lotus-bootstrap-0.dfw.fil-test.net/tcp/1347/p2p/12D3KooWSgJWJZK8LTRtCWzPa5FQheCFJjHpficVYgEQWeimcqCu
/dns4/lotus-bootstrap-1.dfw.fil-test.net/tcp/1347/p2p/12D3KooWFPaC4dyGpbNXCpVHjZucdJnDwmv4ng9tponPx5GrzJkT
+7 -2
View File
@@ -1,4 +1,9 @@
package build
const ForkCCM = 1750
const ForkNoPowerEPSUpdates = 16450
const ForkBlizzardHeight = 6288
const ForkFrigidHeight = 7950
const ForkBootyBayHeight = 11000
const ForkMissingSnowballs = 34000
+3 -3
View File
@@ -2,7 +2,7 @@ package build
import (
rice "github.com/GeertJohan/go.rice"
logging "github.com/ipfs/go-log"
logging "github.com/ipfs/go-log/v2"
)
// moved from now-defunct build/paramfetch.go
@@ -11,12 +11,12 @@ var log = logging.Logger("build")
func MaybeGenesis() []byte {
builtinGen, err := rice.FindBox("genesis")
if err != nil {
log.Warn("loading built-in genesis: %s", err)
log.Warnf("loading built-in genesis: %s", err)
return nil
}
genBytes, err := builtinGen.Bytes("devnet.car")
if err != nil {
log.Warn("loading built-in genesis: %s", err)
log.Warnf("loading built-in genesis: %s", err)
}
return genBytes
Binary file not shown.
+7
View File
@@ -0,0 +1,7 @@
package build
import rice "github.com/GeertJohan/go.rice"
func ParametersJson() []byte {
return rice.MustFindBox("proof-params").MustBytes("parameters.json")
}
+3 -5
View File
@@ -2,7 +2,9 @@
package build
import "os"
func init() {
InsecurePoStValidation = true
}
var SectorSizes = []uint64{1024}
@@ -31,7 +33,3 @@ const InteractivePoRepConfidence = 6
// Bytes
var MinimumMinerPower uint64 = 2 << 10 // 2KiB
func init() {
os.Setenv("TRUST_PARAMS", "1")
}
+11
View File
@@ -21,6 +21,8 @@ func SupportedSectorSize(ssize uint64) bool {
return false
}
const SectorChallengeRatioDiv = 25
// /////
// Payments
@@ -56,6 +58,9 @@ const SealRandomnessLookback = Finality
// Epochs
const SealRandomnessLookbackLimit = SealRandomnessLookback + 2000
// Maximum lookback that randomness can be sourced from for a seal proof submission
const MaxSealLookback = SealRandomnessLookbackLimit + 2000
// /////
// Mining
@@ -97,3 +102,9 @@ const BadBlockCacheSize = 1 << 15
// assuming 4000 messages per round, this lets us not lose any messages across a
// 10 block reorg.
const BlsSignatureCacheSize = 40000
// ///////
// Limits
const BlockMessageLimit = 512
const MinerMaxSectors = 1 << 48
-1
View File
@@ -3,7 +3,6 @@
package build
var SectorSizes = []uint64{
1 << 30,
32 << 30,
}
+103
View File
@@ -0,0 +1,103 @@
{
"v20-proof-of-spacetime-election-5f585aca354eb68e411c8582ed0efd800792430e4e76d73468c4fc03f1a8d6d2.params": {
"cid": "QmX7tYeNPWae2fjZ3Am6GB9dmHvLqvoz8dKo3PR98VYxH9",
"digest": "39a9edec3355516674f0d12b926be493",
"sector_size": 34359738368
},
"v20-proof-of-spacetime-election-5f585aca354eb68e411c8582ed0efd800792430e4e76d73468c4fc03f1a8d6d2.vk": {
"cid": "QmbNGx7pNbGiEr8ykoHxVXHW2LNSmGdsxKtj1onZCyguCX",
"digest": "0227ae7df4f2affe529ebafbbc7540ee",
"sector_size": 34359738368
},
"v20-proof-of-spacetime-election-a4e18190d4b4657ba1b4d08a341871b2a6f398e327cb9951b28ab141fbdbf49d.params": {
"cid": "QmRGZsNp4mp1cZshcXqt3VMuWscAEsiMa2iepF4CsWWoiv",
"digest": "991041a354b12c280542741f58c7f2ca",
"sector_size": 1024
},
"v20-proof-of-spacetime-election-a4e18190d4b4657ba1b4d08a341871b2a6f398e327cb9951b28ab141fbdbf49d.vk": {
"cid": "QmWpmrhCGVcfqLyqp5oGAnhPmCE5hGTPaauHi25mpQwRSU",
"digest": "91fac550e1f9bccab213830bb0c85bd6",
"sector_size": 1024
},
"v20-proof-of-spacetime-election-a9eb6d90b896a282ec2d3a875c6143e3fcff778f0da1460709e051833651559b.params": {
"cid": "QmenSZXh1EsSyHiSRvA6wb8yaPhYBTjrKehJw96Px5HnN4",
"digest": "6322eacd2773163ddd51f9ca7d645fc4",
"sector_size": 1073741824
},
"v20-proof-of-spacetime-election-a9eb6d90b896a282ec2d3a875c6143e3fcff778f0da1460709e051833651559b.vk": {
"cid": "QmPvZoMKofw6eDhDg5ESJA2QAZP8HvM6qMQk7fw4pq9bQf",
"digest": "0df62745fceac922e3e70847cfc70b52",
"sector_size": 1073741824
},
"v20-proof-of-spacetime-election-bf872523641b1de33553db2a177df13e412d7b3b0103e6696ae0a1cf5d525259.params": {
"cid": "QmVibFqzkZoL8cwQmzj8njPokCQGCCx4pBcUH77bzgJgV9",
"digest": "de9d71e672f286706a1673bd57abdaac",
"sector_size": 16777216
},
"v20-proof-of-spacetime-election-bf872523641b1de33553db2a177df13e412d7b3b0103e6696ae0a1cf5d525259.vk": {
"cid": "QmZa5FX27XyiEXQQLQpHqtMJKLzrcY8wMuj3pxzmSimSyu",
"digest": "7f796d3a0f13499181e44b5eee0cc744",
"sector_size": 16777216
},
"v20-proof-of-spacetime-election-ffc3fb192364238b60977839d14e3154d4a98313e30d46694a12af54b6874975.params": {
"cid": "Qmbt2SWWAmMcYoY3DAiRDXA8fAuqdqRLWucJMSxYmzBCmN",
"digest": "151ae0ae183fc141e8c2bebc28e5cc10",
"sector_size": 268435456
},
"v20-proof-of-spacetime-election-ffc3fb192364238b60977839d14e3154d4a98313e30d46694a12af54b6874975.vk": {
"cid": "QmUxvPu4xdVmjMFihUKoYyEdXBqxsXkvmxRweU7KouWHji",
"digest": "95eb89588e9d1832aca044c3a13178af",
"sector_size": 268435456
},
"v20-stacked-proof-of-replication-117839dacd1ef31e5968a6fd13bcd6fa86638d85c40c9241a1d07c2a954eb89b.params": {
"cid": "QmQZe8eLo2xXbhSDxtyYZNqEjqjdcWGdADywECRvNEZQdX",
"digest": "fcd50e2e08a8560a6bb3418e883567ed",
"sector_size": 268435456
},
"v20-stacked-proof-of-replication-117839dacd1ef31e5968a6fd13bcd6fa86638d85c40c9241a1d07c2a954eb89b.vk": {
"cid": "Qme1hn6QT1covfoUFGDZkqoE1pMTax9FNW3nWWmTNqFe7y",
"digest": "872e244d86499fd659082e3bcf3f13e7",
"sector_size": 268435456
},
"v20-stacked-proof-of-replication-b46f3a1051afbb67f70aae7082da95def62eee943662f3e1bf69837fb08aaae4.params": {
"cid": "QmSfrPDC9jwY4MKrjzhCqDBBAG44wSDM8oE5NuDwWSh2xN",
"digest": "0a338b941c5f17946340de5fc95cab30",
"sector_size": 34359738368
},
"v20-stacked-proof-of-replication-b46f3a1051afbb67f70aae7082da95def62eee943662f3e1bf69837fb08aaae4.vk": {
"cid": "QmTDGynCmnbaZNBP3Bv3F3duC3ecKRubCKeMUiQQZYbGpF",
"digest": "c752e070a6b7aa8b79aa661a6b600b55",
"sector_size": 34359738368
},
"v20-stacked-proof-of-replication-e71093863cadc71de61f38311ee45816633973bbf34849316b147f8d2e66f199.params": {
"cid": "QmXjSSnMUnc7EjQBYtTHhvLU3kXJTbUyhVhJRSTRehh186",
"digest": "efa407fd09202dffd15799a8518e73d3",
"sector_size": 1024
},
"v20-stacked-proof-of-replication-e71093863cadc71de61f38311ee45816633973bbf34849316b147f8d2e66f199.vk": {
"cid": "QmYHW3zhQouDP4okFbXSsRMcZ8bokKGvzxqbv7ZrunPMiG",
"digest": "b2f09a0ccb62da28c890d5b881c8dcd2",
"sector_size": 1024
},
"v20-stacked-proof-of-replication-e99a585174b6a45b254ba4780d72c89ad808c305c6d11711009ade4f39dba8e9.params": {
"cid": "QmUhyfNeLb32LfSkjsUwTFYLXQGMj6JQ8daff4DdVMt79q",
"digest": "b53c1916a63839ec345aa2224e9198b7",
"sector_size": 1073741824
},
"v20-stacked-proof-of-replication-e99a585174b6a45b254ba4780d72c89ad808c305c6d11711009ade4f39dba8e9.vk": {
"cid": "QmWReGfbuoozNErbskmFvqV4q36BY6F2WWb4cVFc3zoYkA",
"digest": "20d58a3fae7343481f8298a2dd493dd7",
"sector_size": 1073741824
},
"v20-stacked-proof-of-replication-f571ee2386f4c65a68e802747f2d78691006fc81a67971c4d9641403fffece16.params": {
"cid": "QmSAHu14Pe8iav6BYCt9XkpHJ73XM7tcpY4d9JK9BST9HU",
"digest": "7698426202c7e07b26ef056d31485b3a",
"sector_size": 16777216
},
"v20-stacked-proof-of-replication-f571ee2386f4c65a68e802747f2d78691006fc81a67971c4d9641403fffece16.vk": {
"cid": "QmaKtFLShnhMGVn7P9UsHjkgqtqRFSwCStqqykBN7u8dax",
"digest": "834408e5c3fce6ec5d1bf64e64cee94e",
"sector_size": 16777216
}
}
+1 -1
View File
@@ -5,7 +5,7 @@ import "fmt"
var CurrentCommit string
// BuildVersion is the local build version, set by build system
const BuildVersion = "0.1.6"
const BuildVersion = "0.2.8"
var UserVersion = BuildVersion + CurrentCommit
+4 -7
View File
@@ -15,7 +15,7 @@ import (
"github.com/ipfs/go-cid"
"github.com/ipfs/go-hamt-ipld"
cbor "github.com/ipfs/go-ipld-cbor"
logging "github.com/ipfs/go-log"
logging "github.com/ipfs/go-log/v2"
mh "github.com/multiformats/go-multihash"
)
@@ -27,6 +27,8 @@ const (
GasCreateActor = 100
)
var BuiltInActors map[cid.Cid]bool
func init() {
n, err := cbor.WrapObject(map[string]string{}, mh.SHA2_256, -1)
@@ -160,12 +162,7 @@ func (ia InitActor) Exec(act *types.Actor, vmctx types.VMContext, p *ExecParams)
}
func IsBuiltinActor(code cid.Cid) bool {
switch code {
case StorageMarketCodeCid, StoragePowerCodeCid, StorageMinerCodeCid, AccountCodeCid, InitCodeCid, MultisigCodeCid, PaymentChannelCodeCid:
return true
default:
return false
}
return BuiltInActors[code]
}
func IsSingletonActor(code cid.Cid) bool {
+82 -262
View File
@@ -6,8 +6,6 @@ import (
"encoding/binary"
"fmt"
ffi "github.com/filecoin-project/filecoin-ffi"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-sectorbuilder"
"github.com/filecoin-project/lotus/build"
@@ -19,13 +17,9 @@ import (
cbor "github.com/ipfs/go-ipld-cbor"
"github.com/libp2p/go-libp2p-core/peer"
cbg "github.com/whyrusleeping/cbor-gen"
"go.opencensus.io/trace"
"golang.org/x/xerrors"
)
const MaxSectors = 1 << 48
const RLEMax = 100e3
type StorageMinerActor struct{}
type StorageMinerActorState struct {
@@ -141,10 +135,7 @@ func (sma StorageMinerActor) Exports() []interface{} {
return []interface{}{
1: sma.StorageMinerConstructor,
2: sma.PreCommitSector,
3: withUpdates(
update{start: 0, method: sma.ProveCommitSectorV0},
update{start: build.ForkNoPowerEPSUpdates, method: sma.ProveCommitSectorV1},
),
3: sma.ProveCommitSector,
4: sma.SubmitFallbackPoSt,
//5: sma.SlashStorageFault,
//6: sma.GetCurrentProvingSet,
@@ -159,10 +150,7 @@ func (sma StorageMinerActor) Exports() []interface{} {
//15: sma.ChangeWorker,
16: sma.IsSlashed,
17: sma.CheckMiner,
18: withUpdates(
update{start: 0, method: sma.DeclareFaultsV0},
update{start: build.ForkNoPowerEPSUpdates, method: sma.DeclareFaultsV1},
),
18: sma.DeclareFaults,
19: sma.SlashConsensusFault,
20: sma.SubmitElectionPoSt,
}
@@ -298,110 +286,7 @@ type SectorProveCommitInfo struct {
DealIDs []uint64
}
func (sma StorageMinerActor) ProveCommitSectorV0(act *types.Actor, vmctx types.VMContext, params *SectorProveCommitInfo) ([]byte, ActorError) {
ctx := vmctx.Context()
oldstate, self, err := loadState(vmctx)
if err != nil {
return nil, err
}
mi, err := loadMinerInfo(vmctx, self)
if err != nil {
return nil, err
}
us, ok := self.PreCommittedSectors[uintToStringKey(params.SectorID)]
if !ok {
return nil, aerrors.New(1, "no pre-commitment found for sector")
}
if us.ReceivedEpoch+build.InteractivePoRepDelay >= vmctx.BlockHeight() {
return nil, aerrors.New(2, "too early for proof submission")
}
delete(self.PreCommittedSectors, uintToStringKey(params.SectorID))
// TODO: ensure normalization to ID address
maddr := vmctx.Message().To
ticket, err := vmctx.GetRandomness(us.Info.SealEpoch - build.SealRandomnessLookback)
if err != nil {
return nil, aerrors.Wrap(err, "failed to get ticket randomness")
}
seed, err := vmctx.GetRandomness(us.ReceivedEpoch + build.InteractivePoRepDelay)
if err != nil {
return nil, aerrors.Wrap(err, "failed to get randomness for prove sector commitment")
}
enc, err := SerializeParams(&ComputeDataCommitmentParams{
DealIDs: params.DealIDs,
SectorSize: mi.SectorSize,
})
if err != nil {
return nil, aerrors.Wrap(err, "failed to serialize ComputeDataCommitmentParams")
}
commD, err := vmctx.Send(StorageMarketAddress, SMAMethods.ComputeDataCommitment, types.NewInt(0), enc)
if err != nil {
return nil, aerrors.Wrapf(err, "failed to compute data commitment (sector %d, deals: %v)", params.SectorID, params.DealIDs)
}
if ok, err := vmctx.Sys().ValidatePoRep(ctx, maddr, mi.SectorSize, commD, us.Info.CommR, ticket, params.Proof, seed, params.SectorID); err != nil {
return nil, err
} else if !ok {
return nil, aerrors.Newf(2, "porep proof was invalid (t:%x; s:%x(%d); p:%s)", ticket, seed, us.ReceivedEpoch+build.InteractivePoRepDelay, truncateHexPrint(params.Proof))
}
// Note: There must exist a unique index in the miner's sector set for each
// sector ID. The `faults`, `recovered`, and `done` parameters of the
// SubmitPoSt method express indices into this sector set.
nssroot, err := AddToSectorSet(ctx, types.WrapStorage(vmctx.Storage()), self.Sectors, params.SectorID, us.Info.CommR, commD)
if err != nil {
return nil, err
}
self.Sectors = nssroot
// if miner is not mining, start their proving period now
// Note: As written here, every miners first PoSt will only be over one sector.
// We could set up a 'grace period' for starting mining that would allow miners
// to submit several sectors for their first proving period. Alternatively, we
// could simply make the 'PreCommitSector' call take multiple sectors at a time.
//
// Note: Proving period is a function of sector size; small sectors take less
// time to prove than large sectors do. Sector size is selected when pledging.
pss, lerr := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.ProvingSet)
if lerr != nil {
return nil, aerrors.HandleExternalError(lerr, "could not load proving set node")
}
if pss.Count == 0 {
self.ProvingSet = self.Sectors
// TODO: probably want to wait until the miner is above a certain
// threshold before starting this
self.ElectionPeriodStart = vmctx.BlockHeight()
}
nstate, err := vmctx.Storage().Put(self)
if err != nil {
return nil, err
}
if err := vmctx.Storage().Commit(oldstate, nstate); err != nil {
return nil, err
}
activateParams, err := SerializeParams(&ActivateStorageDealsParams{
Deals: params.DealIDs,
})
if err != nil {
return nil, err
}
_, err = vmctx.Send(StorageMarketAddress, SMAMethods.ActivateStorageDeals, types.NewInt(0), activateParams)
return nil, aerrors.Wrapf(err, "calling ActivateStorageDeals failed")
}
func (sma StorageMinerActor) ProveCommitSectorV1(act *types.Actor, vmctx types.VMContext, params *SectorProveCommitInfo) ([]byte, ActorError) {
func (sma StorageMinerActor) ProveCommitSector(act *types.Actor, vmctx types.VMContext, params *SectorProveCommitInfo) ([]byte, ActorError) {
ctx := vmctx.Context()
oldstate, self, err := loadState(vmctx)
if err != nil {
@@ -431,6 +316,14 @@ func (sma StorageMinerActor) ProveCommitSectorV1(act *types.Actor, vmctx types.V
// TODO: ensure normalization to ID address
maddr := vmctx.Message().To
if vmctx.BlockHeight()-us.Info.SealEpoch > build.MaxSealLookback {
return nil, aerrors.Newf(5, "source randomness for sector SealEpoch too far in past (epoch %d)", us.Info.SealEpoch)
}
if vmctx.BlockHeight()-us.ReceivedEpoch > build.MaxSealLookback {
return nil, aerrors.Newf(6, "source randomness for sector ReceivedEpoch too far in past (epoch %d)", us.ReceivedEpoch)
}
ticket, err := vmctx.GetRandomness(us.Info.SealEpoch - build.SealRandomnessLookback)
if err != nil {
return nil, aerrors.Wrap(err, "failed to get ticket randomness")
@@ -577,25 +470,21 @@ func (sma StorageMinerActor) SubmitFallbackPoSt(act *types.Actor, vmctx types.VM
return nil, aerrors.HandleExternalError(lerr, "could not load proving set node")
}
{
c, nerr := self.FaultSet.Count()
if nerr != nil {
return nil, aerrors.Absorb(nerr, 6, "invalid bitfield")
}
if c > RLEMax {
return nil, aerrors.Newf(7, "too many items in bitfield: %d", c)
}
ss, lerr := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Sectors)
if lerr != nil {
return nil, aerrors.HandleExternalError(lerr, "could not load proving set node")
}
faults, nerr := self.FaultSet.AllMap()
faults, nerr := self.FaultSet.AllMap(2 * ss.Count)
if nerr != nil {
return nil, aerrors.Absorb(err, 5, "RLE+ invalid")
}
var sectorInfos []ffi.PublicSectorInfo
activeFaults := uint64(0)
var sectorInfos []types.PublicSectorInfo
if err := pss.ForEach(func(id uint64, v *cbg.Deferred) error {
if faults[id] {
activeFaults++
return nil
}
@@ -603,7 +492,7 @@ func (sma StorageMinerActor) SubmitFallbackPoSt(act *types.Actor, vmctx types.VM
if err := cbor.DecodeInto(v.Raw, &comms); err != nil {
return xerrors.New("could not decode comms")
}
si := ffi.PublicSectorInfo{
si := types.PublicSectorInfo{
SectorID: id,
}
commR := comms[0]
@@ -621,19 +510,19 @@ func (sma StorageMinerActor) SubmitFallbackPoSt(act *types.Actor, vmctx types.VM
proverID := vmctx.Message().To // TODO: normalize to ID address
var candidates []sectorbuilder.EPostCandidate
var candidates []types.Candidate
for _, t := range params.Candidates {
var partial [32]byte
copy(partial[:], t.Partial)
candidates = append(candidates, sectorbuilder.EPostCandidate{
candidates = append(candidates, types.Candidate{
PartialTicket: partial,
SectorID: t.SectorID,
SectorChallengeIndex: t.ChallengeIndex,
})
}
if ok, lerr := sectorbuilder.VerifyFallbackPost(vmctx.Context(), mi.SectorSize,
sectorbuilder.NewSortedPublicSectorInfo(sectorInfos), seed[:], params.Proof, candidates, proverID, 0); !ok || lerr != nil { // TODO: FORK - set faults to len(faults)
if ok, lerr := vmctx.Sys().VerifyFallbackPost(vmctx.Context(), mi.SectorSize,
sectorInfos, seed[:], params.Proof, candidates, proverID, activeFaults); !ok || lerr != nil {
if lerr != nil {
// TODO: study PoST errors
return nil, aerrors.Absorb(lerr, 4, "PoST error")
@@ -644,7 +533,7 @@ func (sma StorageMinerActor) SubmitFallbackPoSt(act *types.Actor, vmctx types.VM
}
// Post submission is successful!
if err := onSuccessfulPoSt(self, vmctx); err != nil {
if err := onSuccessfulPoSt(self, vmctx, activeFaults); err != nil {
return nil, err
}
@@ -678,7 +567,7 @@ func SectorIsUnique(ctx context.Context, s types.Storage, sroot cid.Cid, sid uin
}
func AddToSectorSet(ctx context.Context, blks amt.Blocks, ss cid.Cid, sectorID uint64, commR, commD []byte) (cid.Cid, ActorError) {
if sectorID >= MaxSectors {
if sectorID >= build.MinerMaxSectors {
return cid.Undef, aerrors.Newf(25, "sector ID out of range: %d", sectorID)
}
ssr, err := amt.LoadAMT(blks, ss)
@@ -701,7 +590,7 @@ func AddToSectorSet(ctx context.Context, blks amt.Blocks, ss cid.Cid, sectorID u
}
func GetFromSectorSet(ctx context.Context, s types.Storage, ss cid.Cid, sectorID uint64) (bool, []byte, []byte, ActorError) {
if sectorID >= MaxSectors {
if sectorID >= build.MinerMaxSectors {
return false, nil, nil, aerrors.Newf(25, "sector ID out of range: %d", sectorID)
}
@@ -747,17 +636,6 @@ func RemoveFromSectorSet(ctx context.Context, s types.Storage, ss cid.Cid, ids [
return ncid, nil
}
func ValidatePoRep(ctx context.Context, maddr address.Address, ssize uint64, commD, commR, ticket, proof, seed []byte, sectorID uint64) (bool, ActorError) {
_, span := trace.StartSpan(ctx, "ValidatePoRep")
defer span.End()
ok, err := sectorbuilder.VerifySeal(ssize, commR, commD, maddr, ticket, seed, sectorID, proof)
if err != nil {
return false, aerrors.Absorb(err, 25, "verify seal failed")
}
return ok, nil
}
func CollateralForPower(power types.BigInt) types.BigInt {
return types.BigMul(power, types.NewInt(10))
/* TODO: this
@@ -935,33 +813,7 @@ type DeclareFaultsParams struct {
Faults types.BitField
}
func (sma StorageMinerActor) DeclareFaultsV0(act *types.Actor, vmctx types.VMContext, params *DeclareFaultsParams) ([]byte, ActorError) {
oldstate, self, aerr := loadState(vmctx)
if aerr != nil {
return nil, aerr
}
nfaults, err := types.MergeBitFields(params.Faults, self.FaultSet)
if err != nil {
return nil, aerrors.Absorb(err, 1, "failed to merge bitfields")
}
self.FaultSet = nfaults
self.LastFaultSubmission = vmctx.BlockHeight()
nstate, aerr := vmctx.Storage().Put(self)
if err != nil { // TODO: FORK: should be aerr
return nil, aerr
}
if err := vmctx.Storage().Commit(oldstate, nstate); err != nil {
return nil, err
}
return nil, nil
}
func (sma StorageMinerActor) DeclareFaultsV1(act *types.Actor, vmctx types.VMContext, params *DeclareFaultsParams) ([]byte, ActorError) {
func (sma StorageMinerActor) DeclareFaults(act *types.Actor, vmctx types.VMContext, params *DeclareFaultsParams) ([]byte, ActorError) {
oldstate, self, aerr := loadState(vmctx)
if aerr != nil {
return nil, aerr
@@ -981,6 +833,20 @@ func (sma StorageMinerActor) DeclareFaultsV1(act *types.Actor, vmctx types.VMCon
return nil, aerrors.Absorb(err, 1, "failed to merge bitfields")
}
ss, nerr := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Sectors)
if nerr != nil {
return nil, aerrors.HandleExternalError(nerr, "failed to load sector set")
}
cf, nerr := nfaults.Count()
if nerr != nil {
return nil, aerrors.Absorb(nerr, 2, "could not decode RLE+")
}
if cf > 2*ss.Count {
return nil, aerrors.Newf(3, "too many declared faults: %d > %d", cf, 2*ss.Count)
}
self.FaultSet = nfaults
self.LastFaultSubmission = vmctx.BlockHeight()
@@ -1056,7 +922,41 @@ func (sma StorageMinerActor) SubmitElectionPoSt(act *types.Actor, vmctx types.VM
return nil, aerrors.New(1, "slashed miners can't perform election PoSt")
}
if err := onSuccessfulPoSt(self, vmctx); err != nil {
pss, nerr := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.ProvingSet)
if nerr != nil {
return nil, aerrors.HandleExternalError(nerr, "failed to load proving set")
}
ss, nerr := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Sectors)
if nerr != nil {
return nil, aerrors.HandleExternalError(nerr, "failed to load proving set")
}
faults, nerr := self.FaultSet.AllMap(2 * ss.Count)
if nerr != nil {
return nil, aerrors.Absorb(nerr, 1, "invalid bitfield (fatal?)")
}
activeFaults := uint64(0)
for f := range faults {
if f > amt.MaxIndex {
continue
}
var comms [][]byte
err := pss.Get(f, &comms)
if err != nil {
var notfound *amt.ErrNotFound
if !xerrors.As(err, &notfound) {
return nil, aerrors.HandleExternalError(err, "failed to find sector in sector set")
}
continue
}
activeFaults++
}
if err := onSuccessfulPoSt(self, vmctx, activeFaults); err != nil { // TODO
return nil, err
}
@@ -1071,82 +971,7 @@ func (sma StorageMinerActor) SubmitElectionPoSt(act *types.Actor, vmctx types.VM
return nil, nil
}
func onSuccessfulPoSt(self *StorageMinerActorState, vmctx types.VMContext) aerrors.ActorError {
if vmctx.BlockHeight() >= build.ForkNoPowerEPSUpdates {
return onSuccessfulPoStV1(self, vmctx)
}
return onSuccessfulPoStV0(self, vmctx)
}
func onSuccessfulPoStV0(self *StorageMinerActorState, vmctx types.VMContext) aerrors.ActorError {
var mi MinerInfo
if err := vmctx.Storage().Get(self.Info, &mi); err != nil {
return err
}
pss, nerr := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.ProvingSet)
if nerr != nil {
return aerrors.HandleExternalError(nerr, "failed to load proving set")
}
faults, nerr := self.FaultSet.All()
if nerr != nil {
return aerrors.Absorb(nerr, 1, "invalid bitfield (fatal?)")
}
self.FaultSet = types.NewBitField()
oldPower := self.Power
newPower := types.BigMul(types.NewInt(pss.Count-uint64(len(faults))), types.NewInt(mi.SectorSize))
// If below the minimum size requirement, miners have zero power
if newPower.LessThan(types.NewInt(build.MinimumMinerPower)) {
newPower = types.NewInt(0)
}
self.Power = newPower
delta := types.BigSub(self.Power, oldPower)
if self.SlashedAt != 0 {
self.SlashedAt = 0
delta = self.Power
}
prevSlashingDeadline := self.ElectionPeriodStart + build.SlashablePowerDelay
if !self.Active && newPower.GreaterThan(types.NewInt(0)) {
self.Active = true
prevSlashingDeadline = 0
}
if !(oldPower.IsZero() && newPower.IsZero()) {
enc, err := SerializeParams(&UpdateStorageParams{
Delta: delta,
NextSlashDeadline: vmctx.BlockHeight() + build.SlashablePowerDelay,
PreviousSlashDeadline: prevSlashingDeadline,
})
if err != nil {
return err
}
_, err = vmctx.Send(StoragePowerAddress, SPAMethods.UpdateStorage, types.NewInt(0), enc)
if err != nil {
return aerrors.Wrap(err, "updating storage failed")
}
}
ncid, err := RemoveFromSectorSet(vmctx.Context(), vmctx.Storage(), self.Sectors, faults)
if err != nil {
return err
}
self.Sectors = ncid
self.ProvingSet = ncid
self.ElectionPeriodStart = vmctx.BlockHeight()
return nil
}
func onSuccessfulPoStV1(self *StorageMinerActorState, vmctx types.VMContext) aerrors.ActorError {
func onSuccessfulPoSt(self *StorageMinerActorState, vmctx types.VMContext, activeFaults uint64) aerrors.ActorError {
// TODO: some sector upkeep stuff that is very haphazard and unclear in the spec
var mi MinerInfo
@@ -1159,17 +984,12 @@ func onSuccessfulPoStV1(self *StorageMinerActorState, vmctx types.VMContext) aer
return aerrors.HandleExternalError(nerr, "failed to load proving set")
}
{
c, nerr := self.FaultSet.Count()
if nerr != nil {
return aerrors.Absorb(nerr, 2, "invalid bitfield")
}
if c > RLEMax {
return aerrors.Newf(3, "too many items in bitfield: %d", c)
}
ss, nerr := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Sectors)
if nerr != nil {
return aerrors.HandleExternalError(nerr, "failed to load sector set")
}
faults, nerr := self.FaultSet.All()
faults, nerr := self.FaultSet.All(2 * ss.Count)
if nerr != nil {
return aerrors.Absorb(nerr, 1, "invalid bitfield (fatal?)")
}
@@ -1177,7 +997,7 @@ func onSuccessfulPoStV1(self *StorageMinerActorState, vmctx types.VMContext) aer
self.FaultSet = types.NewBitField()
oldPower := self.Power
newPower := types.BigMul(types.NewInt(pss.Count-uint64(len(faults))), types.NewInt(mi.SectorSize))
newPower := types.BigMul(types.NewInt(pss.Count-activeFaults), types.NewInt(mi.SectorSize))
// If below the minimum size requirement, miners have zero power
if newPower.LessThan(types.NewInt(build.MinimumMinerPower)) {
+903
View File
@@ -0,0 +1,903 @@
package actors
import (
"bytes"
"context"
"fmt"
amt2 "github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/go-sectorbuilder"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors/aerrors"
"github.com/filecoin-project/lotus/chain/types"
"github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
)
type StorageMinerActor2 struct{}
func (sma StorageMinerActor2) Exports() []interface{} {
return []interface{}{
1: sma.StorageMinerConstructor,
2: sma.PreCommitSector,
3: sma.ProveCommitSector,
4: sma.SubmitFallbackPoSt,
//5: sma.SlashStorageFault,
//6: sma.GetCurrentProvingSet,
//7: sma.ArbitrateDeal,
//8: sma.DePledge,
9: sma.GetOwner,
10: sma.GetWorkerAddr,
11: withUpdates(
update{0, sma.GetPower},
update{build.ForkMissingSnowballs, sma.GetPower2},
), // FORK
12: sma.GetPeerID,
13: sma.GetSectorSize,
14: sma.UpdatePeerID,
//15: sma.ChangeWorker,
16: sma.IsSlashed,
17: sma.CheckMiner,
18: sma.DeclareFaults,
19: sma.SlashConsensusFault,
20: sma.SubmitElectionPoSt,
}
}
func (sma StorageMinerActor2) StorageMinerConstructor(act *types.Actor, vmctx types.VMContext, params *StorageMinerConstructorParams) ([]byte, ActorError) {
minerInfo := &MinerInfo{
Owner: params.Owner,
Worker: params.Worker,
PeerID: params.PeerID,
SectorSize: params.SectorSize,
}
minfocid, err := vmctx.Storage().Put(minerInfo)
if err != nil {
return nil, err
}
var self StorageMinerActorState
sectors := amt2.NewAMT(types.WrapStorage(vmctx.Storage()))
scid, serr := sectors.Flush()
if serr != nil {
return nil, aerrors.HandleExternalError(serr, "initializing AMT")
}
self.Sectors = scid
self.ProvingSet = scid
self.Info = minfocid
storage := vmctx.Storage()
c, err := storage.Put(&self)
if err != nil {
return nil, err
}
if err := storage.Commit(EmptyCBOR, c); err != nil {
return nil, err
}
return nil, nil
}
func (sma StorageMinerActor2) PreCommitSector(act *types.Actor, vmctx types.VMContext, params *SectorPreCommitInfo) ([]byte, ActorError) {
ctx := vmctx.Context()
oldstate, self, err := loadState(vmctx)
if err != nil {
return nil, err
}
if params.SealEpoch >= vmctx.BlockHeight()+build.SealRandomnessLookback {
return nil, aerrors.Newf(1, "sector commitment must be based off past randomness (%d >= %d)", params.SealEpoch, vmctx.BlockHeight()+build.SealRandomnessLookback)
}
if vmctx.BlockHeight()-params.SealEpoch+build.SealRandomnessLookback > build.SealRandomnessLookbackLimit {
return nil, aerrors.Newf(2, "sector commitment must be recent enough (was %d)", vmctx.BlockHeight()-params.SealEpoch+build.SealRandomnessLookback)
}
mi, err := loadMinerInfo(vmctx, self)
if err != nil {
return nil, err
}
if vmctx.Message().From != mi.Worker {
return nil, aerrors.New(1, "not authorized to precommit sector for miner")
}
// make sure the miner isnt trying to submit a pre-existing sector
unique, err := SectorIsUnique(ctx, vmctx.Storage(), self.Sectors, params.SectorNumber)
if err != nil {
return nil, err
}
if !unique {
return nil, aerrors.New(3, "sector already committed!")
}
// Power of the miner after adding this sector
futurePower := types.BigAdd(self.Power, types.NewInt(mi.SectorSize))
collateralRequired := CollateralForPower(futurePower)
// TODO: grab from market?
if act.Balance.LessThan(collateralRequired) {
return nil, aerrors.New(4, "not enough collateral")
}
self.PreCommittedSectors[uintToStringKey(params.SectorNumber)] = &PreCommittedSector{
Info: *params,
ReceivedEpoch: vmctx.BlockHeight(),
}
if len(self.PreCommittedSectors) > 4096 {
return nil, aerrors.New(5, "too many precommitted sectors")
}
nstate, err := vmctx.Storage().Put(self)
if err != nil {
return nil, err
}
if err := vmctx.Storage().Commit(oldstate, nstate); err != nil {
return nil, err
}
return nil, nil
}
func (sma StorageMinerActor2) ProveCommitSector(act *types.Actor, vmctx types.VMContext, params *SectorProveCommitInfo) ([]byte, ActorError) {
ctx := vmctx.Context()
oldstate, self, err := loadState(vmctx)
if err != nil {
return nil, err
}
mi, err := loadMinerInfo(vmctx, self)
if err != nil {
return nil, err
}
if vmctx.Message().From != mi.Worker {
return nil, aerrors.New(1, "not authorized to submit sector proof for miner")
}
us, ok := self.PreCommittedSectors[uintToStringKey(params.SectorID)]
if !ok {
return nil, aerrors.New(1, "no pre-commitment found for sector")
}
if us.ReceivedEpoch+build.InteractivePoRepDelay >= vmctx.BlockHeight() {
return nil, aerrors.New(2, "too early for proof submission")
}
delete(self.PreCommittedSectors, uintToStringKey(params.SectorID))
// TODO: ensure normalization to ID address
maddr := vmctx.Message().To
if vmctx.BlockHeight()-us.Info.SealEpoch > build.MaxSealLookback {
return nil, aerrors.Newf(5, "source randomness for sector SealEpoch too far in past (epoch %d)", us.Info.SealEpoch)
}
if vmctx.BlockHeight()-us.ReceivedEpoch > build.MaxSealLookback {
return nil, aerrors.Newf(6, "source randomness for sector ReceivedEpoch too far in past (epoch %d)", us.ReceivedEpoch)
}
ticket, err := vmctx.GetRandomness(us.Info.SealEpoch - build.SealRandomnessLookback)
if err != nil {
return nil, aerrors.Wrap(err, "failed to get ticket randomness")
}
seed, err := vmctx.GetRandomness(us.ReceivedEpoch + build.InteractivePoRepDelay)
if err != nil {
return nil, aerrors.Wrap(err, "failed to get randomness for prove sector commitment")
}
enc, err := SerializeParams(&ComputeDataCommitmentParams{
DealIDs: params.DealIDs,
SectorSize: mi.SectorSize,
})
if err != nil {
return nil, aerrors.Wrap(err, "failed to serialize ComputeDataCommitmentParams")
}
commD, err := vmctx.Send(StorageMarketAddress, SMAMethods.ComputeDataCommitment, types.NewInt(0), enc)
if err != nil {
return nil, aerrors.Wrapf(err, "failed to compute data commitment (sector %d, deals: %v)", params.SectorID, params.DealIDs)
}
if ok, err := vmctx.Sys().ValidatePoRep(ctx, maddr, mi.SectorSize, commD, us.Info.CommR, ticket, params.Proof, seed, params.SectorID); err != nil {
return nil, err
} else if !ok {
return nil, aerrors.Newf(2, "porep proof was invalid (t:%x; s:%x(%d); p:%s)", ticket, seed, us.ReceivedEpoch+build.InteractivePoRepDelay, truncateHexPrint(params.Proof))
}
// Note: There must exist a unique index in the miner's sector set for each
// sector ID. The `faults`, `recovered`, and `done` parameters of the
// SubmitPoSt method express indices into this sector set.
nssroot, err := AddToSectorSet2(ctx, types.WrapStorage(vmctx.Storage()), self.Sectors, params.SectorID, us.Info.CommR, commD)
if err != nil {
return nil, err
}
self.Sectors = nssroot
// if miner is not mining, start their proving period now
// Note: As written here, every miners first PoSt will only be over one sector.
// We could set up a 'grace period' for starting mining that would allow miners
// to submit several sectors for their first proving period. Alternatively, we
// could simply make the 'PreCommitSector' call take multiple sectors at a time.
//
// Note: Proving period is a function of sector size; small sectors take less
// time to prove than large sectors do. Sector size is selected when pledging.
pss, lerr := amt2.LoadAMT(types.WrapStorage(vmctx.Storage()), self.ProvingSet)
if lerr != nil {
return nil, aerrors.HandleExternalError(lerr, "could not load proving set node")
}
if pss.Count == 0 && !self.Active {
self.ProvingSet = self.Sectors
// TODO: probably want to wait until the miner is above a certain
// threshold before starting this
self.ElectionPeriodStart = vmctx.BlockHeight()
}
nstate, err := vmctx.Storage().Put(self)
if err != nil {
return nil, err
}
if err := vmctx.Storage().Commit(oldstate, nstate); err != nil {
return nil, err
}
activateParams, err := SerializeParams(&ActivateStorageDealsParams{
Deals: params.DealIDs,
})
if err != nil {
return nil, err
}
_, err = vmctx.Send(StorageMarketAddress, SMAMethods.ActivateStorageDeals, types.NewInt(0), activateParams)
return nil, aerrors.Wrapf(err, "calling ActivateStorageDeals failed")
}
func (sma StorageMinerActor2) SubmitFallbackPoSt(act *types.Actor, vmctx types.VMContext, params *SubmitFallbackPoStParams) ([]byte, ActorError) {
oldstate, self, err := loadState(vmctx)
if err != nil {
return nil, err
}
mi, err := loadMinerInfo(vmctx, self)
if err != nil {
return nil, err
}
if vmctx.Message().From != mi.Worker {
return nil, aerrors.New(1, "not authorized to submit post for miner")
}
/*
// TODO: handle fees
msgVal := vmctx.Message().Value
if msgVal.LessThan(feesRequired) {
return nil, aerrors.New(2, "not enough funds to pay post submission fees")
}
if msgVal.GreaterThan(feesRequired) {
_, err := vmctx.Send(vmctx.Message().From, 0,
types.BigSub(msgVal, feesRequired), nil)
if err != nil {
return nil, aerrors.Wrap(err, "could not refund excess fees")
}
}
*/
var seed [sectorbuilder.CommLen]byte
{
randHeight := self.ElectionPeriodStart + build.FallbackPoStDelay
if vmctx.BlockHeight() <= randHeight {
// TODO: spec, retcode
return nil, aerrors.Newf(1, "submit fallback PoSt called too early (%d < %d)", vmctx.BlockHeight(), randHeight)
}
rand, err := vmctx.GetRandomness(randHeight)
if err != nil {
return nil, aerrors.Wrap(err, "could not get randomness for PoST")
}
if len(rand) < len(seed) {
return nil, aerrors.Escalate(fmt.Errorf("randomness too small (%d < %d)",
len(rand), len(seed)), "improper randomness")
}
copy(seed[:], rand)
}
pss, lerr := amt2.LoadAMT(types.WrapStorage(vmctx.Storage()), self.ProvingSet)
if lerr != nil {
return nil, aerrors.HandleExternalError(lerr, "could not load proving set node")
}
ss, lerr := amt2.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Sectors)
if lerr != nil {
return nil, aerrors.HandleExternalError(lerr, "could not load proving set node")
}
faults, nerr := self.FaultSet.AllMap(2 * ss.Count)
if nerr != nil {
return nil, aerrors.Absorb(err, 5, "RLE+ invalid")
}
activeFaults := uint64(0)
var sectorInfos []types.PublicSectorInfo
if err := pss.ForEach(func(id uint64, v *cbg.Deferred) error {
if faults[id] {
activeFaults++
return nil
}
var comms [][]byte
if err := cbor.DecodeInto(v.Raw, &comms); err != nil {
return xerrors.New("could not decode comms")
}
si := types.PublicSectorInfo{
SectorID: id,
}
commR := comms[0]
if len(commR) != len(si.CommR) {
return xerrors.Errorf("commR length is wrong: %d", len(commR))
}
copy(si.CommR[:], commR)
sectorInfos = append(sectorInfos, si)
return nil
}); err != nil {
return nil, aerrors.Absorb(err, 3, "could not decode sectorset")
}
proverID := vmctx.Message().To // TODO: normalize to ID address
var candidates []types.Candidate
for _, t := range params.Candidates {
var partial [32]byte
copy(partial[:], t.Partial)
candidates = append(candidates, types.Candidate{
PartialTicket: partial,
SectorID: t.SectorID,
SectorChallengeIndex: t.ChallengeIndex,
})
}
if ok, lerr := vmctx.Sys().VerifyFallbackPost(vmctx.Context(), mi.SectorSize,
sectorInfos, seed[:], params.Proof, candidates, proverID, activeFaults); !ok || lerr != nil {
if lerr != nil {
// TODO: study PoST errors
return nil, aerrors.Absorb(lerr, 4, "PoST error")
}
if !ok {
return nil, aerrors.New(4, "PoST invalid")
}
}
// Post submission is successful!
if err := onSuccessfulPoSt2(self, vmctx, activeFaults); err != nil {
return nil, err
}
c, err := vmctx.Storage().Put(self)
if err != nil {
return nil, err
}
if err := vmctx.Storage().Commit(oldstate, c); err != nil {
return nil, err
}
return nil, nil
}
func (sma StorageMinerActor2) GetPower(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
_, self, err := loadState(vmctx)
if err != nil {
return nil, err
}
return self.Power.Bytes(), nil
}
func (sma StorageMinerActor2) GetPower2(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
_, self, err := loadState(vmctx)
if err != nil {
return nil, err
}
if self.SlashedAt != 0 {
return types.NewInt(0).Bytes(), nil
}
return self.Power.Bytes(), nil
}
func SectorIsUnique2(ctx context.Context, s types.Storage, sroot cid.Cid, sid uint64) (bool, ActorError) {
found, _, _, err := GetFromSectorSet2(ctx, s, sroot, sid)
if err != nil {
return false, err
}
return !found, nil
}
func AddToSectorSet2(ctx context.Context, blks amt2.Blocks, ss cid.Cid, sectorID uint64, commR, commD []byte) (cid.Cid, ActorError) {
if sectorID >= build.MinerMaxSectors {
return cid.Undef, aerrors.Newf(25, "sector ID out of range: %d", sectorID)
}
ssr, err := amt2.LoadAMT(blks, ss)
if err != nil {
return cid.Undef, aerrors.HandleExternalError(err, "could not load sector set node")
}
// TODO: Spec says to use SealCommitment, and construct commD from deals each time,
// but that would make SubmitPoSt way, way more expensive
if err := ssr.Set(sectorID, [][]byte{commR, commD}); err != nil {
return cid.Undef, aerrors.HandleExternalError(err, "failed to set commitment in sector set")
}
ncid, err := ssr.Flush()
if err != nil {
return cid.Undef, aerrors.HandleExternalError(err, "failed to flush sector set")
}
return ncid, nil
}
func GetFromSectorSet2(ctx context.Context, s types.Storage, ss cid.Cid, sectorID uint64) (bool, []byte, []byte, ActorError) {
if sectorID >= build.MinerMaxSectors {
return false, nil, nil, aerrors.Newf(25, "sector ID out of range: %d", sectorID)
}
ssr, err := amt2.LoadAMT(types.WrapStorage(s), ss)
if err != nil {
return false, nil, nil, aerrors.HandleExternalError(err, "could not load sector set node")
}
var comms [][]byte
err = ssr.Get(sectorID, &comms)
if err != nil {
if _, ok := err.(*amt2.ErrNotFound); ok {
return false, nil, nil, nil
}
return false, nil, nil, aerrors.HandleExternalError(err, "failed to find sector in sector set")
}
if len(comms) != 2 {
return false, nil, nil, aerrors.Newf(20, "sector set entry should only have 2 elements")
}
return true, comms[0], comms[1], nil
}
func RemoveFromSectorSet2(ctx context.Context, s types.Storage, ss cid.Cid, ids []uint64) (cid.Cid, aerrors.ActorError) {
ssr, err := amt2.LoadAMT(types.WrapStorage(s), ss)
if err != nil {
return cid.Undef, aerrors.HandleExternalError(err, "could not load sector set node")
}
for _, id := range ids {
if err := ssr.Delete(id); err != nil {
log.Warnf("failed to delete sector %d from set: %s", id, err)
}
}
ncid, err := ssr.Flush()
if err != nil {
return cid.Undef, aerrors.HandleExternalError(err, "failed to flush sector set")
}
return ncid, nil
}
func (sma StorageMinerActor2) GetWorkerAddr(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
_, self, err := loadState(vmctx)
if err != nil {
return nil, err
}
mi, err := loadMinerInfo(vmctx, self)
if err != nil {
return nil, err
}
return mi.Worker.Bytes(), nil
}
func (sma StorageMinerActor2) GetOwner(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
_, self, err := loadState(vmctx)
if err != nil {
return nil, err
}
mi, err := loadMinerInfo(vmctx, self)
if err != nil {
return nil, err
}
return mi.Owner.Bytes(), nil
}
func (sma StorageMinerActor2) GetPeerID(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
_, self, err := loadState(vmctx)
if err != nil {
return nil, err
}
mi, err := loadMinerInfo(vmctx, self)
if err != nil {
return nil, err
}
return []byte(mi.PeerID), nil
}
func (sma StorageMinerActor2) UpdatePeerID(act *types.Actor, vmctx types.VMContext, params *UpdatePeerIDParams) ([]byte, ActorError) {
oldstate, self, err := loadState(vmctx)
if err != nil {
return nil, err
}
mi, err := loadMinerInfo(vmctx, self)
if err != nil {
return nil, err
}
if vmctx.Message().From != mi.Worker {
return nil, aerrors.New(2, "only the mine worker may update the peer ID")
}
mi.PeerID = params.PeerID
mic, err := vmctx.Storage().Put(mi)
if err != nil {
return nil, err
}
self.Info = mic
c, err := vmctx.Storage().Put(self)
if err != nil {
return nil, err
}
if err := vmctx.Storage().Commit(oldstate, c); err != nil {
return nil, err
}
return nil, nil
}
func (sma StorageMinerActor2) GetSectorSize(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
_, self, err := loadState(vmctx)
if err != nil {
return nil, err
}
mi, err := loadMinerInfo(vmctx, self)
if err != nil {
return nil, err
}
return types.NewInt(mi.SectorSize).Bytes(), nil
}
func (sma StorageMinerActor2) IsSlashed(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
_, self, err := loadState(vmctx)
if err != nil {
return nil, err
}
return cbg.EncodeBool(self.SlashedAt != 0), nil
}
// TODO: better name
func (sma StorageMinerActor2) CheckMiner(act *types.Actor, vmctx types.VMContext, params *CheckMinerParams) ([]byte, ActorError) {
if vmctx.Message().From != StoragePowerAddress {
return nil, aerrors.New(2, "only the storage power actor can check miner")
}
oldstate, self, err := loadState(vmctx)
if err != nil {
return nil, err
}
if !isLate(vmctx.BlockHeight(), self) {
// Everything's fine
return nil, nil
}
if self.SlashedAt != 0 {
// Don't slash more than necessary
return nil, nil
}
if params.NetworkPower.Equals(self.Power) {
// Don't break the network when there's only one miner left
log.Warnf("can't slash miner %s for missed PoSt, no power would be left in the network", vmctx.Message().To)
return nil, nil
}
// Slash for being late
self.SlashedAt = vmctx.BlockHeight()
oldPower := self.Power
if vmctx.BlockHeight() > build.ForkMissingSnowballs {
self.Power = types.NewInt(0)
}
nstate, err := vmctx.Storage().Put(self)
if err != nil {
return nil, err
}
if err := vmctx.Storage().Commit(oldstate, nstate); err != nil {
return nil, err
}
var out bytes.Buffer
if err := oldPower.MarshalCBOR(&out); err != nil {
return nil, aerrors.HandleExternalError(err, "marshaling return value")
}
return out.Bytes(), nil
}
func (sma StorageMinerActor2) DeclareFaults(act *types.Actor, vmctx types.VMContext, params *DeclareFaultsParams) ([]byte, ActorError) {
oldstate, self, aerr := loadState(vmctx)
if aerr != nil {
return nil, aerr
}
mi, aerr := loadMinerInfo(vmctx, self)
if aerr != nil {
return nil, aerr
}
if vmctx.Message().From != mi.Worker {
return nil, aerrors.New(1, "not authorized to declare faults for miner")
}
nfaults, err := types.MergeBitFields(params.Faults, self.FaultSet)
if err != nil {
return nil, aerrors.Absorb(err, 1, "failed to merge bitfields")
}
ss, nerr := amt2.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Sectors)
if nerr != nil {
return nil, aerrors.HandleExternalError(nerr, "failed to load sector set")
}
cf, nerr := nfaults.Count()
if nerr != nil {
return nil, aerrors.Absorb(nerr, 2, "could not decode RLE+")
}
if cf > 2*ss.Count {
return nil, aerrors.Newf(3, "too many declared faults: %d > %d", cf, 2*ss.Count)
}
self.FaultSet = nfaults
self.LastFaultSubmission = vmctx.BlockHeight()
nstate, aerr := vmctx.Storage().Put(self)
if aerr != nil {
return nil, aerr
}
if err := vmctx.Storage().Commit(oldstate, nstate); err != nil {
return nil, err
}
return nil, nil
}
func (sma StorageMinerActor2) SlashConsensusFault(act *types.Actor, vmctx types.VMContext, params *MinerSlashConsensusFault) ([]byte, ActorError) {
if vmctx.Message().From != StoragePowerAddress {
return nil, aerrors.New(1, "SlashConsensusFault may only be called by the storage market actor")
}
slashedCollateral := params.SlashedCollateral
if slashedCollateral.LessThan(act.Balance) {
slashedCollateral = act.Balance
}
// Some of the slashed collateral should be paid to the slasher
// GROWTH_RATE determines how fast the slasher share of slashed collateral will increase as block elapses
// current GROWTH_RATE results in SLASHER_SHARE reaches 1 after 30 blocks
// TODO: define arithmetic precision and rounding for this operation
blockElapsed := vmctx.BlockHeight() - params.AtHeight
slasherShare := slasherShare(params.SlashedCollateral, blockElapsed)
burnPortion := types.BigSub(slashedCollateral, slasherShare)
_, err := vmctx.Send(vmctx.Message().From, 0, slasherShare, nil)
if err != nil {
return nil, aerrors.Wrap(err, "failed to pay slasher")
}
_, err = vmctx.Send(BurntFundsAddress, 0, burnPortion, nil)
if err != nil {
return nil, aerrors.Wrap(err, "failed to burn funds")
}
if vmctx.BlockHeight() > build.ForkMissingSnowballs {
oldstate, self, err := loadState(vmctx)
if err != nil {
return nil, aerrors.Wrap(err, "failed to load state for slashing")
}
self.Power = types.NewInt(0)
ncid, err := vmctx.Storage().Put(self)
if err != nil {
return nil, err
}
if err := vmctx.Storage().Commit(oldstate, ncid); err != nil {
return nil, err
}
}
// TODO: this still allows the miner to commit sectors and submit posts,
// their users could potentially be unaffected, but the miner will never be
// able to mine a block again
// One potential issue: the miner will have to pay back the slashed
// collateral to continue submitting PoSts, which includes pledge
// collateral that they no longer really 'need'
return nil, nil
}
func (sma StorageMinerActor2) SubmitElectionPoSt(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, aerrors.ActorError) {
if vmctx.Message().From != NetworkAddress {
return nil, aerrors.Newf(1, "submit election post can only be called by the storage power actor")
}
oldstate, self, aerr := loadState(vmctx)
if aerr != nil {
return nil, aerr
}
if self.SlashedAt != 0 {
return nil, aerrors.New(1, "slashed miners can't perform election PoSt")
}
pss, nerr := amt2.LoadAMT(types.WrapStorage(vmctx.Storage()), self.ProvingSet)
if nerr != nil {
return nil, aerrors.HandleExternalError(nerr, "failed to load proving set")
}
ss, nerr := amt2.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Sectors)
if nerr != nil {
return nil, aerrors.HandleExternalError(nerr, "failed to load proving set")
}
faults, nerr := self.FaultSet.AllMap(2 * ss.Count)
if nerr != nil {
return nil, aerrors.Absorb(nerr, 1, "invalid bitfield (fatal?)")
}
activeFaults := uint64(0)
for f := range faults {
if f > amt2.MaxIndex {
continue
}
var comms [][]byte
err := pss.Get(f, &comms)
if err != nil {
var notfound *amt2.ErrNotFound
if !xerrors.As(err, &notfound) {
return nil, aerrors.HandleExternalError(err, "failed to find sector in sector set")
}
continue
}
activeFaults++
}
if err := onSuccessfulPoSt2(self, vmctx, activeFaults); err != nil { // TODO
return nil, err
}
ncid, err := vmctx.Storage().Put(self)
if err != nil {
return nil, err
}
if err := vmctx.Storage().Commit(oldstate, ncid); err != nil {
return nil, err
}
return nil, nil
}
func onSuccessfulPoSt2(self *StorageMinerActorState, vmctx types.VMContext, activeFaults uint64) aerrors.ActorError {
// FORK
if vmctx.BlockHeight() < build.ForkBootyBayHeight {
return onSuccessfulPoSt(self, vmctx, activeFaults)
}
var mi MinerInfo
if err := vmctx.Storage().Get(self.Info, &mi); err != nil {
return err
}
pss, nerr := amt2.LoadAMT(types.WrapStorage(vmctx.Storage()), self.ProvingSet)
if nerr != nil {
return aerrors.HandleExternalError(nerr, "failed to load proving set")
}
ss, nerr := amt2.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Sectors)
if nerr != nil {
return aerrors.HandleExternalError(nerr, "failed to load sector set")
}
faults, nerr := self.FaultSet.All(2 * ss.Count)
if nerr != nil {
return aerrors.Absorb(nerr, 1, "invalid bitfield (fatal?)")
}
self.FaultSet = types.NewBitField()
oldPower := self.Power
newPower := types.BigMul(types.NewInt(pss.Count-activeFaults), types.NewInt(mi.SectorSize))
// If below the minimum size requirement, miners have zero power
if newPower.LessThan(types.NewInt(build.MinimumMinerPower)) {
newPower = types.NewInt(0)
}
self.Power = newPower
delta := types.BigSub(self.Power, oldPower)
if self.SlashedAt != 0 {
self.SlashedAt = 0
delta = self.Power
}
prevSlashingDeadline := self.ElectionPeriodStart + build.SlashablePowerDelay
if !self.Active && newPower.GreaterThan(types.NewInt(0)) {
self.Active = true
prevSlashingDeadline = 0
}
if !(oldPower.IsZero() && newPower.IsZero()) {
enc, err := SerializeParams(&UpdateStorageParams{
Delta: delta,
NextSlashDeadline: vmctx.BlockHeight() + build.SlashablePowerDelay,
PreviousSlashDeadline: prevSlashingDeadline,
})
if err != nil {
return err
}
_, err = vmctx.Send(StoragePowerAddress, SPAMethods.UpdateStorage, types.NewInt(0), enc)
if err != nil {
return aerrors.Wrap(err, "updating storage failed")
}
self.ElectionPeriodStart = vmctx.BlockHeight()
}
var ncid cid.Cid
var err aerrors.ActorError
ncid, err = RemoveFromSectorSet2(vmctx.Context(), vmctx.Storage(), self.Sectors, faults)
if err != nil {
return err
}
self.Sectors = ncid
self.ProvingSet = ncid
return nil
}
+71 -12
View File
@@ -3,18 +3,22 @@ package actors_test
import (
"bytes"
"context"
"math"
"math/rand"
"testing"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-sectorbuilder"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/actors/aerrors"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/rlepluslazy"
hamt "github.com/ipfs/go-hamt-ipld"
blockstore "github.com/ipfs/go-ipfs-blockstore"
"github.com/stretchr/testify/assert"
cbg "github.com/whyrusleeping/cbor-gen"
)
@@ -50,23 +54,37 @@ func TestMinerCommitSectors(t *testing.T) {
addSectorToMiner(h, t, minerAddr, worker, client, 1)
assertSectorIDs(h, t, minerAddr, []uint64{1})
}
type badRuns struct {
done bool
}
func (br *badRuns) HasNext() bool {
return !br.done
}
func (br *badRuns) NextRun() (rlepluslazy.Run, error) {
br.done = true
return rlepluslazy.Run{true, math.MaxInt64}, nil
}
var _ rlepluslazy.RunIterator = (*badRuns)(nil)
func TestMinerSubmitBadFault(t *testing.T) {
oldSS, oldMin := build.SectorSizes, build.MinimumMinerPower
build.SectorSizes, build.MinimumMinerPower = []uint64{1024}, 1024
defer func() {
build.SectorSizes, build.MinimumMinerPower = oldSS, oldMin
}()
var worker, client address.Address
var minerAddr address.Address
opts := []HarnessOpt{
HarnessAddr(&worker, 1000000),
HarnessAddr(&client, 1000000),
HarnessActor(&minerAddr, &worker, actors.StorageMinerCodeCid,
func() cbg.CBORMarshaler {
return &actors.StorageMinerConstructorParams{
Owner: worker,
Worker: worker,
SectorSize: 1024,
PeerID: "fakepeerid",
}
}),
HarnessAddMiner(&minerAddr, &worker),
}
h := NewHarness(t, opts...)
@@ -92,18 +110,52 @@ func TestMinerSubmitBadFault(t *testing.T) {
ret, _ = h.Invoke(t, actors.NetworkAddress, minerAddr, actors.MAMethods.SubmitElectionPoSt, nil)
ApplyOK(t, ret)
assertSectorIDs(h, t, minerAddr, []uint64{1})
st, err := getMinerState(context.TODO(), h.vm.StateTree(), h.bs, minerAddr)
assert.NoError(t, err)
expectedPower := st.Power
if types.BigCmp(expectedPower, types.NewInt(1024)) != 0 {
t.Errorf("Expected power of 1024, got %s", expectedPower)
}
badnum := uint64(0)
badnum--
bf = types.NewBitField()
bf.Set(badnum)
bf.Set(badnum - 1)
ret, _ = h.Invoke(t, worker, minerAddr, actors.MAMethods.DeclareFaults, &actors.DeclareFaultsParams{bf})
ApplyOK(t, ret)
ret, _ = h.Invoke(t, actors.NetworkAddress, minerAddr, actors.MAMethods.SubmitElectionPoSt, nil)
ApplyOK(t, ret)
assertSectorIDs(h, t, minerAddr, []uint64{1})
st, err = getMinerState(context.TODO(), h.vm.StateTree(), h.bs, minerAddr)
assert.NoError(t, err)
currentPower := st.Power
if types.BigCmp(expectedPower, currentPower) != 0 {
t.Errorf("power changed and shouldn't have: %s != %s", expectedPower, currentPower)
}
bf.Set(badnum - 2)
ret, _ = h.Invoke(t, worker, minerAddr, actors.MAMethods.DeclareFaults, &actors.DeclareFaultsParams{bf})
if ret.ExitCode != 3 {
t.Errorf("expected exit code 3, got %d: %+v", ret.ExitCode, ret.ActorErr)
}
assertSectorIDs(h, t, minerAddr, []uint64{1})
rle, err := rlepluslazy.EncodeRuns(&badRuns{}, []byte{})
assert.NoError(t, err)
bf, err = types.NewBitFieldFromBytes(rle)
assert.NoError(t, err)
ret, _ = h.Invoke(t, worker, minerAddr, actors.MAMethods.DeclareFaults, &actors.DeclareFaultsParams{bf})
if ret.ExitCode != 3 {
t.Errorf("expected exit code 3, got %d: %+v", ret.ExitCode, ret.ActorErr)
}
assertSectorIDs(h, t, minerAddr, []uint64{1})
bf = types.NewBitField()
bf.Set(1)
@@ -175,7 +227,7 @@ func assertSectorIDs(h *Harness, t *testing.T, maddr address.Address, ids []uint
}
}
func getMinerSectorSet(ctx context.Context, st types.StateTree, bs blockstore.Blockstore, maddr address.Address) ([]*api.ChainSectorInfo, error) {
func getMinerState(ctx context.Context, st types.StateTree, bs blockstore.Blockstore, maddr address.Address) (*actors.StorageMinerActorState, error) {
mact, err := st.GetActor(maddr)
if err != nil {
return nil, err
@@ -187,6 +239,14 @@ func getMinerSectorSet(ctx context.Context, st types.StateTree, bs blockstore.Bl
if err := cst.Get(ctx, mact.Head, &mstate); err != nil {
return nil, err
}
return &mstate, nil
}
func getMinerSectorSet(ctx context.Context, st types.StateTree, bs blockstore.Blockstore, maddr address.Address) ([]*api.ChainSectorInfo, error) {
mstate, err := getMinerState(ctx, st, bs, maddr)
if err != nil {
return nil, err
}
return stmgr.LoadSectorsFromSet(ctx, bs, mstate.Sectors)
}
@@ -202,7 +262,6 @@ func (h *Harness) makeFakeDeal(t *testing.T, miner, worker, client address.Addre
prop := actors.StorageDealProposal{
PieceRef: commP[:],
PieceSize: size,
//PieceSerialization SerializationMode // Needs to be here as it tells how data in the sector maps to PieceRef cid
Client: client,
Provider: miner,
+1 -1
View File
@@ -116,7 +116,7 @@ func (pca PaymentChannelActor) UpdateChannelState(act *types.Actor, vmctx types.
vb, nerr := sv.SigningBytes()
if nerr != nil {
return nil, aerrors.Escalate(nerr, "failed to serialize signedvoucher")
return nil, aerrors.Absorb(nerr, 1, "failed to serialize signedvoucher")
}
if err := vmctx.VerifySignature(sv.Signature, self.From, vb); err != nil {
+16 -9
View File
@@ -13,11 +13,12 @@ import (
"github.com/ipfs/go-hamt-ipld"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-cbor-util"
cborutil "github.com/filecoin-project/go-cbor-util"
"github.com/filecoin-project/go-sectorbuilder"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors/aerrors"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/sigs"
)
type StorageMarketActor struct{}
@@ -122,15 +123,21 @@ func (sdp *StorageDealProposal) Cid() (cid.Cid, error) {
return nd.Cid(), nil
}
func (sdp *StorageDealProposal) Verify() error {
unsigned := *sdp
unsigned.ProposerSignature = nil
var buf bytes.Buffer
if err := unsigned.MarshalCBOR(&buf); err != nil {
return err
func (sdp *StorageDealProposal) Verify(worker address.Address) error {
if sdp.Client != worker || worker == address.Undef {
unsigned := *sdp
unsigned.ProposerSignature = nil
var buf bytes.Buffer
if err := unsigned.MarshalCBOR(&buf); err != nil {
return err
}
if err := sigs.Verify(sdp.ProposerSignature, sdp.Client, buf.Bytes()); err != nil {
return err
}
}
return sdp.ProposerSignature.Verify(sdp.Client, buf.Bytes())
return nil
}
type OnChainDeal struct {
@@ -396,7 +403,7 @@ func (st *StorageMarketState) validateDeal(vmctx types.VMContext, deal StorageDe
return aerrors.New(2, "Deals must be submitted by the miner worker")
}
if err := deal.Verify(); err != nil {
if err := deal.Verify(providerWorker); err != nil {
return aerrors.Absorb(err, 3, "verifying proposer signature")
}
+74 -13
View File
@@ -17,6 +17,7 @@ import (
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors/aerrors"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/sigs"
)
type StoragePowerActor struct{}
@@ -67,7 +68,7 @@ type CreateStorageMinerParams struct {
func (spa StoragePowerActor) CreateStorageMiner(act *types.Actor, vmctx types.VMContext, params *CreateStorageMinerParams) ([]byte, ActorError) {
if !build.SupportedSectorSize(params.SectorSize) {
return nil, aerrors.New(1, "Unsupported sector size")
return nil, aerrors.Newf(1, "Unsupported sector size: %d", params.SectorSize)
}
var self StoragePowerState
@@ -85,7 +86,13 @@ func (spa StoragePowerActor) CreateStorageMiner(act *types.Actor, vmctx types.VM
return nil, aerrors.Newf(1, "not enough funds passed to cover required miner collateral (needed %s, got %s)", reqColl, vmctx.Message().Value)
}
encoded, err := CreateExecParams(StorageMinerCodeCid, &StorageMinerConstructorParams{
// FORK
minerCid := StorageMinerCodeCid
if vmctx.BlockHeight() > build.ForkFrigidHeight {
minerCid = StorageMiner2CodeCid
}
encoded, err := CreateExecParams(minerCid, &StorageMinerConstructorParams{
Owner: params.Owner,
Worker: params.Worker,
SectorSize: params.SectorSize,
@@ -130,10 +137,29 @@ type ArbitrateConsensusFaultParams struct {
}
func (spa StoragePowerActor) ArbitrateConsensusFault(act *types.Actor, vmctx types.VMContext, params *ArbitrateConsensusFaultParams) ([]byte, ActorError) {
if params == nil || params.Block1 == nil || params.Block2 == nil {
return nil, aerrors.New(1, "failed to parse params")
}
if params.Block1.Miner != params.Block2.Miner {
return nil, aerrors.New(2, "blocks must be from the same miner")
}
// FORK
if vmctx.BlockHeight() > build.ForkBlizzardHeight {
if params.Block1.Height <= build.ForkBlizzardHeight {
return nil, aerrors.New(10, "cannot slash miners with blocks from before blizzard")
}
if params.Block2.Height <= build.ForkBlizzardHeight {
return nil, aerrors.New(11, "cannot slash miners with blocks from before blizzard")
}
if params.Block1.Cid() == params.Block2.Cid() {
return nil, aerrors.New(3, "blocks must be different")
}
}
rval, err := vmctx.Send(params.Block1.Miner, MAMethods.GetWorkerAddr, types.NewInt(0), nil)
if err != nil {
return nil, aerrors.Wrap(err, "failed to get miner worker")
@@ -145,11 +171,11 @@ func (spa StoragePowerActor) ArbitrateConsensusFault(act *types.Actor, vmctx typ
return nil, aerrors.Absorb(oerr, 3, "response from 'GetWorkerAddr' was not a valid address")
}
if err := params.Block1.CheckBlockSignature(vmctx.Context(), worker); err != nil {
if err := sigs.CheckBlockSignature(params.Block1, vmctx.Context(), worker); err != nil {
return nil, aerrors.Absorb(err, 4, "block1 did not have valid signature")
}
if err := params.Block2.CheckBlockSignature(vmctx.Context(), worker); err != nil {
if err := sigs.CheckBlockSignature(params.Block2, vmctx.Context(), worker); err != nil {
return nil, aerrors.Absorb(err, 5, "block2 did not have valid signature")
}
@@ -449,7 +475,8 @@ func powerLookup(ctx context.Context, vmctx types.VMContext, self *StoragePowerS
}
if !has {
return types.EmptyInt, aerrors.New(1, "miner not registered with storage power actor")
// A miner could be registered with storage power actor, but removed for some reasons, e.g. consensus fault
return types.EmptyInt, aerrors.New(1, "miner not registered with storage power actor, or removed already")
}
// TODO: Use local amt
@@ -623,6 +650,8 @@ func checkProofSubmissionsAtH(vmctx types.VMContext, self *StoragePowerState, he
return aerrors.HandleExternalError(err, "failed to load proving bucket")
}
forRemoval := make([]address.Address, 0)
err = bhamt.ForEach(vmctx.Context(), func(k string, val interface{}) error {
_, span := trace.StartSpan(vmctx.Context(), "StoragePowerActor.CheckProofSubmissions.loop")
defer span.End()
@@ -632,6 +661,18 @@ func checkProofSubmissionsAtH(vmctx types.VMContext, self *StoragePowerState, he
return aerrors.Escalate(err, "parsing miner address")
}
if vmctx.BlockHeight() > build.ForkMissingSnowballs {
has, aerr := MinerSetHas(vmctx, self.Miners, maddr)
if aerr != nil {
return aerr
}
if !has {
forRemoval = append(forRemoval, maddr)
}
}
span.AddAttributes(trace.StringAttribute("miner", maddr.String()))
params, err := SerializeParams(&CheckMinerParams{NetworkPower: self.TotalStorage})
@@ -665,6 +706,24 @@ func checkProofSubmissionsAtH(vmctx types.VMContext, self *StoragePowerState, he
return aerrors.HandleExternalError(err, "iterating miners in proving bucket")
}
if vmctx.BlockHeight() > build.ForkMissingSnowballs && len(forRemoval) > 0 {
nBucket, err := MinerSetRemove(vmctx.Context(), vmctx, bucket, forRemoval...)
if err != nil {
return aerrors.Wrap(err, "could not remove miners from set")
}
eerr := buckets.Set(bucketID, nBucket)
if err != nil {
return aerrors.HandleExternalError(eerr, "could not set the bucket")
}
ncid, eerr := buckets.Flush()
if err != nil {
return aerrors.HandleExternalError(eerr, "could not flush buckets")
}
self.ProvingBuckets = ncid
}
return nil
}
@@ -739,19 +798,21 @@ func MinerSetAdd(ctx context.Context, vmctx types.VMContext, rcid cid.Cid, maddr
return c, nil
}
func MinerSetRemove(ctx context.Context, vmctx types.VMContext, rcid cid.Cid, maddr address.Address) (cid.Cid, aerrors.ActorError) {
func MinerSetRemove(ctx context.Context, vmctx types.VMContext, rcid cid.Cid, maddrs ...address.Address) (cid.Cid, aerrors.ActorError) {
nd, err := hamt.LoadNode(ctx, vmctx.Ipld(), rcid)
if err != nil {
return cid.Undef, aerrors.HandleExternalError(err, "failed to load miner set")
}
mkey := string(maddr.Bytes())
switch nd.Delete(ctx, mkey) {
default:
return cid.Undef, aerrors.HandleExternalError(err, "failed to delete miner from set")
case hamt.ErrNotFound:
return cid.Undef, aerrors.New(1, "miner not found in set on delete")
case nil:
for _, maddr := range maddrs {
mkey := string(maddr.Bytes())
switch nd.Delete(ctx, mkey) {
default:
return cid.Undef, aerrors.HandleExternalError(err, "failed to delete miner from set")
case hamt.ErrNotFound:
return cid.Undef, aerrors.New(1, "miner not found in set on delete")
case nil:
}
}
if err := nd.Flush(ctx); err != nil {
+11 -1
View File
@@ -13,6 +13,8 @@ import (
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm"
"github.com/filecoin-project/lotus/chain/wallet"
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
cid "github.com/ipfs/go-cid"
hamt "github.com/ipfs/go-hamt-ipld"
@@ -93,7 +95,15 @@ func TestStorageMarketCreateAndSlashMiner(t *testing.T) {
signBlock(t, h.w, workerAddr, b1)
signBlock(t, h.w, workerAddr, b2)
h.BlockHeight = build.ForkBlizzardHeight + 1
ret, _ := h.Invoke(t, ownerAddr, StoragePowerAddress, SPAMethods.ArbitrateConsensusFault,
&ArbitrateConsensusFaultParams{
Block1: b1,
Block2: b1,
})
assert.Equal(t, uint8(3), ret.ExitCode, "should have failed with exit 3")
ret, _ = h.Invoke(t, ownerAddr, StoragePowerAddress, SPAMethods.ArbitrateConsensusFault,
&ArbitrateConsensusFaultParams{
Block1: b1,
Block2: b2,
@@ -145,7 +155,7 @@ func cheatStorageMarketTotal(t *testing.T, vm *vm.VM, bs bstore.Blockstore) {
func fakeBlock(t *testing.T, minerAddr address.Address, ts uint64) *types.BlockHeader {
c := fakeCid(t, 1)
return &types.BlockHeader{Height: 5, Miner: minerAddr, Timestamp: ts, ParentStateRoot: c, Messages: c, ParentMessageReceipts: c, BLSAggregate: types.Signature{Type: types.KTBLS}}
return &types.BlockHeader{Height: 8000, Miner: minerAddr, Timestamp: ts, ParentStateRoot: c, Messages: c, ParentMessageReceipts: c, BLSAggregate: types.Signature{Type: types.KTBLS}}
}
func fakeCid(t *testing.T, s int) cid.Cid {
+13
View File
@@ -12,6 +12,7 @@ var CronCodeCid cid.Cid
var StoragePowerCodeCid cid.Cid
var StorageMarketCodeCid cid.Cid
var StorageMinerCodeCid cid.Cid
var StorageMiner2CodeCid cid.Cid
var MultisigCodeCid cid.Cid
var InitCodeCid cid.Cid
var PaymentChannelCodeCid cid.Cid
@@ -46,7 +47,19 @@ func init() {
StoragePowerCodeCid = mustSum("fil/1/power")
StorageMarketCodeCid = mustSum("fil/1/market")
StorageMinerCodeCid = mustSum("fil/1/miner")
StorageMiner2CodeCid = mustSum("fil/1/miner/2")
MultisigCodeCid = mustSum("fil/1/multisig")
InitCodeCid = mustSum("fil/1/init")
PaymentChannelCodeCid = mustSum("fil/1/paych")
BuiltInActors = map[cid.Cid]bool{
StorageMarketCodeCid: true,
StoragePowerCodeCid: true,
StorageMinerCodeCid: true,
StorageMiner2CodeCid: true,
AccountCodeCid: true,
InitCodeCid: true,
MultisigCodeCid: true,
PaymentChannelCodeCid: true,
}
}
+3 -3
View File
@@ -45,15 +45,15 @@ func setupVMTestEnv(t *testing.T) (*vm.VM, []address.Address, bstore.Blockstore)
t.Fatal(err)
}
stateroot, err := st.Flush()
stateroot, err := st.Flush(context.TODO())
if err != nil {
t.Fatal(err)
}
cs := store.NewChainStore(bs, nil)
cs := store.NewChainStore(bs, nil, nil)
// TODO: should probabaly mock out the randomness bit, nil works for now
vm, err := vm.NewVM(stateroot, 1, nil, maddr, cs.Blockstore())
vm, err := vm.NewVM(stateroot, 1, nil, maddr, cs.Blockstore(), cs.VMSys())
if err != nil {
t.Fatal(err)
}
+2 -1
View File
@@ -171,7 +171,8 @@ func HandleExternalError(err error, msg string) ActorError {
}
return &actorError{
fatal: true,
fatal: false,
retCode: 219,
msg: msg,
frame: xerrors.Caller(1),
+1 -1
View File
@@ -26,7 +26,7 @@ func withUpdates(updates ...update) interface{} {
vmctx := args[1].Interface().(types.VMContext)
for _, u := range updates {
if vmctx.BlockHeight() >= u.start {
if vmctx.BlockHeight() > u.start {
return reflect.ValueOf(u.method).Call(args)
}
}
+32 -4
View File
@@ -6,6 +6,8 @@ import (
"math/rand"
"testing"
"github.com/filecoin-project/go-sectorbuilder"
"github.com/ipfs/go-cid"
dstore "github.com/ipfs/go-datastore"
hamt "github.com/ipfs/go-hamt-ipld"
@@ -115,6 +117,32 @@ func HarnessActor(actor *address.Address, creator *address.Address, code cid.Cid
}
func HarnessAddMiner(addr *address.Address, creator *address.Address) HarnessOpt {
return func(t testing.TB, h *Harness) error {
if h.Stage != HarnessPostInit {
return nil
}
if !addr.Empty() {
return xerrors.New("actor address should be empty")
}
ret, _ := h.InvokeWithValue(t, *creator, actors.StoragePowerAddress,
actors.SPAMethods.CreateStorageMiner, types.NewInt(3000), &actors.StorageMinerConstructorParams{
Owner: *creator,
Worker: *creator,
SectorSize: 1024,
PeerID: "fakepeerid",
})
if ret.ExitCode != 0 {
return xerrors.Errorf("creating actor: %w", ret.ActorErr)
}
var err error
*addr, err = address.NewFromBytes(ret.Return)
return err
}
}
func HarnessCtx(ctx context.Context) HarnessOpt {
return func(t testing.TB, h *Harness) error {
h.ctx = ctx
@@ -158,7 +186,7 @@ func NewHarness(t *testing.T, options ...HarnessOpt) *Harness {
t.Fatal(err)
}
stateroot, err := st.Flush()
stateroot, err := st.Flush(context.TODO())
if err != nil {
t.Fatal(err)
}
@@ -168,8 +196,8 @@ func NewHarness(t *testing.T, options ...HarnessOpt) *Harness {
t.Fatal(err)
}
h.cs = store.NewChainStore(h.bs, nil)
h.vm, err = vm.NewVM(stateroot, 1, h.Rand, h.HI.Miner, h.cs.Blockstore())
h.cs = store.NewChainStore(h.bs, nil, vm.Syscalls(sectorbuilder.ProofVerifier))
h.vm, err = vm.NewVM(stateroot, 1, h.Rand, h.HI.Miner, h.cs.Blockstore(), h.cs.VMSys())
if err != nil {
t.Fatal(err)
}
@@ -177,7 +205,7 @@ func NewHarness(t *testing.T, options ...HarnessOpt) *Harness {
for _, opt := range options {
err := opt(t, h)
if err != nil {
t.Fatalf("Applying options: %v", err)
t.Fatalf("Applying options: %+v", err)
}
}
+9 -4
View File
@@ -21,10 +21,15 @@ func NewBadBlockCache() *BadBlockCache {
}
}
func (bts *BadBlockCache) Add(c cid.Cid) {
bts.badBlocks.Add(c, nil)
func (bts *BadBlockCache) Add(c cid.Cid, reason string) {
bts.badBlocks.Add(c, reason)
}
func (bts *BadBlockCache) Has(c cid.Cid) bool {
return bts.badBlocks.Contains(c)
func (bts *BadBlockCache) Has(c cid.Cid) (string, bool) {
rval, ok := bts.badBlocks.Get(c)
if !ok {
return "", false
}
return rval.(string), true
}
+37 -18
View File
@@ -3,18 +3,18 @@ package blocksync
import (
"bufio"
"context"
"time"
"github.com/libp2p/go-libp2p-core/protocol"
"go.opencensus.io/trace"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-cbor-util"
cborutil "github.com/filecoin-project/go-cbor-util"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
logging "github.com/ipfs/go-log"
logging "github.com/ipfs/go-log/v2"
inet "github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
)
@@ -25,11 +25,7 @@ type NewStreamFunc func(context.Context, peer.ID, ...protocol.ID) (inet.Stream,
const BlockSyncProtocolID = "/fil/sync/blk/0.0.1"
func init() {
cbor.RegisterCborType(BlockSyncRequest{})
cbor.RegisterCborType(BlockSyncResponse{})
cbor.RegisterCborType(BSTipSet{})
}
const BlockSyncMaxRequestLength = 800
type BlockSyncService struct {
cs *store.ChainStore
@@ -55,8 +51,17 @@ func ParseBSOptions(optfield uint64) *BSOptions {
}
const (
BSOptBlocks = 1 << 0
BSOptMessages = 1 << 1
BSOptBlocks = 1 << iota
BSOptMessages
)
const (
StatusOK = uint64(0)
StatusPartial = uint64(101)
StatusNotFound = uint64(201)
StatusGoAway = uint64(202)
StatusInternalError = uint64(203)
StatusBadRequest = uint64(204)
)
type BlockSyncResponse struct {
@@ -93,28 +98,30 @@ func (bss *BlockSyncService) HandleStream(s inet.Stream) {
log.Warnf("failed to read block sync request: %s", err)
return
}
log.Infof("block sync request for: %s %d", req.Start, req.RequestLength)
log.Infow("block sync request", "start", req.Start, "len", req.RequestLength)
resp, err := bss.processRequest(ctx, &req)
resp, err := bss.processRequest(ctx, s.Conn().RemotePeer(), &req)
if err != nil {
log.Warn("failed to process block sync request: ", err)
return
}
writeDeadline := 60 * time.Second
s.SetDeadline(time.Now().Add(writeDeadline))
if err := cborutil.WriteCborRPC(s, resp); err != nil {
log.Warn("failed to write back response for handle stream: ", err)
log.Warnw("failed to write back response for handle stream", "err", err, "peer", s.Conn().RemotePeer())
return
}
}
func (bss *BlockSyncService) processRequest(ctx context.Context, req *BlockSyncRequest) (*BlockSyncResponse, error) {
func (bss *BlockSyncService) processRequest(ctx context.Context, p peer.ID, req *BlockSyncRequest) (*BlockSyncResponse, error) {
_, span := trace.StartSpan(ctx, "blocksync.ProcessRequest")
defer span.End()
opts := ParseBSOptions(req.Options)
if len(req.Start) == 0 {
return &BlockSyncResponse{
Status: 204,
Status: StatusBadRequest,
Message: "no cids given in blocksync request",
}, nil
}
@@ -122,20 +129,32 @@ func (bss *BlockSyncService) processRequest(ctx context.Context, req *BlockSyncR
span.AddAttributes(
trace.BoolAttribute("blocks", opts.IncludeBlocks),
trace.BoolAttribute("messages", opts.IncludeMessages),
trace.Int64Attribute("reqlen", int64(req.RequestLength)),
)
chain, err := bss.collectChainSegment(types.NewTipSetKey(req.Start...), req.RequestLength, opts)
reqlen := req.RequestLength
if reqlen > BlockSyncMaxRequestLength {
log.Warnw("limiting blocksync request length", "orig", req.RequestLength, "peer", p)
reqlen = BlockSyncMaxRequestLength
}
chain, err := bss.collectChainSegment(types.NewTipSetKey(req.Start...), reqlen, opts)
if err != nil {
log.Warn("encountered error while responding to block sync request: ", err)
return &BlockSyncResponse{
Status: 203,
Status: StatusInternalError,
Message: err.Error(),
}, nil
}
status := StatusOK
if reqlen < req.RequestLength {
status = StatusPartial
}
return &BlockSyncResponse{
Chain: chain,
Status: 0,
Status: status,
}, nil
}
+20 -12
View File
@@ -18,9 +18,10 @@ import (
"go.opencensus.io/trace"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-cbor-util"
cborutil "github.com/filecoin-project/go-cbor-util"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
incrt "github.com/filecoin-project/lotus/lib/increadtimeout"
"github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/filecoin-project/lotus/peermgr"
)
@@ -44,15 +45,15 @@ func NewBlockSyncClient(bserv dtypes.ChainBlockService, h host.Host, pmgr peermg
func (bs *BlockSync) processStatus(req *BlockSyncRequest, res *BlockSyncResponse) error {
switch res.Status {
case 101: // Partial Response
case StatusPartial: // Partial Response
return xerrors.Errorf("not handling partial blocksync responses yet")
case 201: // req.Start not found
case StatusNotFound: // req.Start not found
return xerrors.Errorf("not found")
case 202: // Go Away
case StatusGoAway: // Go Away
return xerrors.Errorf("not handling 'go away' blocksync responses yet")
case 203: // Internal Error
case StatusInternalError: // Internal Error
return xerrors.Errorf("block sync peer errored: %s", res.Message)
case 204:
case StatusBadRequest:
return xerrors.Errorf("block sync request invalid: %s", res.Message)
default:
return xerrors.Errorf("unrecognized response code: %d", res.Status)
@@ -194,11 +195,16 @@ func (bs *BlockSync) GetChainMessages(ctx context.Context, h *types.TipSet, coun
continue
}
if res.Status == 0 {
if res.Status == StatusOK {
bs.syncPeers.logGlobalSuccess(time.Since(start))
return res.Chain, nil
}
if res.Status == StatusPartial {
log.Warn("dont yet handle partial responses")
continue
}
err = bs.processStatus(req, res)
if err != nil {
log.Warnf("BlockSync peer %s response was an error: %s", p.String(), err)
@@ -241,16 +247,18 @@ func (bs *BlockSync) sendRequestToPeer(ctx context.Context, p peer.ID, req *Bloc
bs.RemovePeer(p)
return nil, xerrors.Errorf("failed to open stream to peer: %w", err)
}
s.SetDeadline(time.Now().Add(10 * time.Second))
defer s.SetDeadline(time.Time{})
s.SetWriteDeadline(time.Now().Add(5 * time.Second))
if err := cborutil.WriteCborRPC(s, req); err != nil {
s.SetWriteDeadline(time.Time{})
bs.syncPeers.logFailure(p, time.Since(start))
return nil, err
}
s.SetWriteDeadline(time.Time{})
var res BlockSyncResponse
if err := cborutil.ReadCborRPC(bufio.NewReader(s), &res); err != nil {
r := incrt.New(s, 50<<10, 5*time.Second)
if err := cborutil.ReadCborRPC(bufio.NewReader(r), &res); err != nil {
bs.syncPeers.logFailure(p, time.Since(start))
return nil, err
}
@@ -455,7 +463,7 @@ func (bpt *bsPeerTracker) prefSortedPeers() []peer.ID {
getPeerInitLat := func(p peer.ID) float64 {
var res float64
if bpt.pmgr != nil {
if lat, ok := bpt.pmgr.GetPeerLatency(out[i]); ok {
if lat, ok := bpt.pmgr.GetPeerLatency(p); ok {
res = float64(lat)
}
}
@@ -476,7 +484,7 @@ func (bpt *bsPeerTracker) prefSortedPeers() []peer.ID {
failRateJ := float64(pj.failures) / float64(pj.failures+pj.successes)
costJ = float64(pj.averageTime) + failRateJ*float64(bpt.avgGlobalTime)
} else {
costI = getPeerInitLat(out[i])
costJ = getPeerInitLat(out[j])
}
return costI < costJ
-883
View File
@@ -1,883 +0,0 @@
package deals
import (
"fmt"
"io"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
"github.com/libp2p/go-libp2p-core/peer"
cbg "github.com/whyrusleeping/cbor-gen"
xerrors "golang.org/x/xerrors"
)
// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT.
var _ = xerrors.Errorf
func (t *AskRequest) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
if _, err := w.Write([]byte{129}); err != nil {
return err
}
// t.Miner (address.Address) (struct)
if err := t.Miner.MarshalCBOR(w); err != nil {
return err
}
return nil
}
func (t *AskRequest) UnmarshalCBOR(r io.Reader) error {
br := cbg.GetPeeker(r)
maj, extra, err := cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajArray {
return fmt.Errorf("cbor input should be of type array")
}
if extra != 1 {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.Miner (address.Address) (struct)
{
if err := t.Miner.UnmarshalCBOR(br); err != nil {
return err
}
}
return nil
}
func (t *AskResponse) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
if _, err := w.Write([]byte{129}); err != nil {
return err
}
// t.Ask (types.SignedStorageAsk) (struct)
if err := t.Ask.MarshalCBOR(w); err != nil {
return err
}
return nil
}
func (t *AskResponse) UnmarshalCBOR(r io.Reader) error {
br := cbg.GetPeeker(r)
maj, extra, err := cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajArray {
return fmt.Errorf("cbor input should be of type array")
}
if extra != 1 {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.Ask (types.SignedStorageAsk) (struct)
{
pb, err := br.PeekByte()
if err != nil {
return err
}
if pb == cbg.CborNull[0] {
var nbuf [1]byte
if _, err := br.Read(nbuf[:]); err != nil {
return err
}
} else {
t.Ask = new(types.SignedStorageAsk)
if err := t.Ask.UnmarshalCBOR(br); err != nil {
return err
}
}
}
return nil
}
func (t *Proposal) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
if _, err := w.Write([]byte{130}); err != nil {
return err
}
// t.DealProposal (actors.StorageDealProposal) (struct)
if err := t.DealProposal.MarshalCBOR(w); err != nil {
return err
}
// t.Piece (cid.Cid) (struct)
if err := cbg.WriteCid(w, t.Piece); err != nil {
return xerrors.Errorf("failed to write cid field t.Piece: %w", err)
}
return nil
}
func (t *Proposal) UnmarshalCBOR(r io.Reader) error {
br := cbg.GetPeeker(r)
maj, extra, err := cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajArray {
return fmt.Errorf("cbor input should be of type array")
}
if extra != 2 {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.DealProposal (actors.StorageDealProposal) (struct)
{
pb, err := br.PeekByte()
if err != nil {
return err
}
if pb == cbg.CborNull[0] {
var nbuf [1]byte
if _, err := br.Read(nbuf[:]); err != nil {
return err
}
} else {
t.DealProposal = new(actors.StorageDealProposal)
if err := t.DealProposal.UnmarshalCBOR(br); err != nil {
return err
}
}
}
// t.Piece (cid.Cid) (struct)
{
c, err := cbg.ReadCid(br)
if err != nil {
return xerrors.Errorf("failed to read cid field t.Piece: %w", err)
}
t.Piece = c
}
return nil
}
func (t *Response) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
if _, err := w.Write([]byte{132}); err != nil {
return err
}
// t.State (uint64) (uint64)
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.State))); 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 := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.Message)))); err != nil {
return err
}
if _, err := w.Write([]byte(t.Message)); err != nil {
return err
}
// t.Proposal (cid.Cid) (struct)
if err := cbg.WriteCid(w, t.Proposal); err != nil {
return xerrors.Errorf("failed to write cid field t.Proposal: %w", err)
}
// t.StorageDealSubmission (types.SignedMessage) (struct)
if err := t.StorageDealSubmission.MarshalCBOR(w); err != nil {
return err
}
return nil
}
func (t *Response) UnmarshalCBOR(r io.Reader) error {
br := cbg.GetPeeker(r)
maj, extra, err := cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajArray {
return fmt.Errorf("cbor input should be of type array")
}
if extra != 4 {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.State (uint64) (uint64)
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.State = uint64(extra)
// t.Message (string) (string)
{
sval, err := cbg.ReadString(br)
if err != nil {
return err
}
t.Message = string(sval)
}
// t.Proposal (cid.Cid) (struct)
{
c, err := cbg.ReadCid(br)
if err != nil {
return xerrors.Errorf("failed to read cid field t.Proposal: %w", err)
}
t.Proposal = c
}
// t.StorageDealSubmission (types.SignedMessage) (struct)
{
pb, err := br.PeekByte()
if err != nil {
return err
}
if pb == cbg.CborNull[0] {
var nbuf [1]byte
if _, err := br.Read(nbuf[:]); err != nil {
return err
}
} else {
t.StorageDealSubmission = new(types.SignedMessage)
if err := t.StorageDealSubmission.UnmarshalCBOR(br); err != nil {
return err
}
}
}
return nil
}
func (t *SignedResponse) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
if _, err := w.Write([]byte{130}); err != nil {
return err
}
// t.Response (deals.Response) (struct)
if err := t.Response.MarshalCBOR(w); err != nil {
return err
}
// t.Signature (types.Signature) (struct)
if err := t.Signature.MarshalCBOR(w); err != nil {
return err
}
return nil
}
func (t *SignedResponse) UnmarshalCBOR(r io.Reader) error {
br := cbg.GetPeeker(r)
maj, extra, err := cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajArray {
return fmt.Errorf("cbor input should be of type array")
}
if extra != 2 {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.Response (deals.Response) (struct)
{
if err := t.Response.UnmarshalCBOR(br); err != nil {
return err
}
}
// t.Signature (types.Signature) (struct)
{
pb, err := br.PeekByte()
if err != nil {
return err
}
if pb == cbg.CborNull[0] {
var nbuf [1]byte
if _, err := br.Read(nbuf[:]); err != nil {
return err
}
} else {
t.Signature = new(types.Signature)
if err := t.Signature.UnmarshalCBOR(br); err != nil {
return err
}
}
}
return nil
}
func (t *ClientDealProposal) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
if _, err := w.Write([]byte{136}); err != nil {
return err
}
// t.Data (cid.Cid) (struct)
if err := cbg.WriteCid(w, t.Data); err != nil {
return xerrors.Errorf("failed to write cid field t.Data: %w", err)
}
// t.PricePerEpoch (types.BigInt) (struct)
if err := t.PricePerEpoch.MarshalCBOR(w); err != nil {
return err
}
// t.ProposalExpiration (uint64) (uint64)
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.ProposalExpiration))); err != nil {
return err
}
// t.Duration (uint64) (uint64)
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Duration))); err != nil {
return err
}
// t.ProviderAddress (address.Address) (struct)
if err := t.ProviderAddress.MarshalCBOR(w); err != nil {
return err
}
// t.Client (address.Address) (struct)
if err := t.Client.MarshalCBOR(w); err != nil {
return err
}
// t.MinerWorker (address.Address) (struct)
if err := t.MinerWorker.MarshalCBOR(w); err != nil {
return err
}
// t.MinerID (peer.ID) (string)
if len(t.MinerID) > cbg.MaxLength {
return xerrors.Errorf("Value in field t.MinerID was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.MinerID)))); err != nil {
return err
}
if _, err := w.Write([]byte(t.MinerID)); err != nil {
return err
}
return nil
}
func (t *ClientDealProposal) UnmarshalCBOR(r io.Reader) error {
br := cbg.GetPeeker(r)
maj, extra, err := cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajArray {
return fmt.Errorf("cbor input should be of type array")
}
if extra != 8 {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.Data (cid.Cid) (struct)
{
c, err := cbg.ReadCid(br)
if err != nil {
return xerrors.Errorf("failed to read cid field t.Data: %w", err)
}
t.Data = c
}
// t.PricePerEpoch (types.BigInt) (struct)
{
if err := t.PricePerEpoch.UnmarshalCBOR(br); err != nil {
return err
}
}
// t.ProposalExpiration (uint64) (uint64)
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.ProposalExpiration = uint64(extra)
// t.Duration (uint64) (uint64)
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.Duration = uint64(extra)
// t.ProviderAddress (address.Address) (struct)
{
if err := t.ProviderAddress.UnmarshalCBOR(br); err != nil {
return err
}
}
// t.Client (address.Address) (struct)
{
if err := t.Client.UnmarshalCBOR(br); err != nil {
return err
}
}
// t.MinerWorker (address.Address) (struct)
{
if err := t.MinerWorker.UnmarshalCBOR(br); err != nil {
return err
}
}
// t.MinerID (peer.ID) (string)
{
sval, err := cbg.ReadString(br)
if err != nil {
return err
}
t.MinerID = peer.ID(sval)
}
return nil
}
func (t *ClientDeal) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
if _, err := w.Write([]byte{135}); err != nil {
return err
}
// t.ProposalCid (cid.Cid) (struct)
if err := cbg.WriteCid(w, t.ProposalCid); err != nil {
return xerrors.Errorf("failed to write cid field t.ProposalCid: %w", err)
}
// t.Proposal (actors.StorageDealProposal) (struct)
if err := t.Proposal.MarshalCBOR(w); err != nil {
return err
}
// t.State (uint64) (uint64)
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.State))); err != nil {
return err
}
// t.Miner (peer.ID) (string)
if len(t.Miner) > cbg.MaxLength {
return xerrors.Errorf("Value in field t.Miner was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.Miner)))); err != nil {
return err
}
if _, err := w.Write([]byte(t.Miner)); err != nil {
return err
}
// t.MinerWorker (address.Address) (struct)
if err := t.MinerWorker.MarshalCBOR(w); err != nil {
return err
}
// t.DealID (uint64) (uint64)
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.DealID))); err != nil {
return err
}
// t.PublishMessage (types.SignedMessage) (struct)
if err := t.PublishMessage.MarshalCBOR(w); err != nil {
return err
}
return nil
}
func (t *ClientDeal) UnmarshalCBOR(r io.Reader) error {
br := cbg.GetPeeker(r)
maj, extra, err := cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajArray {
return fmt.Errorf("cbor input should be of type array")
}
if extra != 7 {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.ProposalCid (cid.Cid) (struct)
{
c, err := cbg.ReadCid(br)
if err != nil {
return xerrors.Errorf("failed to read cid field t.ProposalCid: %w", err)
}
t.ProposalCid = c
}
// t.Proposal (actors.StorageDealProposal) (struct)
{
if err := t.Proposal.UnmarshalCBOR(br); err != nil {
return err
}
}
// t.State (uint64) (uint64)
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.State = uint64(extra)
// t.Miner (peer.ID) (string)
{
sval, err := cbg.ReadString(br)
if err != nil {
return err
}
t.Miner = peer.ID(sval)
}
// t.MinerWorker (address.Address) (struct)
{
if err := t.MinerWorker.UnmarshalCBOR(br); err != nil {
return err
}
}
// t.DealID (uint64) (uint64)
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.DealID = uint64(extra)
// t.PublishMessage (types.SignedMessage) (struct)
{
pb, err := br.PeekByte()
if err != nil {
return err
}
if pb == cbg.CborNull[0] {
var nbuf [1]byte
if _, err := br.Read(nbuf[:]); err != nil {
return err
}
} else {
t.PublishMessage = new(types.SignedMessage)
if err := t.PublishMessage.UnmarshalCBOR(br); err != nil {
return err
}
}
}
return nil
}
func (t *MinerDeal) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
if _, err := w.Write([]byte{135}); err != nil {
return err
}
// t.Client (peer.ID) (string)
if len(t.Client) > cbg.MaxLength {
return xerrors.Errorf("Value in field t.Client was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.Client)))); err != nil {
return err
}
if _, err := w.Write([]byte(t.Client)); err != nil {
return err
}
// t.Proposal (actors.StorageDealProposal) (struct)
if err := t.Proposal.MarshalCBOR(w); err != nil {
return err
}
// t.ProposalCid (cid.Cid) (struct)
if err := cbg.WriteCid(w, t.ProposalCid); err != nil {
return xerrors.Errorf("failed to write cid field t.ProposalCid: %w", err)
}
// t.State (uint64) (uint64)
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.State))); err != nil {
return err
}
// t.Ref (cid.Cid) (struct)
if err := cbg.WriteCid(w, t.Ref); err != nil {
return xerrors.Errorf("failed to write cid field t.Ref: %w", err)
}
// t.DealID (uint64) (uint64)
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.DealID))); err != nil {
return err
}
// t.SectorID (uint64) (uint64)
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SectorID))); err != nil {
return err
}
return nil
}
func (t *MinerDeal) UnmarshalCBOR(r io.Reader) error {
br := cbg.GetPeeker(r)
maj, extra, err := cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajArray {
return fmt.Errorf("cbor input should be of type array")
}
if extra != 7 {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.Client (peer.ID) (string)
{
sval, err := cbg.ReadString(br)
if err != nil {
return err
}
t.Client = peer.ID(sval)
}
// t.Proposal (actors.StorageDealProposal) (struct)
{
if err := t.Proposal.UnmarshalCBOR(br); err != nil {
return err
}
}
// t.ProposalCid (cid.Cid) (struct)
{
c, err := cbg.ReadCid(br)
if err != nil {
return xerrors.Errorf("failed to read cid field t.ProposalCid: %w", err)
}
t.ProposalCid = c
}
// t.State (uint64) (uint64)
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.State = uint64(extra)
// t.Ref (cid.Cid) (struct)
{
c, err := cbg.ReadCid(br)
if err != nil {
return xerrors.Errorf("failed to read cid field t.Ref: %w", err)
}
t.Ref = c
}
// t.DealID (uint64) (uint64)
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.DealID = uint64(extra)
// t.SectorID (uint64) (uint64)
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.SectorID = uint64(extra)
return nil
}
func (t *StorageDataTransferVoucher) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
if _, err := w.Write([]byte{130}); err != nil {
return err
}
// t.Proposal (cid.Cid) (struct)
if err := cbg.WriteCid(w, t.Proposal); err != nil {
return xerrors.Errorf("failed to write cid field t.Proposal: %w", err)
}
// t.DealID (uint64) (uint64)
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.DealID))); err != nil {
return err
}
return nil
}
func (t *StorageDataTransferVoucher) UnmarshalCBOR(r io.Reader) error {
br := cbg.GetPeeker(r)
maj, extra, err := cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajArray {
return fmt.Errorf("cbor input should be of type array")
}
if extra != 2 {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.Proposal (cid.Cid) (struct)
{
c, err := cbg.ReadCid(br)
if err != nil {
return xerrors.Errorf("failed to read cid field t.Proposal: %w", err)
}
t.Proposal = c
}
// t.DealID (uint64) (uint64)
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.DealID = uint64(extra)
return nil
}
-311
View File
@@ -1,311 +0,0 @@
package deals
import (
"context"
"github.com/ipfs/go-cid"
logging "github.com/ipfs/go-log"
"github.com/libp2p/go-libp2p-core/host"
inet "github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-cbor-util"
"github.com/filecoin-project/go-statestore"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/events"
"github.com/filecoin-project/lotus/chain/market"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/lotus/node/impl/full"
"github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/filecoin-project/lotus/retrieval/discovery"
)
var log = logging.Logger("deals")
type ClientDeal struct {
ProposalCid cid.Cid
Proposal actors.StorageDealProposal
State api.DealState
Miner peer.ID
MinerWorker address.Address
DealID uint64
PublishMessage *types.SignedMessage
s inet.Stream
}
type Client struct {
sm *stmgr.StateManager
chain *store.ChainStore
h host.Host
w *wallet.Wallet
// dataTransfer
// TODO: once the data transfer module is complete, the
// client will listen to events on the data transfer module
// Because we are using only a fake DAGService
// implementation, there's no validation or events on the client side
dataTransfer dtypes.ClientDataTransfer
dag dtypes.ClientDAG
discovery *discovery.Local
events *events.Events
fm *market.FundMgr
deals *statestore.StateStore
conns map[cid.Cid]inet.Stream
incoming chan *ClientDeal
updated chan clientDealUpdate
stop chan struct{}
stopped chan struct{}
}
type clientDealUpdate struct {
newState api.DealState
id cid.Cid
err error
mut func(*ClientDeal)
}
type clientApi struct {
full.ChainAPI
full.StateAPI
}
func NewClient(sm *stmgr.StateManager, chain *store.ChainStore, h host.Host, w *wallet.Wallet, dag dtypes.ClientDAG, dataTransfer dtypes.ClientDataTransfer, discovery *discovery.Local, fm *market.FundMgr, deals dtypes.ClientDealStore, chainapi full.ChainAPI, stateapi full.StateAPI) *Client {
c := &Client{
sm: sm,
chain: chain,
h: h,
w: w,
dataTransfer: dataTransfer,
dag: dag,
discovery: discovery,
fm: fm,
events: events.NewEvents(context.TODO(), &clientApi{chainapi, stateapi}),
deals: deals,
conns: map[cid.Cid]inet.Stream{},
incoming: make(chan *ClientDeal, 16),
updated: make(chan clientDealUpdate, 16),
stop: make(chan struct{}),
stopped: make(chan struct{}),
}
return c
}
func (c *Client) Run(ctx context.Context) {
go func() {
defer close(c.stopped)
for {
select {
case deal := <-c.incoming:
c.onIncoming(deal)
case update := <-c.updated:
c.onUpdated(ctx, update)
case <-c.stop:
return
}
}
}()
}
func (c *Client) onIncoming(deal *ClientDeal) {
log.Info("incoming deal")
if _, ok := c.conns[deal.ProposalCid]; ok {
log.Errorf("tracking deal connection: already tracking connection for deal %s", deal.ProposalCid)
return
}
c.conns[deal.ProposalCid] = deal.s
if err := c.deals.Begin(deal.ProposalCid, deal); err != nil {
// We may have re-sent the proposal
log.Errorf("deal tracking failed: %s", err)
c.failDeal(deal.ProposalCid, err)
return
}
go func() {
c.updated <- clientDealUpdate{
newState: api.DealUnknown,
id: deal.ProposalCid,
err: nil,
}
}()
}
func (c *Client) onUpdated(ctx context.Context, update clientDealUpdate) {
log.Infof("Client deal %s updated state to %s", update.id, api.DealStates[update.newState])
var deal ClientDeal
err := c.deals.Mutate(update.id, func(d *ClientDeal) error {
d.State = update.newState
if update.mut != nil {
update.mut(d)
}
deal = *d
return nil
})
if update.err != nil {
log.Errorf("deal %s failed: %s", update.id, update.err)
c.failDeal(update.id, update.err)
return
}
if err != nil {
c.failDeal(update.id, err)
return
}
switch update.newState {
case api.DealUnknown: // new
c.handle(ctx, deal, c.new, api.DealAccepted)
case api.DealAccepted:
c.handle(ctx, deal, c.accepted, api.DealStaged)
case api.DealStaged:
c.handle(ctx, deal, c.staged, api.DealSealing)
case api.DealSealing:
c.handle(ctx, deal, c.sealing, api.DealNoUpdate)
// TODO: DealComplete -> watch for faults, expiration, etc.
}
}
type ClientDealProposal struct {
Data cid.Cid
PricePerEpoch types.BigInt
ProposalExpiration uint64
Duration uint64
ProviderAddress address.Address
Client address.Address
MinerWorker address.Address
MinerID peer.ID
}
func (c *Client) Start(ctx context.Context, p ClientDealProposal) (cid.Cid, error) {
if err := c.fm.EnsureAvailable(ctx, p.Client, types.BigMul(p.PricePerEpoch, types.NewInt(p.Duration))); err != nil {
return cid.Undef, xerrors.Errorf("adding market funds failed: %w", err)
}
commP, pieceSize, err := c.commP(ctx, p.Data)
if err != nil {
return cid.Undef, xerrors.Errorf("computing commP failed: %w", err)
}
dealProposal := &actors.StorageDealProposal{
PieceRef: commP,
PieceSize: uint64(pieceSize),
Client: p.Client,
Provider: p.ProviderAddress,
ProposalExpiration: p.ProposalExpiration,
Duration: p.Duration,
StoragePricePerEpoch: p.PricePerEpoch,
StorageCollateral: types.NewInt(uint64(pieceSize)), // TODO: real calc
}
if err := api.SignWith(ctx, c.w.Sign, p.Client, dealProposal); err != nil {
return cid.Undef, xerrors.Errorf("signing deal proposal failed: %w", err)
}
proposalNd, err := cborutil.AsIpld(dealProposal)
if err != nil {
return cid.Undef, xerrors.Errorf("getting proposal node failed: %w", err)
}
s, err := c.h.NewStream(ctx, p.MinerID, DealProtocolID)
if err != nil {
return cid.Undef, xerrors.Errorf("connecting to storage provider failed: %w", err)
}
proposal := &Proposal{
DealProposal: dealProposal,
Piece: p.Data,
}
if err := cborutil.WriteCborRPC(s, proposal); err != nil {
s.Reset()
return cid.Undef, xerrors.Errorf("sending proposal to storage provider failed: %w", err)
}
deal := &ClientDeal{
ProposalCid: proposalNd.Cid(),
Proposal: *dealProposal,
State: api.DealUnknown,
Miner: p.MinerID,
MinerWorker: p.MinerWorker,
s: s,
}
c.incoming <- deal
return deal.ProposalCid, c.discovery.AddPeer(p.Data, discovery.RetrievalPeer{
Address: dealProposal.Provider,
ID: deal.Miner,
})
}
func (c *Client) QueryAsk(ctx context.Context, p peer.ID, a address.Address) (*types.SignedStorageAsk, error) {
s, err := c.h.NewStream(ctx, p, AskProtocolID)
if err != nil {
return nil, xerrors.Errorf("failed to open stream to miner: %w", err)
}
req := &AskRequest{
Miner: a,
}
if err := cborutil.WriteCborRPC(s, req); err != nil {
return nil, xerrors.Errorf("failed to send ask request: %w", err)
}
var out AskResponse
if err := cborutil.ReadCborRPC(s, &out); err != nil {
return nil, xerrors.Errorf("failed to read ask response: %w", err)
}
if out.Ask == nil {
return nil, xerrors.Errorf("got no ask back")
}
if out.Ask.Ask.Miner != a {
return nil, xerrors.Errorf("got back ask for wrong miner")
}
if err := c.checkAskSignature(out.Ask); err != nil {
return nil, xerrors.Errorf("ask was not properly signed")
}
return out.Ask, nil
}
func (c *Client) List() ([]ClientDeal, error) {
var out []ClientDeal
if err := c.deals.List(&out); err != nil {
return nil, err
}
return out, nil
}
func (c *Client) GetDeal(d cid.Cid) (*ClientDeal, error) {
var out ClientDeal
if err := c.deals.Get(d, &out); err != nil {
return nil, err
}
return &out, nil
}
func (c *Client) Stop() {
close(c.stop)
<-c.stopped
}
-233
View File
@@ -1,233 +0,0 @@
package deals
import (
"bytes"
"context"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-cbor-util"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types"
)
type clientHandlerFunc func(ctx context.Context, deal ClientDeal) (func(*ClientDeal), error)
func (c *Client) handle(ctx context.Context, deal ClientDeal, cb clientHandlerFunc, next api.DealState) {
go func() {
mut, err := cb(ctx, deal)
if err != nil {
next = api.DealError
}
if err == nil && next == api.DealNoUpdate {
return
}
select {
case c.updated <- clientDealUpdate{
newState: next,
id: deal.ProposalCid,
err: err,
mut: mut,
}:
case <-c.stop:
}
}()
}
func (c *Client) new(ctx context.Context, deal ClientDeal) (func(*ClientDeal), error) {
resp, err := c.readStorageDealResp(deal)
if err != nil {
return nil, err
}
// TODO: verify StorageDealSubmission
if err := c.disconnect(deal); err != nil {
return nil, err
}
/* data transfer happens */
if resp.State != api.DealAccepted {
return nil, xerrors.Errorf("deal wasn't accepted (State=%d)", resp.State)
}
return func(info *ClientDeal) {
info.PublishMessage = resp.StorageDealSubmission
}, nil
}
func (c *Client) accepted(ctx context.Context, deal ClientDeal) (func(*ClientDeal), error) {
log.Infow("DEAL ACCEPTED!")
pubmsg := deal.PublishMessage.Message
pw, err := stmgr.GetMinerWorker(ctx, c.sm, nil, deal.Proposal.Provider)
if err != nil {
return nil, xerrors.Errorf("getting miner worker failed: %w", err)
}
if pubmsg.From != pw {
return nil, xerrors.Errorf("deal wasn't published by storage provider: from=%s, provider=%s", pubmsg.From, deal.Proposal.Provider)
}
if pubmsg.To != actors.StorageMarketAddress {
return nil, xerrors.Errorf("deal publish message wasn't set to StorageMarket actor (to=%s)", pubmsg.To)
}
if pubmsg.Method != actors.SMAMethods.PublishStorageDeals {
return nil, xerrors.Errorf("deal publish message called incorrect method (method=%s)", pubmsg.Method)
}
var params actors.PublishStorageDealsParams
if err := params.UnmarshalCBOR(bytes.NewReader(pubmsg.Params)); err != nil {
return nil, err
}
dealIdx := -1
for i, storageDeal := range params.Deals {
// TODO: make it less hacky
sd := storageDeal
eq, err := cborutil.Equals(&deal.Proposal, &sd)
if err != nil {
return nil, err
}
if eq {
dealIdx = i
break
}
}
if dealIdx == -1 {
return nil, xerrors.Errorf("deal publish didn't contain our deal (message cid: %s)", deal.PublishMessage.Cid())
}
// TODO: timeout
_, ret, err := c.sm.WaitForMessage(ctx, deal.PublishMessage.Cid())
if err != nil {
return nil, xerrors.Errorf("waiting for deal publish message: %w", err)
}
if ret.ExitCode != 0 {
return nil, xerrors.Errorf("deal publish failed: exit=%d", ret.ExitCode)
}
var res actors.PublishStorageDealResponse
if err := res.UnmarshalCBOR(bytes.NewReader(ret.Return)); err != nil {
return nil, err
}
return func(info *ClientDeal) {
info.DealID = res.DealIDs[dealIdx]
}, nil
}
func (c *Client) staged(ctx context.Context, deal ClientDeal) (func(*ClientDeal), error) {
// TODO: Maybe wait for pre-commit
return nil, nil
}
func (c *Client) sealing(ctx context.Context, deal ClientDeal) (func(*ClientDeal), error) {
checkFunc := func(ts *types.TipSet) (done bool, more bool, err error) {
sd, err := stmgr.GetStorageDeal(ctx, c.sm, deal.DealID, ts)
if err != nil {
// TODO: This may be fine for some errors
return false, false, xerrors.Errorf("failed to look up deal on chain: %w", err)
}
if sd.ActivationEpoch > 0 {
select {
case c.updated <- clientDealUpdate{
newState: api.DealComplete,
id: deal.ProposalCid,
}:
case <-c.stop:
}
return true, false, nil
}
return false, true, nil
}
called := func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH uint64) (more bool, err error) {
defer func() {
if err != nil {
select {
case c.updated <- clientDealUpdate{
newState: api.DealComplete,
id: deal.ProposalCid,
err: xerrors.Errorf("handling applied event: %w", err),
}:
case <-c.stop:
}
}
}()
if msg == nil {
log.Error("timed out waiting for deal activation... what now?")
return false, nil
}
sd, err := stmgr.GetStorageDeal(ctx, c.sm, deal.DealID, ts)
if err != nil {
return false, xerrors.Errorf("failed to look up deal on chain: %w", err)
}
if sd.ActivationEpoch == 0 {
return false, xerrors.Errorf("deal wasn't active: deal=%d, parentState=%s, h=%d", deal.DealID, ts.ParentState(), ts.Height())
}
log.Infof("Storage deal %d activated at epoch %d", deal.DealID, sd.ActivationEpoch)
select {
case c.updated <- clientDealUpdate{
newState: api.DealComplete,
id: deal.ProposalCid,
}:
case <-c.stop:
}
return false, nil
}
revert := func(ctx context.Context, ts *types.TipSet) error {
log.Warn("deal activation reverted; TODO: actually handle this!")
// TODO: Just go back to DealSealing?
return nil
}
matchEvent := func(msg *types.Message) (bool, error) {
if msg.To != deal.Proposal.Provider {
return false, nil
}
if msg.Method != actors.MAMethods.ProveCommitSector {
return false, nil
}
var params actors.SectorProveCommitInfo
if err := params.UnmarshalCBOR(bytes.NewReader(msg.Params)); err != nil {
return false, err
}
var found bool
for _, dealID := range params.DealIDs {
if dealID == deal.DealID {
found = true
break
}
}
return found, nil
}
if err := c.events.Called(checkFunc, called, revert, 3, build.SealRandomnessLookbackLimit, matchEvent); err != nil {
return nil, xerrors.Errorf("failed to set up called handler")
}
return nil, nil
}
-171
View File
@@ -1,171 +0,0 @@
package deals
import (
"bytes"
"context"
"runtime"
sectorbuilder "github.com/filecoin-project/go-sectorbuilder"
"github.com/ipfs/go-cid"
files "github.com/ipfs/go-ipfs-files"
unixfile "github.com/ipfs/go-unixfs/file"
"github.com/ipld/go-ipld-prime"
"github.com/libp2p/go-libp2p-core/peer"
"golang.org/x/xerrors"
cborutil "github.com/filecoin-project/go-cbor-util"
"github.com/filecoin-project/go-statestore"
"github.com/filecoin-project/lotus/datatransfer"
"github.com/filecoin-project/lotus/lib/padreader"
"github.com/filecoin-project/lotus/node/modules/dtypes"
)
func (c *Client) failDeal(id cid.Cid, cerr error) {
if cerr == nil {
_, f, l, _ := runtime.Caller(1)
cerr = xerrors.Errorf("unknown error (fail called at %s:%d)", f, l)
}
s, ok := c.conns[id]
if ok {
_ = s.Reset()
delete(c.conns, id)
}
// TODO: store in some sort of audit log
log.Errorf("deal %s failed: %+v", id, cerr)
}
func (c *Client) commP(ctx context.Context, data cid.Cid) ([]byte, uint64, error) {
root, err := c.dag.Get(ctx, data)
if err != nil {
log.Errorf("failed to get file root for deal: %s", err)
return nil, 0, err
}
n, err := unixfile.NewUnixfsFile(ctx, c.dag, root)
if err != nil {
log.Errorf("cannot open unixfs file: %s", err)
return nil, 0, err
}
uf, ok := n.(files.File)
if !ok {
// TODO: we probably got directory, how should we handle this in unixfs mode?
return nil, 0, xerrors.New("unsupported unixfs type")
}
s, err := uf.Size()
if err != nil {
return nil, 0, err
}
pr, psize := padreader.New(uf, uint64(s))
commp, err := sectorbuilder.GeneratePieceCommitment(pr, psize)
if err != nil {
return nil, 0, xerrors.Errorf("generating CommP: %w", err)
}
return commp[:], psize, nil
}
func (c *Client) readStorageDealResp(deal ClientDeal) (*Response, error) {
s, ok := c.conns[deal.ProposalCid]
if !ok {
// TODO: Try to re-establish the connection using query protocol
return nil, xerrors.Errorf("no connection to miner")
}
var resp SignedResponse
if err := cborutil.ReadCborRPC(s, &resp); err != nil {
log.Errorw("failed to read Response message", "error", err)
return nil, err
}
if err := resp.Verify(deal.MinerWorker); err != nil {
return nil, xerrors.Errorf("verifying response signature failed", err)
}
if resp.Response.Proposal != deal.ProposalCid {
return nil, xerrors.Errorf("miner responded to a wrong proposal: %s != %s", resp.Response.Proposal, deal.ProposalCid)
}
return &resp.Response, nil
}
func (c *Client) disconnect(deal ClientDeal) error {
s, ok := c.conns[deal.ProposalCid]
if !ok {
return nil
}
err := s.Close()
delete(c.conns, deal.ProposalCid)
return err
}
var _ datatransfer.RequestValidator = &ClientRequestValidator{}
// ClientRequestValidator validates data transfer requests for the client
// in a storage market
type ClientRequestValidator struct {
deals *statestore.StateStore
}
// NewClientRequestValidator returns a new client request validator for the
// given datastore
func NewClientRequestValidator(deals dtypes.ClientDealStore) *ClientRequestValidator {
crv := &ClientRequestValidator{
deals: deals,
}
return crv
}
// ValidatePush validates a push request received from the peer that will send data
// Will always error because clients should not accept push requests from a provider
// in a storage deal (i.e. send data to client).
func (c *ClientRequestValidator) ValidatePush(
sender peer.ID,
voucher datatransfer.Voucher,
baseCid cid.Cid,
Selector ipld.Node) error {
return ErrNoPushAccepted
}
// ValidatePull validates a pull request received from the peer that will receive data
// Will succeed only if:
// - voucher has correct type
// - voucher references an active deal
// - referenced deal matches the receiver (miner)
// - referenced deal matches the given base CID
// - referenced deal is in an acceptable state
func (c *ClientRequestValidator) ValidatePull(
receiver peer.ID,
voucher datatransfer.Voucher,
baseCid cid.Cid,
Selector ipld.Node) error {
dealVoucher, ok := voucher.(*StorageDataTransferVoucher)
if !ok {
return xerrors.Errorf("voucher type %s: %w", voucher.Identifier(), ErrWrongVoucherType)
}
var deal ClientDeal
err := c.deals.Get(dealVoucher.Proposal, &deal)
if err != nil {
return xerrors.Errorf("Proposal CID %s: %w", dealVoucher.Proposal.String(), ErrNoDeal)
}
if deal.Miner != receiver {
return xerrors.Errorf("Deal Peer %s, Data Transfer Peer %s: %w", deal.Miner.String(), receiver.String(), ErrWrongPeer)
}
if !bytes.Equal(deal.Proposal.PieceRef, baseCid.Bytes()) {
return xerrors.Errorf("Deal Payload CID %s, Data Transfer CID %s: %w", string(deal.Proposal.PieceRef), baseCid.String(), ErrWrongPiece)
}
for _, state := range DataTransferStates {
if deal.State == state {
return nil
}
}
return xerrors.Errorf("Deal State %s: %w", deal.State, ErrInacceptableDealState)
}
-294
View File
@@ -1,294 +0,0 @@
package deals
import (
"context"
"errors"
"sync"
cid "github.com/ipfs/go-cid"
datastore "github.com/ipfs/go-datastore"
"github.com/ipfs/go-datastore/namespace"
inet "github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-cbor-util"
"github.com/filecoin-project/go-statestore"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/datatransfer"
"github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/filecoin-project/lotus/storage"
"github.com/filecoin-project/lotus/storage/sectorblocks"
)
var ProviderDsPrefix = "/deals/provider"
type MinerDeal struct {
Client peer.ID
Proposal actors.StorageDealProposal
ProposalCid cid.Cid
State api.DealState
Ref cid.Cid
DealID uint64
SectorID uint64 // Set when State >= DealStaged
s inet.Stream
}
type Provider struct {
pricePerByteBlock types.BigInt // how much we want for storing one byte for one block
minPieceSize uint64
ask *types.SignedStorageAsk
askLk sync.Mutex
secb *sectorblocks.SectorBlocks
sminer *storage.Miner
full api.FullNode
// TODO: This will go away once storage market module + CAR
// is implemented
dag dtypes.StagingDAG
// dataTransfer is the manager of data transfers used by this storage provider
dataTransfer dtypes.ProviderDataTransfer
deals *statestore.StateStore
ds dtypes.MetadataDS
conns map[cid.Cid]inet.Stream
actor address.Address
incoming chan MinerDeal
updated chan minerDealUpdate
stop chan struct{}
stopped chan struct{}
}
type minerDealUpdate struct {
newState api.DealState
id cid.Cid
err error
mut func(*MinerDeal)
}
var (
// ErrDataTransferFailed means a data transfer for a deal failed
ErrDataTransferFailed = errors.New("deal data transfer failed")
)
func NewProvider(ds dtypes.MetadataDS, sminer *storage.Miner, secb *sectorblocks.SectorBlocks, dag dtypes.StagingDAG, dataTransfer dtypes.ProviderDataTransfer, fullNode api.FullNode) (*Provider, error) {
addr, err := ds.Get(datastore.NewKey("miner-address"))
if err != nil {
return nil, err
}
minerAddress, err := address.NewFromBytes(addr)
if err != nil {
return nil, err
}
h := &Provider{
sminer: sminer,
dag: dag,
dataTransfer: dataTransfer,
full: fullNode,
secb: secb,
pricePerByteBlock: types.NewInt(3), // TODO: allow setting
minPieceSize: 256, // TODO: allow setting (BUT KEEP MIN 256! (because of how we fill sectors up))
conns: map[cid.Cid]inet.Stream{},
incoming: make(chan MinerDeal),
updated: make(chan minerDealUpdate),
stop: make(chan struct{}),
stopped: make(chan struct{}),
actor: minerAddress,
deals: statestore.New(namespace.Wrap(ds, datastore.NewKey(ProviderDsPrefix))),
ds: ds,
}
if err := h.tryLoadAsk(); err != nil {
return nil, err
}
if h.ask == nil {
// TODO: we should be fine with this state, and just say it means 'not actively accepting deals'
// for now... lets just set a price
if err := h.SetPrice(types.NewInt(500_000_000), 1000000); err != nil {
return nil, xerrors.Errorf("failed setting a default price: %w", err)
}
}
// register a data transfer event handler -- this will move deals from
// accepted to staged
h.dataTransfer.SubscribeToEvents(h.onDataTransferEvent)
return h, nil
}
func (p *Provider) Run(ctx context.Context) {
// TODO: restore state
go func() {
defer log.Warn("quitting deal provider loop")
defer close(p.stopped)
for {
select {
case deal := <-p.incoming: // DealAccepted
p.onIncoming(deal)
case update := <-p.updated: // DealStaged
p.onUpdated(ctx, update)
case <-p.stop:
return
}
}
}()
}
func (p *Provider) onIncoming(deal MinerDeal) {
log.Info("incoming deal")
p.conns[deal.ProposalCid] = deal.s
if err := p.deals.Begin(deal.ProposalCid, &deal); err != nil {
// This can happen when client re-sends proposal
p.failDeal(deal.ProposalCid, err)
log.Errorf("deal tracking failed: %s", err)
return
}
go func() {
p.updated <- minerDealUpdate{
newState: api.DealAccepted,
id: deal.ProposalCid,
err: nil,
}
}()
}
func (p *Provider) onUpdated(ctx context.Context, update minerDealUpdate) {
log.Infof("Deal %s updated state to %s", update.id, api.DealStates[update.newState])
if update.err != nil {
log.Errorf("deal %s (newSt: %d) failed: %+v", update.id, update.newState, update.err)
p.failDeal(update.id, update.err)
return
}
var deal MinerDeal
err := p.deals.Mutate(update.id, func(d *MinerDeal) error {
d.State = update.newState
if update.mut != nil {
update.mut(d)
}
deal = *d
return nil
})
if err != nil {
p.failDeal(update.id, err)
return
}
switch update.newState {
case api.DealAccepted:
p.handle(ctx, deal, p.accept, api.DealNoUpdate)
case api.DealStaged:
p.handle(ctx, deal, p.staged, api.DealSealing)
case api.DealSealing:
p.handle(ctx, deal, p.sealing, api.DealComplete)
case api.DealComplete:
p.handle(ctx, deal, p.complete, api.DealNoUpdate)
}
}
// onDataTransferEvent is the function called when an event occurs in a data
// transfer -- it reads the voucher to verify this even occurred in a storage
// market deal, then, based on the data transfer event that occurred, it generates
// and update message for the deal -- either moving to staged for a completion
// event or moving to error if a data transfer error occurs
func (p *Provider) onDataTransferEvent(event datatransfer.Event, channelState datatransfer.ChannelState) {
voucher, ok := channelState.Voucher().(*StorageDataTransferVoucher)
// if this event is for a transfer not related to storage, ignore
if !ok {
return
}
// data transfer events for opening and progress do not affect deal state
var next api.DealState
var err error
var mut func(*MinerDeal)
switch event {
case datatransfer.Complete:
next = api.DealStaged
mut = func(deal *MinerDeal) {
deal.DealID = voucher.DealID
}
case datatransfer.Error:
next = api.DealFailed
err = ErrDataTransferFailed
default:
// the only events we care about are complete and error
return
}
select {
case p.updated <- minerDealUpdate{
newState: next,
id: voucher.Proposal,
err: err,
mut: mut,
}:
case <-p.stop:
}
}
func (p *Provider) newDeal(s inet.Stream, proposal Proposal) (MinerDeal, error) {
proposalNd, err := cborutil.AsIpld(proposal.DealProposal)
if err != nil {
return MinerDeal{}, err
}
return MinerDeal{
Client: s.Conn().RemotePeer(),
Proposal: *proposal.DealProposal,
ProposalCid: proposalNd.Cid(),
State: api.DealUnknown,
Ref: proposal.Piece,
s: s,
}, nil
}
func (p *Provider) HandleStream(s inet.Stream) {
log.Info("Handling storage deal proposal!")
proposal, err := p.readProposal(s)
if err != nil {
log.Error(err)
s.Close()
return
}
deal, err := p.newDeal(s, proposal)
if err != nil {
log.Errorf("%+v", err)
s.Close()
return
}
p.incoming <- deal
}
func (p *Provider) Stop() {
close(p.stop)
<-p.stopped
}
-160
View File
@@ -1,160 +0,0 @@
package deals
import (
"bytes"
"context"
"time"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-cbor-util"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types"
datastore "github.com/ipfs/go-datastore"
inet "github.com/libp2p/go-libp2p-core/network"
"golang.org/x/xerrors"
)
func (p *Provider) SetPrice(price types.BigInt, ttlsecs int64) error {
p.askLk.Lock()
defer p.askLk.Unlock()
var seqno uint64
if p.ask != nil {
seqno = p.ask.Ask.SeqNo + 1
}
now := time.Now().Unix()
ask := &types.StorageAsk{
Price: price,
Timestamp: uint64(now),
Expiry: uint64(now + ttlsecs),
Miner: p.actor,
SeqNo: seqno,
MinPieceSize: p.minPieceSize,
}
ssa, err := p.signAsk(ask)
if err != nil {
return err
}
return p.saveAsk(ssa)
}
func (p *Provider) getAsk(m address.Address) *types.SignedStorageAsk {
p.askLk.Lock()
defer p.askLk.Unlock()
if m != p.actor {
return nil
}
return p.ask
}
func (p *Provider) HandleAskStream(s inet.Stream) {
defer s.Close()
var ar AskRequest
if err := cborutil.ReadCborRPC(s, &ar); err != nil {
log.Errorf("failed to read AskRequest from incoming stream: %s", err)
return
}
resp := p.processAskRequest(&ar)
if err := cborutil.WriteCborRPC(s, resp); err != nil {
log.Errorf("failed to write ask response: %s", err)
return
}
}
func (p *Provider) processAskRequest(ar *AskRequest) *AskResponse {
return &AskResponse{
Ask: p.getAsk(ar.Miner),
}
}
var bestAskKey = datastore.NewKey("latest-ask")
func (p *Provider) tryLoadAsk() error {
p.askLk.Lock()
defer p.askLk.Unlock()
err := p.loadAsk()
if err != nil {
if xerrors.Is(err, datastore.ErrNotFound) {
log.Warn("no previous ask found, miner will not accept deals until a price is set")
return nil
}
return err
}
return nil
}
func (p *Provider) loadAsk() error {
askb, err := p.ds.Get(datastore.NewKey("latest-ask"))
if err != nil {
return xerrors.Errorf("failed to load most recent ask from disk: %w", err)
}
var ssa types.SignedStorageAsk
if err := cborutil.ReadCborRPC(bytes.NewReader(askb), &ssa); err != nil {
return err
}
p.ask = &ssa
return nil
}
func (p *Provider) signAsk(a *types.StorageAsk) (*types.SignedStorageAsk, error) {
b, err := cborutil.Dump(a)
if err != nil {
return nil, err
}
worker, err := p.getWorker(p.actor)
if err != nil {
return nil, xerrors.Errorf("failed to get worker to sign ask: %w", err)
}
sig, err := p.full.WalletSign(context.TODO(), worker, b)
if err != nil {
return nil, err
}
return &types.SignedStorageAsk{
Ask: a,
Signature: sig,
}, nil
}
func (p *Provider) saveAsk(a *types.SignedStorageAsk) error {
b, err := cborutil.Dump(a)
if err != nil {
return err
}
if err := p.ds.Put(bestAskKey, b); err != nil {
return err
}
p.ask = a
return nil
}
func (c *Client) checkAskSignature(ask *types.SignedStorageAsk) error {
tss := c.sm.ChainStore().GetHeaviestTipSet().ParentState()
w, err := stmgr.GetMinerWorkerRaw(context.TODO(), c.sm, tss, ask.Ask.Miner)
if err != nil {
return xerrors.Errorf("failed to get worker for miner in ask", err)
}
sigb, err := cborutil.Dump(ask.Ask)
if err != nil {
return xerrors.Errorf("failed to re-serialize ask")
}
return ask.Signature.Verify(w, sigb)
}
-215
View File
@@ -1,215 +0,0 @@
package deals
import (
"bytes"
"context"
ipldfree "github.com/ipld/go-ipld-prime/impl/free"
"github.com/ipld/go-ipld-prime/traversal/selector"
"github.com/ipld/go-ipld-prime/traversal/selector/builder"
unixfile "github.com/ipfs/go-unixfs/file"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/padreader"
"github.com/filecoin-project/lotus/storage/sectorblocks"
)
type providerHandlerFunc func(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error)
func (p *Provider) handle(ctx context.Context, deal MinerDeal, cb providerHandlerFunc, next api.DealState) {
go func() {
mut, err := cb(ctx, deal)
if err == nil && next == api.DealNoUpdate {
return
}
select {
case p.updated <- minerDealUpdate{
newState: next,
id: deal.ProposalCid,
err: err,
mut: mut,
}:
case <-p.stop:
}
}()
}
// ACCEPTED
func (p *Provider) accept(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) {
head, err := p.full.ChainHead(ctx)
if err != nil {
return nil, err
}
if head.Height() >= deal.Proposal.ProposalExpiration {
return nil, xerrors.Errorf("deal proposal already expired")
}
// TODO: check StorageCollateral
minPrice := types.BigDiv(types.BigMul(p.ask.Ask.Price, types.NewInt(deal.Proposal.PieceSize)), types.NewInt(1<<30))
if deal.Proposal.StoragePricePerEpoch.LessThan(minPrice) {
return nil, xerrors.Errorf("storage price per epoch less than asking price: %s < %s", deal.Proposal.StoragePricePerEpoch, minPrice)
}
if deal.Proposal.PieceSize < p.ask.Ask.MinPieceSize {
return nil, xerrors.Errorf("piece size less than minimum required size: %d < %d", deal.Proposal.PieceSize, p.ask.Ask.MinPieceSize)
}
// check market funds
clientMarketBalance, err := p.full.StateMarketBalance(ctx, deal.Proposal.Client, nil)
if err != nil {
return nil, xerrors.Errorf("getting client market balance failed: %w", err)
}
// This doesn't guarantee that the client won't withdraw / lock those funds
// but it's a decent first filter
if clientMarketBalance.Available.LessThan(deal.Proposal.TotalStoragePrice()) {
return nil, xerrors.New("clientMarketBalance.Available too small")
}
waddr, err := p.full.StateMinerWorker(ctx, deal.Proposal.Provider, nil)
if err != nil {
return nil, err
}
// TODO: check StorageCollateral (may be too large (or too small))
if err := p.full.MarketEnsureAvailable(ctx, waddr, deal.Proposal.StorageCollateral); err != nil {
return nil, err
}
log.Info("publishing deal")
params, err := actors.SerializeParams(&actors.PublishStorageDealsParams{
Deals: []actors.StorageDealProposal{deal.Proposal},
})
if err != nil {
return nil, xerrors.Errorf("serializing PublishStorageDeals params failed: ", err)
}
// TODO: We may want this to happen after fetching data
smsg, err := p.full.MpoolPushMessage(ctx, &types.Message{
To: actors.StorageMarketAddress,
From: waddr,
Value: types.NewInt(0),
GasPrice: types.NewInt(0),
GasLimit: types.NewInt(1000000),
Method: actors.SMAMethods.PublishStorageDeals,
Params: params,
})
if err != nil {
return nil, err
}
r, err := p.full.StateWaitMsg(ctx, smsg.Cid())
if err != nil {
return nil, err
}
if r.Receipt.ExitCode != 0 {
return nil, xerrors.Errorf("publishing deal failed: exit %d", r.Receipt.ExitCode)
}
var resp actors.PublishStorageDealResponse
if err := resp.UnmarshalCBOR(bytes.NewReader(r.Receipt.Return)); err != nil {
return nil, err
}
if len(resp.DealIDs) != 1 {
return nil, xerrors.Errorf("got unexpected number of DealIDs from SMA")
}
log.Infof("fetching data for a deal %d", resp.DealIDs[0])
err = p.sendSignedResponse(&Response{
State: api.DealAccepted,
Proposal: deal.ProposalCid,
StorageDealSubmission: smsg,
})
if err != nil {
return nil, err
}
if err := p.disconnect(deal); err != nil {
log.Warnf("closing client connection: %+v", err)
}
ssb := builder.NewSelectorSpecBuilder(ipldfree.NodeBuilder())
// this is the selector for "get the whole DAG"
// TODO: support storage deals with custom payload selectors
allSelector := ssb.ExploreRecursive(selector.RecursionLimitNone(),
ssb.ExploreAll(ssb.ExploreRecursiveEdge())).Node()
// initiate a pull data transfer. This will complete asynchronously and the
// completion of the data transfer will trigger a change in deal state
// (see onDataTransferEvent)
_, err = p.dataTransfer.OpenPullDataChannel(ctx,
deal.Client,
&StorageDataTransferVoucher{Proposal: deal.ProposalCid, DealID: resp.DealIDs[0]},
deal.Ref,
allSelector,
)
if err != nil {
return nil, xerrors.Errorf("failed to open pull data channel: %w", err)
}
return nil, nil
}
// STAGED
func (p *Provider) staged(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) {
root, err := p.dag.Get(ctx, deal.Ref)
if err != nil {
return nil, xerrors.Errorf("failed to get file root for deal: %s", err)
}
// TODO: abstract this away into ReadSizeCloser + implement different modes
n, err := unixfile.NewUnixfsFile(ctx, p.dag, root)
if err != nil {
return nil, xerrors.Errorf("cannot open unixfs file: %s", err)
}
uf, ok := n.(sectorblocks.UnixfsReader)
if !ok {
// we probably got directory, unsupported for now
return nil, xerrors.Errorf("unsupported unixfs file type")
}
// TODO: uf.Size() is user input, not trusted
// This won't be useful / here after we migrate to putting CARs into sectors
size, err := uf.Size()
if err != nil {
return nil, xerrors.Errorf("getting unixfs file size: %w", err)
}
if padreader.PaddedSize(uint64(size)) != deal.Proposal.PieceSize {
return nil, xerrors.Errorf("deal.Proposal.PieceSize didn't match padded unixfs file size")
}
sectorID, err := p.secb.AddUnixfsPiece(ctx, uf, deal.DealID)
if err != nil {
return nil, xerrors.Errorf("AddPiece failed: %s", err)
}
log.Warnf("New Sector: %d (deal %d)", sectorID, deal.DealID)
return func(deal *MinerDeal) {
deal.SectorID = sectorID
}, nil
}
// SEALING
func (p *Provider) sealing(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) {
// TODO: consider waiting for seal to happen
return nil, nil
}
func (p *Provider) complete(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) {
// TODO: observe sector lifecycle, status, expiration..
return nil, nil
}
-198
View File
@@ -1,198 +0,0 @@
package deals
import (
"bytes"
"context"
"runtime"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/datatransfer"
"github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/ipld/go-ipld-prime"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-cbor-util"
"github.com/filecoin-project/go-statestore"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
"github.com/ipfs/go-cid"
inet "github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
"golang.org/x/xerrors"
)
func (p *Provider) failDeal(id cid.Cid, cerr error) {
if err := p.deals.End(id); err != nil {
log.Warnf("deals.End: %s", err)
}
if cerr == nil {
_, f, l, _ := runtime.Caller(1)
cerr = xerrors.Errorf("unknown error (fail called at %s:%d)", f, l)
}
log.Warnf("deal %s failed: %s", id, cerr)
err := p.sendSignedResponse(&Response{
State: api.DealFailed,
Message: cerr.Error(),
Proposal: id,
})
s, ok := p.conns[id]
if ok {
_ = s.Reset()
delete(p.conns, id)
}
if err != nil {
log.Warnf("notifying client about deal failure: %s", err)
}
}
func (p *Provider) readProposal(s inet.Stream) (proposal Proposal, err error) {
if err := cborutil.ReadCborRPC(s, &proposal); err != nil {
log.Errorw("failed to read proposal message", "error", err)
return proposal, err
}
if err := proposal.DealProposal.Verify(); err != nil {
return proposal, xerrors.Errorf("verifying StorageDealProposal: %w", err)
}
if proposal.DealProposal.Provider != p.actor {
log.Errorf("proposal with wrong ProviderAddress: %s", proposal.DealProposal.Provider)
return proposal, err
}
return
}
func (p *Provider) sendSignedResponse(resp *Response) error {
s, ok := p.conns[resp.Proposal]
if !ok {
return xerrors.New("couldn't send response: not connected")
}
msg, err := cborutil.Dump(resp)
if err != nil {
return xerrors.Errorf("serializing response: %w", err)
}
worker, err := p.getWorker(p.actor)
if err != nil {
return err
}
sig, err := p.full.WalletSign(context.TODO(), worker, msg)
if err != nil {
return xerrors.Errorf("failed to sign response message: %w", err)
}
signedResponse := &SignedResponse{
Response: *resp,
Signature: sig,
}
err = cborutil.WriteCborRPC(s, signedResponse)
if err != nil {
// Assume client disconnected
s.Close()
delete(p.conns, resp.Proposal)
}
return err
}
func (p *Provider) disconnect(deal MinerDeal) error {
s, ok := p.conns[deal.ProposalCid]
if !ok {
return nil
}
err := s.Close()
delete(p.conns, deal.ProposalCid)
return err
}
func (p *Provider) getWorker(miner address.Address) (address.Address, error) {
getworker := &types.Message{
To: miner,
From: miner,
Method: actors.MAMethods.GetWorkerAddr,
}
r, err := p.full.StateCall(context.TODO(), getworker, nil)
if err != nil {
return address.Undef, xerrors.Errorf("getting worker address: %w", err)
}
if r.ExitCode != 0 {
return address.Undef, xerrors.Errorf("getWorker call failed: %d", r.ExitCode)
}
return address.NewFromBytes(r.Return)
}
var _ datatransfer.RequestValidator = &ProviderRequestValidator{}
// ProviderRequestValidator validates data transfer requests for the provider
// in a storage market
type ProviderRequestValidator struct {
deals *statestore.StateStore
}
// NewProviderRequestValidator returns a new client request validator for the
// given datastore
func NewProviderRequestValidator(deals dtypes.ProviderDealStore) *ProviderRequestValidator {
return &ProviderRequestValidator{
deals: deals,
}
}
// ValidatePush validates a push request received from the peer that will send data
// Will succeed only if:
// - voucher has correct type
// - voucher references an active deal
// - referenced deal matches the client
// - referenced deal matches the given base CID
// - referenced deal is in an acceptable state
func (m *ProviderRequestValidator) ValidatePush(
sender peer.ID,
voucher datatransfer.Voucher,
baseCid cid.Cid,
Selector ipld.Node) error {
dealVoucher, ok := voucher.(*StorageDataTransferVoucher)
if !ok {
return xerrors.Errorf("voucher type %s: %w", voucher.Identifier(), ErrWrongVoucherType)
}
var deal MinerDeal
err := m.deals.Get(dealVoucher.Proposal, &deal)
if err != nil {
return xerrors.Errorf("Proposal CID %s: %w", dealVoucher.Proposal.String(), ErrNoDeal)
}
if deal.Client != sender {
return xerrors.Errorf("Deal Peer %s, Data Transfer Peer %s: %w", deal.Client.String(), sender.String(), ErrWrongPeer)
}
if !bytes.Equal(deal.Proposal.PieceRef, baseCid.Bytes()) {
return xerrors.Errorf("Deal Payload CID %s, Data Transfer CID %s: %w", string(deal.Proposal.PieceRef), baseCid.String(), ErrWrongPiece)
}
for _, state := range DataTransferStates {
if deal.State == state {
return nil
}
}
return xerrors.Errorf("Deal State %s: %w", deal.State, ErrInacceptableDealState)
}
// ValidatePull validates a pull request received from the peer that will receive data.
// Will always error because providers should not accept pull requests from a client
// in a storage deal (i.e. send data to client).
func (m *ProviderRequestValidator) ValidatePull(
receiver peer.ID,
voucher datatransfer.Voucher,
baseCid cid.Cid,
Selector ipld.Node) error {
return ErrNoPullAccepted
}
-291
View File
@@ -1,291 +0,0 @@
package deals_test
import (
"fmt"
"math/rand"
"testing"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
"github.com/ipfs/go-datastore/namespace"
dss "github.com/ipfs/go-datastore/sync"
blocksutil "github.com/ipfs/go-ipfs-blocksutil"
"github.com/libp2p/go-libp2p-core/peer"
xerrors "golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-cbor-util"
"github.com/filecoin-project/go-statestore"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/deals"
"github.com/filecoin-project/lotus/chain/types"
)
var blockGenerator = blocksutil.NewBlockGenerator()
type wrongDTType struct {
}
func (wrongDTType) ToBytes() ([]byte, error) {
return []byte{}, nil
}
func (wrongDTType) FromBytes([]byte) error {
return fmt.Errorf("not implemented")
}
func (wrongDTType) Identifier() string {
return "WrongDTTYPE"
}
func uniqueStorageDealProposal() (actors.StorageDealProposal, error) {
clientAddr, err := address.NewIDAddress(uint64(rand.Int()))
if err != nil {
return actors.StorageDealProposal{}, err
}
providerAddr, err := address.NewIDAddress(uint64(rand.Int()))
if err != nil {
return actors.StorageDealProposal{}, err
}
return actors.StorageDealProposal{
PieceRef: blockGenerator.Next().Cid().Bytes(),
Client: clientAddr,
Provider: providerAddr,
ProposerSignature: &types.Signature{
Data: []byte("foo bar cat dog"),
Type: types.KTBLS,
},
}, nil
}
func newClientDeal(minerID peer.ID, state api.DealState) (deals.ClientDeal, error) {
newProposal, err := uniqueStorageDealProposal()
if err != nil {
return deals.ClientDeal{}, err
}
proposalNd, err := cborutil.AsIpld(&newProposal)
if err != nil {
return deals.ClientDeal{}, err
}
minerAddr, err := address.NewIDAddress(uint64(rand.Int()))
if err != nil {
return deals.ClientDeal{}, err
}
return deals.ClientDeal{
Proposal: newProposal,
ProposalCid: proposalNd.Cid(),
Miner: minerID,
MinerWorker: minerAddr,
State: state,
}, nil
}
func newMinerDeal(clientID peer.ID, state api.DealState) (deals.MinerDeal, error) {
newProposal, err := uniqueStorageDealProposal()
if err != nil {
return deals.MinerDeal{}, err
}
proposalNd, err := cborutil.AsIpld(&newProposal)
if err != nil {
return deals.MinerDeal{}, err
}
ref, err := cid.Cast(newProposal.PieceRef)
if err != nil {
return deals.MinerDeal{}, err
}
return deals.MinerDeal{
Proposal: newProposal,
ProposalCid: proposalNd.Cid(),
Client: clientID,
State: state,
Ref: ref,
}, nil
}
func TestClientRequestValidation(t *testing.T) {
ds := dss.MutexWrap(datastore.NewMapDatastore())
state := statestore.New(namespace.Wrap(ds, datastore.NewKey("/deals/client")))
crv := deals.NewClientRequestValidator(state)
minerID := peer.ID("fakepeerid")
block := blockGenerator.Next()
t.Run("ValidatePush fails", func(t *testing.T) {
if !xerrors.Is(crv.ValidatePush(minerID, wrongDTType{}, block.Cid(), nil), deals.ErrNoPushAccepted) {
t.Fatal("Push should fail for the client request validator for storage deals")
}
})
t.Run("ValidatePull fails deal not found", func(t *testing.T) {
proposal, err := uniqueStorageDealProposal()
if err != nil {
t.Fatal("error creating proposal")
}
proposalNd, err := cborutil.AsIpld(&proposal)
if err != nil {
t.Fatal("error serializing proposal")
}
pieceRef, err := cid.Cast(proposal.PieceRef)
if err != nil {
t.Fatal("unable to construct piece cid")
}
if !xerrors.Is(crv.ValidatePull(minerID, &deals.StorageDataTransferVoucher{proposalNd.Cid(), 1}, pieceRef, nil), deals.ErrNoDeal) {
t.Fatal("Pull should fail if there is no deal stored")
}
})
t.Run("ValidatePull fails wrong client", func(t *testing.T) {
otherMiner := peer.ID("otherminer")
clientDeal, err := newClientDeal(otherMiner, api.DealAccepted)
if err != nil {
t.Fatal("error creating client deal")
}
if err := state.Begin(clientDeal.ProposalCid, &clientDeal); err != nil {
t.Fatal("deal tracking failed")
}
pieceRef, err := cid.Cast(clientDeal.Proposal.PieceRef)
if err != nil {
t.Fatal("unable to construct piece cid")
}
if !xerrors.Is(crv.ValidatePull(minerID, &deals.StorageDataTransferVoucher{clientDeal.ProposalCid, 1}, pieceRef, nil), deals.ErrWrongPeer) {
t.Fatal("Pull should fail if miner address is incorrect")
}
})
t.Run("ValidatePull fails wrong piece ref", func(t *testing.T) {
clientDeal, err := newClientDeal(minerID, api.DealAccepted)
if err != nil {
t.Fatal("error creating client deal")
}
if err := state.Begin(clientDeal.ProposalCid, &clientDeal); err != nil {
t.Fatal("deal tracking failed")
}
if !xerrors.Is(crv.ValidatePull(minerID, &deals.StorageDataTransferVoucher{clientDeal.ProposalCid, 1}, blockGenerator.Next().Cid(), nil), deals.ErrWrongPiece) {
t.Fatal("Pull should fail if piece ref is incorrect")
}
})
t.Run("ValidatePull fails wrong deal state", func(t *testing.T) {
clientDeal, err := newClientDeal(minerID, api.DealComplete)
if err != nil {
t.Fatal("error creating client deal")
}
if err := state.Begin(clientDeal.ProposalCid, &clientDeal); err != nil {
t.Fatal("deal tracking failed")
}
pieceRef, err := cid.Cast(clientDeal.Proposal.PieceRef)
if err != nil {
t.Fatal("unable to construct piece cid")
}
if !xerrors.Is(crv.ValidatePull(minerID, &deals.StorageDataTransferVoucher{clientDeal.ProposalCid, 1}, pieceRef, nil), deals.ErrInacceptableDealState) {
t.Fatal("Pull should fail if deal is in a state that cannot be data transferred")
}
})
t.Run("ValidatePull succeeds", func(t *testing.T) {
clientDeal, err := newClientDeal(minerID, api.DealAccepted)
if err != nil {
t.Fatal("error creating client deal")
}
if err := state.Begin(clientDeal.ProposalCid, &clientDeal); err != nil {
t.Fatal("deal tracking failed")
}
pieceRef, err := cid.Cast(clientDeal.Proposal.PieceRef)
if err != nil {
t.Fatal("unable to construct piece cid")
}
if crv.ValidatePull(minerID, &deals.StorageDataTransferVoucher{clientDeal.ProposalCid, 1}, pieceRef, nil) != nil {
t.Fatal("Pull should should succeed when all parameters are correct")
}
})
}
func TestProviderRequestValidation(t *testing.T) {
ds := dss.MutexWrap(datastore.NewMapDatastore())
state := statestore.New(namespace.Wrap(ds, datastore.NewKey("/deals/client")))
mrv := deals.NewProviderRequestValidator(state)
clientID := peer.ID("fakepeerid")
block := blockGenerator.Next()
t.Run("ValidatePull fails", func(t *testing.T) {
if !xerrors.Is(mrv.ValidatePull(clientID, wrongDTType{}, block.Cid(), nil), deals.ErrNoPullAccepted) {
t.Fatal("Pull should fail for the provider request validator for storage deals")
}
})
t.Run("ValidatePush fails deal not found", func(t *testing.T) {
proposal, err := uniqueStorageDealProposal()
if err != nil {
t.Fatal("error creating proposal")
}
proposalNd, err := cborutil.AsIpld(&proposal)
if err != nil {
t.Fatal("error serializing proposal")
}
pieceRef, err := cid.Cast(proposal.PieceRef)
if err != nil {
t.Fatal("unable to construct piece cid")
}
if !xerrors.Is(mrv.ValidatePush(clientID, &deals.StorageDataTransferVoucher{proposalNd.Cid(), 1}, pieceRef, nil), deals.ErrNoDeal) {
t.Fatal("Push should fail if there is no deal stored")
}
})
t.Run("ValidatePush fails wrong miner", func(t *testing.T) {
otherClient := peer.ID("otherclient")
minerDeal, err := newMinerDeal(otherClient, api.DealAccepted)
if err != nil {
t.Fatal("error creating client deal")
}
if err := state.Begin(minerDeal.ProposalCid, &minerDeal); err != nil {
t.Fatal("deal tracking failed")
}
pieceRef, err := cid.Cast(minerDeal.Proposal.PieceRef)
if err != nil {
t.Fatal("unable to construct piece cid")
}
if !xerrors.Is(mrv.ValidatePush(clientID, &deals.StorageDataTransferVoucher{minerDeal.ProposalCid, 1}, pieceRef, nil), deals.ErrWrongPeer) {
t.Fatal("Push should fail if miner address is incorrect")
}
})
t.Run("ValidatePush fails wrong piece ref", func(t *testing.T) {
minerDeal, err := newMinerDeal(clientID, api.DealAccepted)
if err != nil {
t.Fatal("error creating client deal")
}
if err := state.Begin(minerDeal.ProposalCid, &minerDeal); err != nil {
t.Fatal("deal tracking failed")
}
if !xerrors.Is(mrv.ValidatePush(clientID, &deals.StorageDataTransferVoucher{minerDeal.ProposalCid, 1}, blockGenerator.Next().Cid(), nil), deals.ErrWrongPiece) {
t.Fatal("Push should fail if piece ref is incorrect")
}
})
t.Run("ValidatePush fails wrong deal state", func(t *testing.T) {
minerDeal, err := newMinerDeal(clientID, api.DealComplete)
if err != nil {
t.Fatal("error creating client deal")
}
if err := state.Begin(minerDeal.ProposalCid, &minerDeal); err != nil {
t.Fatal("deal tracking failed")
}
pieceRef, err := cid.Cast(minerDeal.Proposal.PieceRef)
if err != nil {
t.Fatal("unable to construct piece cid")
}
if !xerrors.Is(mrv.ValidatePush(clientID, &deals.StorageDataTransferVoucher{minerDeal.ProposalCid, 1}, pieceRef, nil), deals.ErrInacceptableDealState) {
t.Fatal("Push should fail if deal is in a state that cannot be data transferred")
}
})
t.Run("ValidatePush succeeds", func(t *testing.T) {
minerDeal, err := newMinerDeal(clientID, api.DealAccepted)
if err != nil {
t.Fatal("error creating client deal")
}
if err := state.Begin(minerDeal.ProposalCid, &minerDeal); err != nil {
t.Fatal("deal tracking failed")
}
pieceRef, err := cid.Cast(minerDeal.Proposal.PieceRef)
if err != nil {
t.Fatal("unable to construct piece cid")
}
if mrv.ValidatePush(clientID, &deals.StorageDataTransferVoucher{minerDeal.ProposalCid, 1}, pieceRef, nil) != nil {
t.Fatal("Push should should succeed when all parameters are correct")
}
})
}
-114
View File
@@ -1,114 +0,0 @@
package deals
import (
"bytes"
"errors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-cbor-util"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
"github.com/ipfs/go-cid"
)
var (
// ErrWrongVoucherType means the voucher was not the correct type can validate against
ErrWrongVoucherType = errors.New("cannot validate voucher type.")
// ErrNoPushAccepted just means clients do not accept pushes for storage deals
ErrNoPushAccepted = errors.New("client should not receive data for a storage deal.")
// ErrNoPullAccepted just means providers do not accept pulls for storage deals
ErrNoPullAccepted = errors.New("provider should not send data for a storage deal.")
// ErrNoDeal means no active deal was found for this vouchers proposal cid
ErrNoDeal = errors.New("no deal found for this proposal.")
// ErrWrongPeer means that the other peer for this data transfer request does not match
// the other peer for the deal
ErrWrongPeer = errors.New("data Transfer peer id and Deal peer id do not match.")
// ErrWrongPiece means that the pieceref for this data transfer request does not match
// the one specified in the deal
ErrWrongPiece = errors.New("base CID for deal does not match CID for piece.")
// ErrInacceptableDealState means the deal for this transfer is not in a deal state
// where transfer can be performed
ErrInacceptableDealState = errors.New("deal is not a in a state where deals are accepted.")
// DataTransferStates are the states in which it would make sense to actually start a data transfer
DataTransferStates = []api.DealState{api.DealAccepted, api.DealUnknown}
)
const DealProtocolID = "/fil/storage/mk/1.0.1"
const AskProtocolID = "/fil/storage/ask/1.0.1"
type Proposal struct {
DealProposal *actors.StorageDealProposal
Piece cid.Cid // Used for retrieving from the client
}
type Response struct {
State api.DealState
// DealProposalRejected
Message string
Proposal cid.Cid
// DealAccepted
StorageDealSubmission *types.SignedMessage
}
// TODO: Do we actually need this to be signed?
type SignedResponse struct {
Response Response
Signature *types.Signature
}
func (r *SignedResponse) Verify(addr address.Address) error {
b, err := cborutil.Dump(&r.Response)
if err != nil {
return err
}
return r.Signature.Verify(addr, b)
}
type AskRequest struct {
Miner address.Address
}
type AskResponse struct {
Ask *types.SignedStorageAsk
}
// StorageDataTransferVoucher is the voucher type for data transfers
// used by the storage market
type StorageDataTransferVoucher struct {
Proposal cid.Cid
DealID uint64
}
// ToBytes converts the StorageDataTransferVoucher to raw bytes
func (dv *StorageDataTransferVoucher) ToBytes() ([]byte, error) {
var buf bytes.Buffer
err := dv.MarshalCBOR(&buf)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// FromBytes converts the StorageDataTransferVoucher to raw bytes
func (dv *StorageDataTransferVoucher) FromBytes(raw []byte) error {
r := bytes.NewReader(raw)
return dv.UnmarshalCBOR(r)
}
// Identifier is the unique string identifier for a StorageDataTransferVoucher
func (dv *StorageDataTransferVoucher) Identifier() string {
return "StorageDataTransferVoucher"
}
+4 -4
View File
@@ -6,7 +6,7 @@ import (
"time"
"github.com/ipfs/go-cid"
logging "github.com/ipfs/go-log"
logging "github.com/ipfs/go-log/v2"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
@@ -33,10 +33,10 @@ type heightHandler struct {
type eventApi interface {
ChainNotify(context.Context) (<-chan []*store.HeadChange, error)
ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error)
ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error)
StateGetReceipt(context.Context, cid.Cid, *types.TipSet) (*types.MessageReceipt, error)
ChainGetTipSetByHeight(context.Context, uint64, types.TipSetKey) (*types.TipSet, error)
StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error)
StateGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error) // optional / for CalledMsg
StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) // optional / for CalledMsg
}
type Events struct {
+1 -1
View File
@@ -192,7 +192,7 @@ func (e *calledEvents) applyWithConfidence(ts *types.TipSet) {
continue
}
rec, err := e.cs.StateGetReceipt(e.ctx, event.msg.Cid(), ts)
rec, err := e.cs.StateGetReceipt(e.ctx, event.msg.Cid(), ts.Key())
if err != nil {
log.Error(err)
return
+3 -3
View File
@@ -40,15 +40,15 @@ type fakeCS struct {
sub func(rev, app []*types.TipSet)
}
func (fcs *fakeCS) StateGetReceipt(context.Context, cid.Cid, *types.TipSet) (*types.MessageReceipt, error) {
func (fcs *fakeCS) StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error) {
return nil, nil
}
func (fcs *fakeCS) StateGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error) {
func (fcs *fakeCS) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) {
panic("Not Implemented")
}
func (fcs *fakeCS) ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error) {
func (fcs *fakeCS) ChainGetTipSetByHeight(context.Context, uint64, types.TipSetKey) (*types.TipSet, error) {
panic("Not Implemented")
}
+3 -3
View File
@@ -8,7 +8,7 @@ import (
"github.com/filecoin-project/lotus/chain/types"
)
type tsByHFunc func(context.Context, uint64, *types.TipSet) (*types.TipSet, error)
type tsByHFunc func(context.Context, uint64, types.TipSetKey) (*types.TipSet, error)
// tipSetCache implements a simple ring-buffer cache to keep track of recent
// tipsets
@@ -93,7 +93,7 @@ func (tsc *tipSetCache) getNonNull(height uint64) (*types.TipSet, error) {
func (tsc *tipSetCache) get(height uint64) (*types.TipSet, error) {
if tsc.len == 0 {
log.Warnf("tipSetCache.get: cache is empty, requesting from storage (h=%d)", height)
return tsc.storage(context.TODO(), height, nil)
return tsc.storage(context.TODO(), height, types.EmptyTSK)
}
headH := tsc.cache[tsc.start].Height()
@@ -113,7 +113,7 @@ func (tsc *tipSetCache) get(height uint64) (*types.TipSet, error) {
if height < tail.Height() {
log.Warnf("tipSetCache.get: requested tipset not in cache, requesting from storage (h=%d; tail=%d)", height, tail.Height())
return tsc.storage(context.TODO(), height, tail)
return tsc.storage(context.TODO(), height, tail.Key())
}
return tsc.cache[normalModulo(tsc.start-int(headH-height), clen)], nil
+2 -2
View File
@@ -11,7 +11,7 @@ import (
)
func TestTsCache(t *testing.T) {
tsc := newTSCache(50, func(context.Context, uint64, *types.TipSet) (*types.TipSet, error) {
tsc := newTSCache(50, func(context.Context, uint64, types.TipSetKey) (*types.TipSet, error) {
t.Fatal("storage call")
return &types.TipSet{}, nil
})
@@ -54,7 +54,7 @@ func TestTsCache(t *testing.T) {
}
func TestTsCacheNulls(t *testing.T) {
tsc := newTSCache(50, func(context.Context, uint64, *types.TipSet) (*types.TipSet, error) {
tsc := newTSCache(50, func(context.Context, uint64, types.TipSetKey) (*types.TipSet, error) {
t.Fatal("storage call")
return &types.TipSet{}, nil
})
+2 -2
View File
@@ -13,7 +13,7 @@ func (e *calledEvents) CheckMsg(ctx context.Context, smsg store.ChainMsg, hnd Ca
msg := smsg.VMMessage()
return func(ts *types.TipSet) (done bool, more bool, err error) {
fa, err := e.cs.StateGetActor(ctx, msg.From, ts)
fa, err := e.cs.StateGetActor(ctx, msg.From, ts.Key())
if err != nil {
return false, true, err
}
@@ -23,7 +23,7 @@ func (e *calledEvents) CheckMsg(ctx context.Context, smsg store.ChainMsg, hnd Ca
return false, true, nil
}
rec, err := e.cs.StateGetReceipt(ctx, smsg.VMMessage().Cid(), ts)
rec, err := e.cs.StateGetReceipt(ctx, smsg.VMMessage().Cid(), ts.Key())
if err != nil {
return false, true, xerrors.Errorf("getting receipt in CheckMsg: %w", err)
}
+68 -30
View File
@@ -9,32 +9,33 @@ import (
"io/ioutil"
"sync/atomic"
ffi "github.com/filecoin-project/filecoin-ffi"
sectorbuilder "github.com/filecoin-project/go-sectorbuilder"
block "github.com/ipfs/go-block-format"
"github.com/ipfs/go-blockservice"
"github.com/ipfs/go-car"
"github.com/ipfs/go-cid"
blockstore "github.com/ipfs/go-ipfs-blockstore"
offline "github.com/ipfs/go-ipfs-exchange-offline"
logging "github.com/ipfs/go-log/v2"
"github.com/ipfs/go-merkledag"
peer "github.com/libp2p/go-libp2p-core/peer"
"go.opencensus.io/trace"
"golang.org/x/xerrors"
ffi "github.com/filecoin-project/filecoin-ffi"
"github.com/filecoin-project/go-address"
sectorbuilder "github.com/filecoin-project/go-sectorbuilder"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm"
"github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/lotus/cmd/lotus-seed/seed"
"github.com/filecoin-project/lotus/genesis"
"github.com/filecoin-project/lotus/lib/sigs"
"github.com/filecoin-project/lotus/node/repo"
block "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
blockstore "github.com/ipfs/go-ipfs-blockstore"
logging "github.com/ipfs/go-log"
"go.opencensus.io/trace"
"golang.org/x/xerrors"
)
var log = logging.Logger("gen")
@@ -55,6 +56,8 @@ type ChainGen struct {
Timestamper func(*types.TipSet, uint64) uint64
GetMessages func(*ChainGen) ([]*types.SignedMessage, error)
w *wallet.Wallet
eppProvs map[address.Address]ElectionPoStProver
@@ -170,7 +173,9 @@ func NewGenerator() (*ChainGen, error) {
MinerAddrs: []address.Address{maddr1, maddr2},
}
genb, err := MakeGenesisBlock(bs, map[address.Address]types.BigInt{
sys := vm.Syscalls(sectorbuilder.ProofVerifier)
genb, err := MakeGenesisBlock(bs, sys, map[address.Address]types.BigInt{
mk1: types.FromFil(40000),
mk2: types.FromFil(40000),
banker: types.FromFil(50000),
@@ -179,7 +184,7 @@ func NewGenerator() (*ChainGen, error) {
return nil, xerrors.Errorf("make genesis block failed: %w", err)
}
cs := store.NewChainStore(bs, ds)
cs := store.NewChainStore(bs, ds, sys)
genfb := &types.FullBlock{Header: genb.Genesis}
gents := store.NewFullTipSet([]*types.FullBlock{genfb})
@@ -207,10 +212,11 @@ func NewGenerator() (*ChainGen, error) {
genesis: genb.Genesis,
w: w,
Miners: minercfg.MinerAddrs,
eppProvs: mgen,
banker: banker,
receivers: receievers,
GetMessages: getRandomMessages,
Miners: minercfg.MinerAddrs,
eppProvs: mgen,
banker: banker,
receivers: receievers,
CurTipset: gents,
@@ -221,6 +227,14 @@ func NewGenerator() (*ChainGen, error) {
return gen, nil
}
func (cg *ChainGen) SetStateManager(sm *stmgr.StateManager) {
cg.sm = sm
}
func (cg *ChainGen) ChainStore() *store.ChainStore {
return cg.cs
}
func (cg *ChainGen) Genesis() *types.BlockHeader {
return cg.genesis
}
@@ -292,7 +306,7 @@ func (cg *ChainGen) NextTipSet() (*MinedTipSet, error) {
func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Address) (*MinedTipSet, error) {
var blks []*types.FullBlock
msgs, err := cg.getRandomMessages()
msgs, err := cg.GetMessages(cg)
if err != nil {
return nil, xerrors.Errorf("get random messages: %w", err)
}
@@ -356,7 +370,15 @@ func (cg *ChainGen) ResyncBankerNonce(ts *types.TipSet) error {
return nil
}
func (cg *ChainGen) getRandomMessages() ([]*types.SignedMessage, error) {
func (cg *ChainGen) Banker() address.Address {
return cg.banker
}
func (cg *ChainGen) Wallet() *wallet.Wallet {
return cg.w
}
func getRandomMessages(cg *ChainGen) ([]*types.SignedMessage, error) {
msgs := make([]*types.SignedMessage, cg.msgsPerBlock)
for m := range msgs {
msg := types.Message{
@@ -397,13 +419,13 @@ func (cg *ChainGen) YieldRepo() (repo.Repo, error) {
type MiningCheckAPI interface {
ChainGetRandomness(context.Context, types.TipSetKey, int64) ([]byte, error)
StateMinerPower(context.Context, address.Address, *types.TipSet) (api.MinerPower, error)
StateMinerPower(context.Context, address.Address, types.TipSetKey) (api.MinerPower, error)
StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error)
StateMinerWorker(context.Context, address.Address, types.TipSetKey) (address.Address, error)
StateMinerSectorSize(context.Context, address.Address, *types.TipSet) (uint64, error)
StateMinerSectorSize(context.Context, address.Address, types.TipSetKey) (uint64, error)
StateMinerProvingSet(context.Context, address.Address, *types.TipSet) ([]*api.ChainSectorInfo, error)
StateMinerProvingSet(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error)
WalletSign(context.Context, address.Address, []byte) (*types.Signature, error)
}
@@ -417,7 +439,11 @@ func (mca mca) ChainGetRandomness(ctx context.Context, pts types.TipSetKey, lb i
return mca.sm.ChainStore().GetRandomness(ctx, pts.Cids(), int64(lb))
}
func (mca mca) StateMinerPower(ctx context.Context, maddr address.Address, ts *types.TipSet) (api.MinerPower, error) {
func (mca mca) StateMinerPower(ctx context.Context, maddr address.Address, tsk types.TipSetKey) (api.MinerPower, error) {
ts, err := mca.sm.ChainStore().LoadTipSet(tsk)
if err != nil {
return api.MinerPower{}, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
mpow, tpow, err := stmgr.GetPower(ctx, mca.sm, ts, maddr)
if err != nil {
return api.MinerPower{}, err
@@ -429,15 +455,27 @@ func (mca mca) StateMinerPower(ctx context.Context, maddr address.Address, ts *t
}, err
}
func (mca mca) StateMinerWorker(ctx context.Context, maddr address.Address, ts *types.TipSet) (address.Address, error) {
func (mca mca) StateMinerWorker(ctx context.Context, maddr address.Address, tsk types.TipSetKey) (address.Address, error) {
ts, err := mca.sm.ChainStore().LoadTipSet(tsk)
if err != nil {
return address.Undef, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return stmgr.GetMinerWorkerRaw(ctx, mca.sm, ts.ParentState(), maddr)
}
func (mca mca) StateMinerSectorSize(ctx context.Context, maddr address.Address, ts *types.TipSet) (uint64, error) {
func (mca mca) StateMinerSectorSize(ctx context.Context, maddr address.Address, tsk types.TipSetKey) (uint64, error) {
ts, err := mca.sm.ChainStore().LoadTipSet(tsk)
if err != nil {
return 0, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return stmgr.GetMinerSectorSize(ctx, mca.sm, ts, maddr)
}
func (mca mca) StateMinerProvingSet(ctx context.Context, maddr address.Address, ts *types.TipSet) ([]*api.ChainSectorInfo, error) {
func (mca mca) StateMinerProvingSet(ctx context.Context, maddr address.Address, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) {
ts, err := mca.sm.ChainStore().LoadTipSet(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return stmgr.GetMinerProvingSet(ctx, mca.sm, ts, maddr)
}
@@ -481,7 +519,7 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner add
return nil, xerrors.Errorf("chain get randomness: %w", err)
}
mworker, err := a.StateMinerWorker(ctx, miner, ts)
mworker, err := a.StateMinerWorker(ctx, miner, ts.Key())
if err != nil {
return nil, xerrors.Errorf("failed to get miner worker: %w", err)
}
@@ -491,7 +529,7 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner add
return nil, xerrors.Errorf("failed to compute VRF: %w", err)
}
pset, err := a.StateMinerProvingSet(ctx, miner, ts)
pset, err := a.StateMinerProvingSet(ctx, miner, ts.Key())
if err != nil {
return nil, xerrors.Errorf("failed to load proving set for miner: %w", err)
}
@@ -516,12 +554,12 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner add
return nil, xerrors.Errorf("failed to generate electionPoSt candidates: %w", err)
}
pow, err := a.StateMinerPower(ctx, miner, ts)
pow, err := a.StateMinerPower(ctx, miner, ts.Key())
if err != nil {
return nil, xerrors.Errorf("failed to check power: %w", err)
}
ssize, err := a.StateMinerSectorSize(ctx, miner, ts)
ssize, err := a.StateMinerSectorSize(ctx, miner, ts.Key())
if err != nil {
return nil, xerrors.Errorf("failed to look up miners sector size: %w", err)
}
@@ -608,7 +646,7 @@ func VerifyVRF(ctx context.Context, worker, miner address.Address, p uint64, inp
Data: vrfproof,
}
if err := sig.Verify(worker, vrfBase); err != nil {
if err := sigs.Verify(sig, worker, vrfBase); err != nil {
return xerrors.Errorf("vrf was invalid: %w", err)
}
+2
View File
@@ -4,6 +4,8 @@ import (
"testing"
"github.com/filecoin-project/lotus/build"
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
)
func init() {
+6 -6
View File
@@ -254,7 +254,7 @@ func SetupStorageMarketActor(bs bstore.Blockstore, sroot cid.Cid, deals []actors
return cid.Undef, xerrors.Errorf("set storage market actor: %w", err)
}
return state.Flush()
return state.Flush(context.TODO())
}
type GenMinerCfg struct {
@@ -275,7 +275,7 @@ func mustEnc(i cbg.CBORMarshaler) []byte {
}
func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid, gmcfg *GenMinerCfg) (cid.Cid, []actors.StorageDealProposal, error) {
vm, err := vm.NewVM(sroot, 0, nil, actors.NetworkAddress, cs.Blockstore())
vm, err := vm.NewVM(sroot, 0, nil, actors.NetworkAddress, cs.Blockstore(), cs.VMSys())
if err != nil {
return cid.Undef, nil, xerrors.Errorf("failed to create NewVM: %w", err)
}
@@ -555,7 +555,7 @@ func doExecValue(ctx context.Context, vm *vm.VM, to, from address.Address, value
return ret.Return, nil
}
func MakeGenesisBlock(bs bstore.Blockstore, balances map[address.Address]types.BigInt, gmcfg *GenMinerCfg, ts uint64) (*GenesisBootstrap, error) {
func MakeGenesisBlock(bs bstore.Blockstore, sys *types.VMSyscalls, balances map[address.Address]types.BigInt, gmcfg *GenMinerCfg, ts uint64) (*GenesisBootstrap, error) {
ctx := context.Background()
state, err := MakeInitialStateTree(bs, balances)
@@ -563,13 +563,13 @@ func MakeGenesisBlock(bs bstore.Blockstore, balances map[address.Address]types.B
return nil, xerrors.Errorf("make initial state tree failed: %w", err)
}
stateroot, err := state.Flush()
stateroot, err := state.Flush(ctx)
if err != nil {
return nil, xerrors.Errorf("flush state tree failed: %w", err)
}
// temp chainstore
cs := store.NewChainStore(bs, datastore.NewMapDatastore())
cs := store.NewChainStore(bs, datastore.NewMapDatastore(), sys)
stateroot, deals, err := SetupStorageMiners(ctx, cs, stateroot, gmcfg)
if err != nil {
return nil, xerrors.Errorf("setup storage miners failed: %w", err)
@@ -673,5 +673,5 @@ func AdjustInitActorStartID(ctx context.Context, bs blockstore.Blockstore, state
return cid.Undef, err
}
return tree.Flush()
return tree.Flush(ctx)
}
+4 -3
View File
@@ -13,7 +13,7 @@ import (
"github.com/ipfs/go-datastore"
"github.com/ipfs/go-datastore/namespace"
"github.com/ipfs/go-datastore/query"
logging "github.com/ipfs/go-log"
logging "github.com/ipfs/go-log/v2"
pubsub "github.com/libp2p/go-libp2p-pubsub"
lps "github.com/whyrusleeping/pubsub"
"go.uber.org/multierr"
@@ -25,6 +25,7 @@ import (
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/sigs"
"github.com/filecoin-project/lotus/node/modules/dtypes"
)
@@ -94,7 +95,7 @@ func (ms *msgSet) add(m *types.SignedMessage) error {
if _, has := ms.msgs[m.Message.Nonce]; has {
if m.Cid() != ms.msgs[m.Message.Nonce].Cid() {
log.Error("Add with duplicate nonce")
return xerrors.Errorf("message to %s with nonce %d already in mpool")
return xerrors.Errorf("message to %s with nonce %d already in mpool", m.Message.To, m.Message.Nonce)
}
}
ms.msgs[m.Message.Nonce] = m
@@ -303,7 +304,7 @@ func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet) error
return ErrMessageValueTooHigh
}
if err := m.Signature.Verify(m.Message.From, m.Message.Cid().Bytes()); err != nil {
if err := sigs.Verify(&m.Signature, m.Message.From, m.Message.Cid().Bytes()); err != nil {
log.Warnf("mpooladd signature verification failed: %s", err)
return err
}
+2
View File
@@ -9,6 +9,8 @@ import (
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/mock"
"github.com/filecoin-project/lotus/chain/wallet"
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
)
+2 -2
View File
@@ -6,7 +6,7 @@ import (
"time"
"github.com/ipfs/go-cid"
logging "github.com/ipfs/go-log"
logging "github.com/ipfs/go-log/v2"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"go.uber.org/fx"
@@ -95,7 +95,7 @@ func sendHeadNotifs(ctx context.Context, ps *pubsub.PubSub, topic string, chain
case notif := <-notifs:
n := notif[len(notif)-1]
w, err := chain.ChainTipSetWeight(ctx, n.Val)
w, err := chain.ChainTipSetWeight(ctx, n.Val.Key())
if err != nil {
return err
}
+14 -7
View File
@@ -6,7 +6,8 @@ import (
"github.com/ipfs/go-cid"
hamt "github.com/ipfs/go-hamt-ipld"
logging "github.com/ipfs/go-log"
logging "github.com/ipfs/go-log/v2"
"go.opencensus.io/trace"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
@@ -116,23 +117,29 @@ func (st *StateTree) GetActor(addr address.Address) (*types.Actor, error) {
return &act, nil
}
func (st *StateTree) Flush() (cid.Cid, error) {
func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) {
ctx, span := trace.StartSpan(ctx, "stateTree.Flush")
defer span.End()
for addr, act := range st.actorcache {
if err := st.root.Set(context.TODO(), string(addr.Bytes()), act); err != nil {
if err := st.root.Set(ctx, string(addr.Bytes()), act); err != nil {
return cid.Undef, err
}
}
st.actorcache = make(map[address.Address]*types.Actor)
if err := st.root.Flush(context.TODO()); err != nil {
if err := st.root.Flush(ctx); err != nil {
return cid.Undef, err
}
return st.Store.Put(context.TODO(), st.root)
return st.Store.Put(ctx, st.root)
}
func (st *StateTree) Snapshot() error {
ss, err := st.Flush()
func (st *StateTree) Snapshot(ctx context.Context) error {
ctx, span := trace.StartSpan(ctx, "stateTree.SnapShot")
defer span.End()
ss, err := st.Flush(ctx)
if err != nil {
return err
}
+3 -2
View File
@@ -1,6 +1,7 @@
package state
import (
"context"
"testing"
address "github.com/filecoin-project/go-address"
@@ -60,7 +61,7 @@ func BenchmarkStateTreeSetFlush(b *testing.B) {
if err != nil {
b.Fatal(err)
}
if _, err := st.Flush(); err != nil {
if _, err := st.Flush(context.TODO()); err != nil {
b.Fatal(err)
}
}
@@ -88,7 +89,7 @@ func BenchmarkStateTree10kGetActor(b *testing.B) {
}
}
if _, err := st.Flush(); err != nil {
if _, err := st.Flush(context.TODO()); err != nil {
b.Fatal(err)
}
+10 -4
View File
@@ -8,17 +8,18 @@ import (
"go.opencensus.io/trace"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm"
)
func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate cid.Cid, r vm.Rand, bheight uint64) (*types.MessageReceipt, error) {
func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate cid.Cid, r vm.Rand, bheight uint64) (*api.MethodCall, error) {
ctx, span := trace.StartSpan(ctx, "statemanager.CallRaw")
defer span.End()
vmi, err := vm.NewVM(bstate, bheight, r, actors.NetworkAddress, sm.cs.Blockstore())
vmi, err := vm.NewVM(bstate, bheight, r, actors.NetworkAddress, sm.cs.Blockstore(), sm.cs.VMSys())
if err != nil {
return nil, xerrors.Errorf("failed to set up vm: %w", err)
}
@@ -54,14 +55,19 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate
return nil, xerrors.Errorf("apply message failed: %w", err)
}
var errs string
if ret.ActorErr != nil {
errs = ret.ActorErr.Error()
log.Warnf("chain call failed: %s", ret.ActorErr)
}
return &ret.MessageReceipt, nil
return &api.MethodCall{
MessageReceipt: ret.MessageReceipt,
Error: errs,
}, nil
}
func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) {
func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.MethodCall, error) {
if ts == nil {
ts = sm.cs.GetHeaviestTipSet()
}
-127
View File
@@ -1,127 +0,0 @@
package stmgr
import (
"context"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-amt-ipld"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-hamt-ipld"
cbor "github.com/ipfs/go-ipld-cbor"
"github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/types"
)
func (sm *StateManager) forkNoPowerEPS(ctx context.Context, pstate cid.Cid) (cid.Cid, error) {
cst := hamt.CSTFromBstore(sm.cs.Blockstore())
st, err := state.LoadStateTree(cst, pstate)
if err != nil {
return cid.Undef, xerrors.Errorf("loading parent state tree: %w", err)
}
if err := st.MutateActor(actors.StoragePowerAddress, func(spa *types.Actor) error {
var head actors.StoragePowerState
if err := cst.Get(ctx, spa.Head, &head); err != nil {
return xerrors.Errorf("reading StoragePower state: %w", err)
}
buckets, err := amt.LoadAMT(amt.WrapBlockstore(sm.cs.Blockstore()), head.ProvingBuckets)
if err != nil {
return xerrors.Errorf("opening proving buckets AMT: %w", err)
}
fixedBuckets := map[uint64]map[address.Address]struct{}{}
if err := buckets.ForEach(func(bucketId uint64, ent *typegen.Deferred) error {
var bcid cid.Cid
if err := cbor.DecodeInto(ent.Raw, &bcid); err != nil {
return xerrors.Errorf("decoding bucket cid: %w", err)
}
bucket, err := hamt.LoadNode(ctx, cst, bcid)
if err != nil {
return xerrors.Errorf("loading bucket hamt: %w", err)
}
return bucket.ForEach(ctx, func(abytes string, _ interface{}) error {
addr, err := address.NewFromBytes([]byte(abytes))
if err != nil {
return xerrors.Errorf("parsing address in proving bucket: %w", err)
}
// now find the correct bucket
miner, err := st.GetActor(addr)
if err != nil {
return xerrors.Errorf("getting miner %s: %w", addr, err)
}
var minerHead actors.StorageMinerActorState
if err := cst.Get(ctx, miner.Head, &minerHead); err != nil {
return xerrors.Errorf("reading miner %s state: %w", addr, err)
}
correctBucket := minerHead.ElectionPeriodStart % build.SlashablePowerDelay
if correctBucket != bucketId {
log.Warnf("miner %s was in wrong proving bucket %d, putting in %d (eps: %d)", addr, bucketId, correctBucket, minerHead.ElectionPeriodStart)
}
if _, ok := fixedBuckets[correctBucket]; !ok {
fixedBuckets[correctBucket] = map[address.Address]struct{}{}
}
fixedBuckets[correctBucket][addr] = struct{}{}
return nil
})
}); err != nil {
return err
}
// /////
// Write fixed buckets
fixed := amt.NewAMT(amt.WrapBlockstore(sm.cs.Blockstore()))
for bucketId, addrss := range fixedBuckets {
bucket := hamt.NewNode(cst)
for addr := range addrss {
if err := bucket.Set(ctx, string(addr.Bytes()), actors.CborNull); err != nil {
return xerrors.Errorf("setting address in bucket: %w", err)
}
}
if err := bucket.Flush(ctx); err != nil {
return xerrors.Errorf("flushing bucket amt: %w", err)
}
bcid, err := cst.Put(context.TODO(), bucket)
if err != nil {
return xerrors.Errorf("put bucket: %w", err)
}
if err := fixed.Set(bucketId, bcid); err != nil {
return xerrors.Errorf("set bucket: %w", err)
}
}
head.ProvingBuckets, err = fixed.Flush()
if err != nil {
return xerrors.Errorf("flushing bucket amt: %w", err)
}
spa.Head, err = cst.Put(ctx, &head)
if err != nil {
return xerrors.Errorf("putting actor head: %w", err)
}
return nil
}); err != nil {
return cid.Undef, err
}
return st.Flush()
}
+209 -8
View File
@@ -2,24 +2,225 @@ package stmgr
import (
"context"
"github.com/ipfs/go-cid"
"golang.org/x/xerrors"
amt "github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/types"
"github.com/ipfs/go-cid"
hamt "github.com/ipfs/go-hamt-ipld"
blockstore "github.com/ipfs/go-ipfs-blockstore"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
)
var ForksAtHeight = map[uint64]func(context.Context, *StateManager, cid.Cid) (cid.Cid, error){
build.ForkBlizzardHeight: func(ctx context.Context, sm *StateManager, pstate cid.Cid) (cid.Cid, error) {
log.Warnw("Executing blizzard fork logic")
nstate, err := fixBlizzardAMTBug(ctx, sm, pstate)
if err != nil {
return cid.Undef, xerrors.Errorf("blizzard bug fix failed: %w", err)
}
return nstate, nil
},
build.ForkFrigidHeight: func(ctx context.Context, sm *StateManager, pstate cid.Cid) (cid.Cid, error) {
log.Warnw("Executing frigid fork logic")
nstate, err := fixBlizzardAMTBug(ctx, sm, pstate)
if err != nil {
return cid.Undef, xerrors.Errorf("frigid bug fix failed: %w", err)
}
return nstate, nil
},
build.ForkBootyBayHeight: func(ctx context.Context, sm *StateManager, pstate cid.Cid) (cid.Cid, error) {
log.Warnw("Executing booty bay fork logic")
nstate, err := fixBlizzardAMTBug(ctx, sm, pstate)
if err != nil {
return cid.Undef, xerrors.Errorf("booty bay bug fix failed: %w", err)
}
return nstate, nil
},
build.ForkMissingSnowballs: func(ctx context.Context, sm *StateManager, pstate cid.Cid) (cid.Cid, error) {
log.Warnw("Adding more snow to the world")
nstate, err := fixTooFewSnowballs(ctx, sm, pstate)
if err != nil {
return cid.Undef, xerrors.Errorf("missing snowballs bug fix failed: %w", err)
}
return nstate, nil
},
}
func (sm *StateManager) handleStateForks(ctx context.Context, pstate cid.Cid, height, parentH uint64) (_ cid.Cid, err error) {
for i := parentH; i < height; i++ {
switch i {
case build.ForkNoPowerEPSUpdates:
pstate, err = sm.forkNoPowerEPS(ctx, pstate)
f, ok := ForksAtHeight[i]
if ok {
nstate, err := f(ctx, sm, pstate)
if err != nil {
return cid.Undef, xerrors.Errorf("executing state fork in epoch %d: %w", i, err)
return cid.Undef, err
}
log.Infof("forkNoPowerEPS state: %s", pstate)
pstate = nstate
}
}
return pstate, nil
}
func fixTooFewSnowballs(ctx context.Context, sm *StateManager, pstate cid.Cid) (cid.Cid, error) {
cst := hamt.CSTFromBstore(sm.cs.Blockstore())
st, err := state.LoadStateTree(cst, pstate)
if err != nil {
return cid.Undef, err
}
spa, err := st.GetActor(actors.StoragePowerAddress)
if err != nil {
return cid.Undef, xerrors.Errorf("failed to get storage power actor: %w", err)
}
var spast actors.StoragePowerState
if err := cst.Get(ctx, spa.Head, &spast); err != nil {
return cid.Undef, err
}
miners, err := actors.MinerSetList(ctx, cst, spast.Miners)
if err != nil {
return cid.Undef, err
}
sum := types.NewInt(0)
for _, m := range miners {
mact, err := st.GetActor(m)
if err != nil {
return cid.Undef, xerrors.Errorf("getting miner actor to fix: %w", err)
}
var mstate actors.StorageMinerActorState
if err := cst.Get(ctx, mact.Head, &mstate); err != nil {
return cid.Undef, xerrors.Errorf("failed to load miner actor state: %w", err)
}
if mstate.SlashedAt != 0 {
continue
}
sum = types.BigAdd(sum, mstate.Power)
}
spast.TotalStorage = sum
nspahead, err := cst.Put(ctx, &spast)
if err != nil {
return cid.Undef, err
}
spa.Head = nspahead
return st.Flush(ctx)
}
/*
1) Iterate through each miner in the chain:
1.1) Fixup their sector set and proving set
1.2) Change their code cid to point to the new miner actor code
*/
func fixBlizzardAMTBug(ctx context.Context, sm *StateManager, pstate cid.Cid) (cid.Cid, error) {
cst := hamt.CSTFromBstore(sm.cs.Blockstore())
st, err := state.LoadStateTree(cst, pstate)
if err != nil {
return cid.Undef, err
}
spa, err := st.GetActor(actors.StoragePowerAddress)
if err != nil {
return cid.Undef, xerrors.Errorf("failed to get storage power actor: %w", err)
}
var spast actors.StoragePowerState
if err := cst.Get(ctx, spa.Head, &spast); err != nil {
return cid.Undef, err
}
miners, err := actors.MinerSetList(ctx, cst, spast.Miners)
if err != nil {
return cid.Undef, err
}
for _, m := range miners {
mact, err := st.GetActor(m)
if err != nil {
return cid.Undef, xerrors.Errorf("getting miner actor to fix: %w", err)
}
nhead, err := fixMiner(ctx, cst, sm.cs.Blockstore(), mact.Head)
if err != nil {
return cid.Undef, xerrors.Errorf("fixing miner: %w", err)
}
if nhead != mact.Head {
log.Warnf("Miner %s had changes", m)
}
mact.Head = nhead
mact.Code = actors.StorageMiner2CodeCid
if err := st.SetActor(m, mact); err != nil {
return cid.Undef, err
}
}
return st.Flush(ctx)
}
func fixMiner(ctx context.Context, cst *hamt.CborIpldStore, bs blockstore.Blockstore, mscid cid.Cid) (cid.Cid, error) {
var mstate actors.StorageMinerActorState
if err := cst.Get(ctx, mscid, &mstate); err != nil {
return cid.Undef, xerrors.Errorf("failed to load miner actor state: %w", err)
}
amts := amt.WrapBlockstore(bs)
nsectors, err := amtFsck(amts, mstate.Sectors)
if err != nil {
return cid.Undef, xerrors.Errorf("error fsck'ing sector set: %w", err)
}
mstate.Sectors = nsectors
nproving, err := amtFsck(amts, mstate.ProvingSet)
if err != nil {
return cid.Undef, xerrors.Errorf("error fsck'ing proving set: %w", err)
}
mstate.ProvingSet = nproving
nmcid, err := cst.Put(ctx, &mstate)
if err != nil {
return cid.Undef, xerrors.Errorf("failed to put modified miner state: %w", err)
}
return nmcid, nil
}
func amtFsck(s amt.Blocks, ss cid.Cid) (cid.Cid, error) {
a, err := amt.LoadAMT(s, ss)
if err != nil {
return cid.Undef, xerrors.Errorf("could not load AMT: %w", a)
}
b := amt.NewAMT(s)
err = a.ForEach(func(id uint64, data *cbg.Deferred) error {
err := b.Set(id, data)
if err != nil {
return xerrors.Errorf("could not copy at idx (%d): %w", id, err)
}
return nil
})
if err != nil {
return cid.Undef, xerrors.Errorf("could not copy: %w", err)
}
nss, err := b.Flush()
if err != nil {
return cid.Undef, xerrors.Errorf("could not flush: %w", err)
}
return nss, nil
}
+233
View File
@@ -0,0 +1,233 @@
package stmgr_test
import (
"context"
"fmt"
"io"
"testing"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/actors/aerrors"
"github.com/filecoin-project/lotus/chain/gen"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/stmgr"
. "github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm"
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
"github.com/ipfs/go-cid"
hamt "github.com/ipfs/go-hamt-ipld"
blockstore "github.com/ipfs/go-ipfs-blockstore"
logging "github.com/ipfs/go-log"
mh "github.com/multiformats/go-multihash"
cbg "github.com/whyrusleeping/cbor-gen"
)
func init() {
build.SectorSizes = []uint64{1024}
build.MinimumMinerPower = 1024
}
const testForkHeight = 40
type testActor struct {
}
type testActorState struct {
HasUpgraded uint64
}
func (tas *testActorState) MarshalCBOR(w io.Writer) error {
return cbg.CborWriteHeader(w, cbg.MajUnsignedInt, tas.HasUpgraded)
}
func (tas *testActorState) UnmarshalCBOR(r io.Reader) error {
t, v, err := cbg.CborReadHeader(r)
if err != nil {
return err
}
if t != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type in test actor state")
}
tas.HasUpgraded = v
return nil
}
func (ta *testActor) Exports() []interface{} {
return []interface{}{
1: ta.Constructor,
2: ta.TestMethod,
}
}
func (ta *testActor) Constructor(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, aerrors.ActorError) {
c, err := vmctx.Storage().Put(&testActorState{11})
if err != nil {
return nil, err
}
fmt.Println("NEW ACTOR ADDRESS IS: ", vmctx.Message().To.String())
return nil, vmctx.Storage().Commit(actors.EmptyCBOR, c)
}
func (ta *testActor) TestMethod(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, aerrors.ActorError) {
var st testActorState
if err := vmctx.Storage().Get(vmctx.Storage().GetHead(), &st); err != nil {
return nil, err
}
if vmctx.BlockHeight() > testForkHeight {
if st.HasUpgraded != 55 {
return nil, aerrors.Fatal("fork updating applied in wrong order")
}
} else {
if st.HasUpgraded != 11 {
return nil, aerrors.Fatal("fork updating happened too early")
}
}
return nil, nil
}
func TestForkHeightTriggers(t *testing.T) {
logging.SetAllLoggers(logging.LevelInfo)
ctx := context.TODO()
cg, err := gen.NewGenerator()
if err != nil {
t.Fatal(err)
}
sm := NewStateManager(cg.ChainStore())
inv := vm.NewInvoker()
pref := cid.NewPrefixV1(cid.Raw, mh.IDENTITY)
actcid, err := pref.Sum([]byte("testactor"))
if err != nil {
t.Fatal(err)
}
actors.BuiltInActors[actcid] = true
// predicting the address here... may break if other assumptions change
taddr, err := address.NewIDAddress(1000)
if err != nil {
t.Fatal(err)
}
stmgr.ForksAtHeight[testForkHeight] = func(ctx context.Context, sm *StateManager, pstate cid.Cid) (cid.Cid, error) {
cst := hamt.CSTFromBstore(sm.ChainStore().Blockstore())
st, err := state.LoadStateTree(cst, pstate)
if err != nil {
return cid.Undef, err
}
act, err := st.GetActor(taddr)
if err != nil {
return cid.Undef, err
}
var tas testActorState
if err := cst.Get(ctx, act.Head, &tas); err != nil {
return cid.Undef, err
}
tas.HasUpgraded = 55
ns, err := cst.Put(ctx, &tas)
if err != nil {
return cid.Undef, err
}
act.Head = ns
if err := st.SetActor(taddr, act); err != nil {
return cid.Undef, err
}
return st.Flush(ctx)
}
inv.Register(actcid, &testActor{}, &testActorState{})
sm.SetVMConstructor(func(c cid.Cid, h uint64, r vm.Rand, a address.Address, b blockstore.Blockstore, s *types.VMSyscalls) (*vm.VM, error) {
nvm, err := vm.NewVM(c, h, r, a, b, s)
if err != nil {
return nil, err
}
nvm.SetInvoker(inv)
return nvm, nil
})
cg.SetStateManager(sm)
var msgs []*types.SignedMessage
enc, err := actors.SerializeParams(&actors.ExecParams{Code: actcid})
if err != nil {
t.Fatal(err)
}
m := &types.Message{
From: cg.Banker(),
To: actors.InitAddress,
Method: actors.IAMethods.Exec,
Params: enc,
GasLimit: types.NewInt(10000),
GasPrice: types.NewInt(0),
}
sig, err := cg.Wallet().Sign(ctx, cg.Banker(), m.Cid().Bytes())
if err != nil {
t.Fatal(err)
}
msgs = append(msgs, &types.SignedMessage{
Signature: *sig,
Message: *m,
})
nonce := uint64(1)
cg.GetMessages = func(cg *gen.ChainGen) ([]*types.SignedMessage, error) {
if len(msgs) > 0 {
fmt.Println("added construct method")
m := msgs
msgs = nil
return m, nil
}
m := &types.Message{
From: cg.Banker(),
To: taddr,
Method: 2,
Params: nil,
Nonce: nonce,
GasLimit: types.NewInt(10000),
GasPrice: types.NewInt(0),
}
nonce++
sig, err := cg.Wallet().Sign(ctx, cg.Banker(), m.Cid().Bytes())
if err != nil {
return nil, err
}
return []*types.SignedMessage{
&types.SignedMessage{
Signature: *sig,
Message: *m,
},
}, nil
}
for i := 0; i < 50; i++ {
_, err = cg.NextTipSet()
if err != nil {
t.Fatal(err)
}
}
}
+38 -2
View File
@@ -18,7 +18,8 @@ import (
bls "github.com/filecoin-project/filecoin-ffi"
"github.com/ipfs/go-cid"
hamt "github.com/ipfs/go-hamt-ipld"
logging "github.com/ipfs/go-log"
blockstore "github.com/ipfs/go-ipfs-blockstore"
logging "github.com/ipfs/go-log/v2"
"go.opencensus.io/trace"
)
@@ -30,10 +31,12 @@ type StateManager struct {
stCache map[string][]cid.Cid
compWait map[string]chan struct{}
stlk sync.Mutex
newVM func(cid.Cid, uint64, vm.Rand, address.Address, blockstore.Blockstore, *types.VMSyscalls) (*vm.VM, error)
}
func NewStateManager(cs *store.ChainStore) *StateManager {
return &StateManager{
newVM: vm.NewVM,
cs: cs,
stCache: make(map[string][]cid.Cid),
compWait: make(map[string]chan struct{}),
@@ -139,7 +142,7 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.Bl
r := store.NewChainRand(sm.cs, cids, blks[0].Height)
vmi, err := vm.NewVM(pstate, blks[0].Height, r, address.Undef, sm.cs.Blockstore())
vmi, err := sm.newVM(pstate, blks[0].Height, r, address.Undef, sm.cs.Blockstore(), sm.cs.VMSys())
if err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("instantiating VM failed: %w", err)
}
@@ -607,3 +610,36 @@ func (sm *StateManager) MarketBalance(ctx context.Context, addr address.Address,
return b[0], nil
}
func (sm *StateManager) ValidateChain(ctx context.Context, ts *types.TipSet) error {
tschain := []*types.TipSet{ts}
for ts.Height() != 0 {
next, err := sm.cs.LoadTipSet(ts.Parents())
if err != nil {
return err
}
tschain = append(tschain, next)
ts = next
}
lastState := tschain[len(tschain)-1].ParentState()
for i := len(tschain) - 1; i >= 0; i-- {
cur := tschain[i]
log.Infof("computing state (height: %d, ts=%s)", cur.Height(), cur.Cids())
if cur.ParentState() != lastState {
return xerrors.Errorf("tipset chain had state mismatch at height %d", cur.Height())
}
st, _, err := sm.TipSetState(ctx, cur)
if err != nil {
return err
}
lastState = st
}
return nil
}
func (sm *StateManager) SetVMConstructor(nvm func(cid.Cid, uint64, vm.Rand, address.Address, blockstore.Blockstore, *types.VMSyscalls) (*vm.VM, error)) {
sm.newVM = nvm
}
+53
View File
@@ -2,6 +2,8 @@ package stmgr
import (
"context"
amt2 "github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/lotus/chain/actors/aerrors"
ffi "github.com/filecoin-project/filecoin-ffi"
sectorbuilder "github.com/filecoin-project/go-sectorbuilder"
@@ -10,7 +12,9 @@ import (
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm"
amt "github.com/filecoin-project/go-amt-ipld"
cid "github.com/ipfs/go-cid"
@@ -251,6 +255,21 @@ func GetMinerSlashed(ctx context.Context, sm *StateManager, ts *types.TipSet, ma
return mas.SlashedAt, nil
}
func GetMinerFaults(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) ([]uint64, error) {
var mas actors.StorageMinerActorState
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
if err != nil {
return nil, xerrors.Errorf("(get ssize) failed to load miner actor state: %w", err)
}
ss, lerr := amt2.LoadAMT(amt.WrapBlockstore(sm.cs.Blockstore()), mas.Sectors)
if lerr != nil {
return nil, aerrors.HandleExternalError(lerr, "could not load proving set node")
}
return mas.FaultSet.All(2 * ss.Count)
}
func GetStorageDeal(ctx context.Context, sm *StateManager, dealId uint64, ts *types.TipSet) (*actors.OnChainDeal, error) {
var state actors.StorageMarketState
if _, err := sm.LoadActorState(ctx, actors.StorageMarketAddress, &state, ts); err != nil {
@@ -311,3 +330,37 @@ func LoadSectorsFromSet(ctx context.Context, bs blockstore.Blockstore, ssc cid.C
return sset, nil
}
func ComputeState(ctx context.Context, sm *StateManager, height uint64, msgs []*types.Message, ts *types.TipSet) (cid.Cid, error) {
if ts == nil {
ts = sm.cs.GetHeaviestTipSet()
}
base, _, err := sm.TipSetState(ctx, ts)
if err != nil {
return cid.Undef, err
}
fstate, err := sm.handleStateForks(ctx, base, height, ts.Height())
if err != nil {
return cid.Undef, err
}
r := store.NewChainRand(sm.cs, ts.Cids(), height)
vmi, err := vm.NewVM(fstate, height, r, actors.NetworkAddress, sm.cs.Blockstore(), sm.cs.VMSys())
if err != nil {
return cid.Undef, err
}
for i, msg := range msgs {
ret, err := vmi.ApplyMessage(ctx, msg)
if err != nil {
return cid.Undef, xerrors.Errorf("applying message %s: %w", msg.Cid(), err)
}
if ret.ExitCode != 0 {
log.Infof("compute state apply message %d failed (exit: %d): %s", i, ret.ExitCode, ret.ActorErr)
}
}
return vmi.Flush(ctx)
}
+126 -2
View File
@@ -1,10 +1,12 @@
package store
import (
"bytes"
"context"
"crypto/sha256"
"encoding/binary"
"encoding/json"
"io"
"sync"
"github.com/filecoin-project/go-address"
@@ -19,11 +21,16 @@ import (
lru "github.com/hashicorp/golang-lru"
block "github.com/ipfs/go-block-format"
"github.com/ipfs/go-blockservice"
car "github.com/ipfs/go-car"
"github.com/ipfs/go-cid"
dstore "github.com/ipfs/go-datastore"
hamt "github.com/ipfs/go-hamt-ipld"
blockstore "github.com/ipfs/go-ipfs-blockstore"
bstore "github.com/ipfs/go-ipfs-blockstore"
logging "github.com/ipfs/go-log"
format "github.com/ipfs/go-ipld-format"
logging "github.com/ipfs/go-log/v2"
dag "github.com/ipfs/go-merkledag"
cbg "github.com/whyrusleeping/cbor-gen"
pubsub "github.com/whyrusleeping/pubsub"
"golang.org/x/xerrors"
@@ -51,9 +58,11 @@ type ChainStore struct {
mmCache *lru.ARCCache
tsCache *lru.ARCCache
vmcalls *types.VMSyscalls
}
func NewChainStore(bs bstore.Blockstore, ds dstore.Batching) *ChainStore {
func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls *types.VMSyscalls) *ChainStore {
c, _ := lru.NewARC(2048)
tsc, _ := lru.NewARC(4096)
cs := &ChainStore{
@@ -63,6 +72,7 @@ func NewChainStore(bs bstore.Blockstore, ds dstore.Batching) *ChainStore {
tipsets: make(map[uint64][]cid.Cid),
mmCache: c,
tsCache: tsc,
vmcalls: vmcalls,
}
cs.reorgCh = cs.reorgWorker(context.TODO())
@@ -727,6 +737,30 @@ func (cs *ChainStore) readMsgMetaCids(mmc cid.Cid) ([]cid.Cid, []cid.Cid, error)
return blscids, secpkcids, nil
}
func (cs *ChainStore) GetPath(ctx context.Context, from types.TipSetKey, to types.TipSetKey) ([]*HeadChange, error) {
fts, err := cs.LoadTipSet(from)
if err != nil {
return nil, xerrors.Errorf("loading from tipset %s: %w", from, err)
}
tts, err := cs.LoadTipSet(to)
if err != nil {
return nil, xerrors.Errorf("loading to tipset %s: %w", to, err)
}
revert, apply, err := cs.ReorgOps(fts, tts)
if err != nil {
return nil, xerrors.Errorf("error getting tipset branches: %w", err)
}
path := make([]*HeadChange, len(revert)+len(apply))
for i, r := range revert {
path[i] = &HeadChange{Type: HCRevert, Val: r}
}
for j, i := 0, len(apply)-1; i >= 0; j, i = j+1, i-1 {
path[j+len(revert)] = &HeadChange{Type: HCApply, Val: apply[i]}
}
return path, nil
}
func (cs *ChainStore) MessagesForBlock(b *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) {
blscids, secpkcids, err := cs.readMsgMetaCids(b.Messages)
if err != nil {
@@ -793,6 +827,10 @@ func (cs *ChainStore) Blockstore() bstore.Blockstore {
return cs.bs
}
func (cs *ChainStore) VMSys() *types.VMSyscalls {
return cs.vmcalls
}
func (cs *ChainStore) TryFillTipSet(ts *types.TipSet) (*FullTipSet, error) {
var out []*types.FullBlock
@@ -886,6 +924,84 @@ func (cs *ChainStore) GetTipsetByHeight(ctx context.Context, h uint64, ts *types
}
}
func recurseLinks(bs blockstore.Blockstore, root cid.Cid, in []cid.Cid) ([]cid.Cid, error) {
data, err := bs.Get(root)
if err != nil {
return nil, err
}
top, err := cbg.ScanForLinks(bytes.NewReader(data.RawData()))
if err != nil {
return nil, err
}
in = append(in, top...)
for _, c := range top {
var err error
in, err = recurseLinks(bs, c, in)
if err != nil {
return nil, err
}
}
return in, nil
}
func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, w io.Writer) error {
if ts == nil {
ts = cs.GetHeaviestTipSet()
}
bsrv := blockservice.New(cs.bs, nil)
dserv := dag.NewDAGService(bsrv)
return car.WriteCarWithWalker(ctx, dserv, ts.Cids(), w, func(nd format.Node) ([]*format.Link, error) {
var b types.BlockHeader
if err := b.UnmarshalCBOR(bytes.NewBuffer(nd.RawData())); err != nil {
return nil, err
}
var out []*format.Link
for _, p := range b.Parents {
out = append(out, &format.Link{Cid: p})
}
cids, err := recurseLinks(cs.bs, b.Messages, nil)
if err != nil {
return nil, err
}
for _, c := range cids {
out = append(out, &format.Link{Cid: c})
}
if b.Height == 0 {
cids, err := recurseLinks(cs.bs, b.ParentStateRoot, nil)
if err != nil {
return nil, err
}
for _, c := range cids {
out = append(out, &format.Link{Cid: c})
}
}
return out, nil
})
}
func (cs *ChainStore) Import(r io.Reader) (*types.TipSet, error) {
header, err := car.LoadCar(cs.Blockstore(), r)
if err != nil {
return nil, xerrors.Errorf("loadcar failed: %w", err)
}
root, err := cs.LoadTipSet(types.NewTipSetKey(header.Roots...))
if err != nil {
return nil, xerrors.Errorf("failed to load root tipset from chainfile: %w", err)
}
return root, nil
}
type chainRand struct {
cs *ChainStore
blks []cid.Cid
@@ -903,3 +1019,11 @@ func NewChainRand(cs *ChainStore, blks []cid.Cid, bheight uint64) vm.Rand {
func (cr *chainRand) GetRandomness(ctx context.Context, round int64) ([]byte, error) {
return cr.cs.GetRandomness(ctx, cr.blks, round)
}
func (cs *ChainStore) GetTipSetFromKey(tsk types.TipSetKey) (*types.TipSet, error) {
if tsk.IsEmpty() {
return cs.GetHeaviestTipSet(), nil
} else {
return cs.LoadTipSet(tsk)
}
}
+1 -1
View File
@@ -55,7 +55,7 @@ func BenchmarkGetRandomness(b *testing.B) {
bs := blockstore.NewBlockstore(bds)
cs := store.NewChainStore(bs, mds)
cs := store.NewChainStore(bs, mds, nil)
b.ResetTimer()
+1 -1
View File
@@ -60,7 +60,7 @@ func (cs *ChainStore) call(ctx context.Context, msg *types.Message, ts *types.Ti
r := NewChainRand(cs, ts.Cids(), ts.Height())
vmi, err := vm.NewVM(bstate, ts.Height(), r, actors.NetworkAddress, cs.bs)
vmi, err := vm.NewVM(bstate, ts.Height(), r, actors.NetworkAddress, cs.bs, cs.vmcalls)
if err != nil {
return nil, xerrors.Errorf("failed to set up vm: %w", err)
}
+94 -8
View File
@@ -4,10 +4,14 @@ import (
"context"
"time"
logging "github.com/ipfs/go-log"
lru "github.com/hashicorp/golang-lru"
"github.com/ipfs/go-cid"
logging "github.com/ipfs/go-log/v2"
connmgr "github.com/libp2p/go-libp2p-core/connmgr"
peer "github.com/libp2p/go-libp2p-peer"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain"
"github.com/filecoin-project/lotus/chain/messagepool"
"github.com/filecoin-project/lotus/chain/types"
@@ -27,10 +31,9 @@ func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *cha
continue
}
blk, err := types.DecodeBlockMsg(msg.GetData())
if err != nil {
log.Error("got invalid block over pubsub: ", err)
continue
blk, ok := msg.ValidatorData.(*types.BlockMsg)
if !ok {
log.Warnf("pubsub block validator passed on wrong type: %#v", msg.ValidatorData)
}
go func() {
@@ -67,6 +70,89 @@ func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *cha
}
}
type BlockValidator struct {
peers *lru.TwoQueueCache
killThresh int
recvBlocks *blockReceiptCache
blacklist func(peer.ID)
}
func NewBlockValidator(blacklist func(peer.ID)) *BlockValidator {
p, _ := lru.New2Q(4096)
return &BlockValidator{
peers: p,
killThresh: 5,
blacklist: blacklist,
recvBlocks: newBlockReceiptCache(),
}
}
func (bv *BlockValidator) flagPeer(p peer.ID) {
v, ok := bv.peers.Get(p)
if !ok {
bv.peers.Add(p, int(1))
return
}
val := v.(int)
if val >= bv.killThresh {
bv.blacklist(p)
}
bv.peers.Add(p, v.(int)+1)
}
func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub.Message) bool {
blk, err := types.DecodeBlockMsg(msg.GetData())
if err != nil {
log.Error("got invalid block over pubsub: ", err)
bv.flagPeer(pid)
return false
}
if len(blk.BlsMessages)+len(blk.SecpkMessages) > build.BlockMessageLimit {
log.Warnf("received block with too many messages over pubsub")
bv.flagPeer(pid)
return false
}
if bv.recvBlocks.add(blk.Header.Cid()) > 0 {
// TODO: once these changes propagate to the network, we can consider
// dropping peers who send us the same block multiple times
return false
}
msg.ValidatorData = blk
return true
}
type blockReceiptCache struct {
blocks *lru.TwoQueueCache
}
func newBlockReceiptCache() *blockReceiptCache {
c, _ := lru.New2Q(8192)
return &blockReceiptCache{
blocks: c,
}
}
func (brc *blockReceiptCache) add(bcid cid.Cid) int {
val, ok := brc.blocks.Get(bcid)
if !ok {
brc.blocks.Add(bcid, int(1))
return 0
}
brc.blocks.Add(bcid, val.(int)+1)
return val.(int)
}
func HandleIncomingMessages(ctx context.Context, mpool *messagepool.MessagePool, msub *pubsub.Subscription) {
for {
msg, err := msub.Next(ctx)
@@ -79,9 +165,9 @@ func HandleIncomingMessages(ctx context.Context, mpool *messagepool.MessagePool,
continue
}
m, err := types.DecodeSignedMessage(msg.GetData())
if err != nil {
log.Errorf("got incorrectly formatted Message: %s", err)
m, ok := msg.ValidatorData.(*types.SignedMessage)
if !ok {
log.Errorf("message validator func passed on wrong type: %#v", msg.ValidatorData)
continue
}
+44 -28
View File
@@ -18,7 +18,7 @@ import (
dstore "github.com/ipfs/go-datastore"
hamt "github.com/ipfs/go-hamt-ipld"
bstore "github.com/ipfs/go-ipfs-blockstore"
logging "github.com/ipfs/go-log"
logging "github.com/ipfs/go-log/v2"
"github.com/libp2p/go-libp2p-core/connmgr"
"github.com/libp2p/go-libp2p-core/peer"
cbg "github.com/whyrusleeping/cbor-gen"
@@ -37,6 +37,7 @@ import (
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/sigs"
)
var log = logging.Logger("chain")
@@ -117,6 +118,10 @@ func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
}
for _, b := range fts.Blocks {
if reason, ok := syncer.bad.Has(b.Cid()); ok {
log.Warnf("InformNewHead called on block marked as bad: %s (reason: %s)", b.Cid(), reason)
return false
}
if err := syncer.ValidateMsgMeta(b); err != nil {
log.Warnf("invalid block received: %s", err)
return false
@@ -189,6 +194,10 @@ func (syncer *Syncer) IncomingBlocks(ctx context.Context) (<-chan *types.BlockHe
}
func (syncer *Syncer) ValidateMsgMeta(fblk *types.FullBlock) error {
if msgc := len(fblk.BlsMessages) + len(fblk.SecpkMessages); msgc > build.BlockMessageLimit {
return xerrors.Errorf("block %s has too many messages (%d)", fblk.Header.Cid(), msgc)
}
var bcids, scids []cbg.CBORMarshaler
for _, m := range fblk.BlsMessages {
c := cbg.CborCid(m.Cid())
@@ -295,6 +304,10 @@ func zipTipSetAndMessages(bs amt.Blocks, ts *types.TipSet, allbmsgs []*types.Mes
bmsgCids = append(bmsgCids, &c)
}
if msgc := len(bmsgCids) + len(smsgCids); msgc > build.BlockMessageLimit {
return nil, fmt.Errorf("block %q has too many messages (%d)", b.Cid(), msgc)
}
mrcid, err := computeMsgMeta(bs, bmsgCids, smsgCids)
if err != nil {
return nil, err
@@ -437,7 +450,7 @@ func (syncer *Syncer) ValidateTipSet(ctx context.Context, fts *store.FullTipSet)
for _, b := range fts.Blocks {
if err := syncer.ValidateBlock(ctx, b); err != nil {
if isPermanent(err) {
syncer.bad.Add(b.Cid())
syncer.bad.Add(b.Cid(), err.Error())
}
return xerrors.Errorf("validating block %s: %w", b.Cid(), err)
}
@@ -533,15 +546,17 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
snum := types.BigDiv(mpow, types.NewInt(ssize))
// FORK START
if h.Height > build.ForkCCM {
if len(h.EPostProof.Candidates) == 0 {
return xerrors.Errorf("no candidates")
}
if len(h.EPostProof.Candidates) == 0 {
return xerrors.Errorf("no candidates")
}
// FORK END
wins := make(map[uint64]bool)
for _, t := range h.EPostProof.Candidates {
if wins[t.ChallengeIndex] {
return xerrors.Errorf("block had duplicate epost candidates")
}
wins[t.ChallengeIndex] = true
if !types.IsTicketWinner(t.Partial, ssize, snum.Uint64(), tpow) {
return xerrors.Errorf("miner created a block but was not a winner")
}
@@ -594,7 +609,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
}
blockSigCheck := async.Err(func() error {
if err := h.CheckBlockSignature(ctx, waddr); err != nil {
if err := sigs.CheckBlockSignature(h, ctx, waddr); err != nil {
return xerrors.Errorf("check block signature failed: %w", err)
}
return nil
@@ -662,13 +677,10 @@ func (syncer *Syncer) VerifyElectionPoStProof(ctx context.Context, h *types.Bloc
SectorChallengeIndex: t.ChallengeIndex,
})
}
// FORK START
if h.Height > build.ForkCCM {
if len(winners) == 0 {
return xerrors.Errorf("no candidates")
}
if len(winners) == 0 {
return xerrors.Errorf("no candidates")
}
// FORK END
sectorInfo, err := stmgr.GetSectorsForElectionPost(ctx, syncer.sm, baseTs, h.Miner)
if err != nil {
@@ -683,7 +695,7 @@ func (syncer *Syncer) VerifyElectionPoStProof(ctx context.Context, h *types.Bloc
}
hvrf := sha256.Sum256(h.EPostProof.PostRand)
ok, err := sectorbuilder.VerifyElectionPost(ctx, ssize, *sectorInfo, hvrf[:], h.EPostProof.Proof, winners, h.Miner)
ok, err := sectorbuilder.ProofVerifier.VerifyElectionPost(ctx, ssize, *sectorInfo, hvrf[:], h.EPostProof.Proof, winners, h.Miner)
if err != nil {
return xerrors.Errorf("failed to verify election post: %w", err)
}
@@ -780,7 +792,7 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
return xerrors.Errorf("failed to resolve key addr: %w", err)
}
if err := m.Signature.Verify(kaddr, m.Message.Cid().Bytes()); err != nil {
if err := sigs.Verify(&m.Signature, kaddr, m.Message.Cid().Bytes()); err != nil {
return xerrors.Errorf("secpk message %s has invalid signature: %w", m.Cid(), err)
}
@@ -864,11 +876,11 @@ func (syncer *Syncer) collectHeaders(ctx context.Context, from *types.TipSet, to
)
for _, pcid := range from.Parents().Cids() {
if syncer.bad.Has(pcid) {
if reason, ok := syncer.bad.Has(pcid); ok {
for _, b := range from.Cids() {
syncer.bad.Add(b)
syncer.bad.Add(b, fmt.Sprintf("linked to %s", pcid))
}
return nil, xerrors.Errorf("chain linked to block marked previously as bad (%s, %s)", from.Cids(), pcid)
return nil, xerrors.Errorf("chain linked to block marked previously as bad (%s, %s) (reason: %s)", from.Cids(), pcid, reason)
}
}
@@ -886,12 +898,12 @@ func (syncer *Syncer) collectHeaders(ctx context.Context, from *types.TipSet, to
loop:
for blockSet[len(blockSet)-1].Height() > untilHeight {
for _, bc := range at.Cids() {
if syncer.bad.Has(bc) {
if reason, ok := syncer.bad.Has(bc); ok {
for _, b := range acceptedBlocks {
syncer.bad.Add(b)
syncer.bad.Add(b, fmt.Sprintf("chain contained %s", bc))
}
return nil, xerrors.Errorf("chain contained block marked previously as bad (%s, %s)", from.Cids(), bc)
return nil, xerrors.Errorf("chain contained block marked previously as bad (%s, %s) (reason: %s)", from.Cids(), bc, reason)
}
}
@@ -934,12 +946,12 @@ loop:
break loop
}
for _, bc := range b.Cids() {
if syncer.bad.Has(bc) {
if reason, ok := syncer.bad.Has(bc); ok {
for _, b := range acceptedBlocks {
syncer.bad.Add(b)
syncer.bad.Add(b, fmt.Sprintf("chain contained %s", bc))
}
return nil, xerrors.Errorf("chain contained block marked previously as bad (%s, %s)", from.Cids(), bc)
return nil, xerrors.Errorf("chain contained block marked previously as bad (%s, %s) (reason: %s)", from.Cids(), bc, reason)
}
}
blockSet = append(blockSet, b)
@@ -966,7 +978,7 @@ loop:
// TODO: we're marking this block bad in the same way that we mark invalid blocks bad. Maybe distinguish?
log.Warn("adding forked chain to our bad tipset cache")
for _, b := range from.Blocks() {
syncer.bad.Add(b.Cid())
syncer.bad.Add(b.Cid(), "fork past finality")
}
}
return nil, xerrors.Errorf("failed to sync fork: %w", err)
@@ -1183,5 +1195,9 @@ func (syncer *Syncer) State() []SyncerState {
}
func (syncer *Syncer) MarkBad(blk cid.Cid) {
syncer.bad.Add(blk)
syncer.bad.Add(blk, "manually marked bad")
}
func (syncer *Syncer) CheckBadBlockCache(blk cid.Cid) (string, bool) {
return syncer.bad.Has(blk)
}
+2 -2
View File
@@ -7,7 +7,7 @@ import (
"testing"
"time"
logging "github.com/ipfs/go-log"
logging "github.com/ipfs/go-log/v2"
"github.com/libp2p/go-libp2p-core/peer"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/require"
@@ -73,7 +73,7 @@ func prepSyncTest(t testing.TB, h int) *syncTestUtil {
g, err := gen.NewGenerator()
if err != nil {
t.Fatal(err)
t.Fatalf("%+v", err)
}
ctx, cancel := context.WithCancel(context.Background())
+33 -7
View File
@@ -1,6 +1,7 @@
package types
import (
"errors"
"fmt"
"io"
@@ -9,6 +10,8 @@ import (
"golang.org/x/xerrors"
)
var ErrBitFieldTooMany = errors.New("to many items in RLE")
type BitField struct {
rle rlepluslazy.RLE
@@ -16,14 +19,23 @@ type BitField struct {
}
func NewBitField() BitField {
rle, err := rlepluslazy.FromBuf([]byte{})
bf, err := NewBitFieldFromBytes([]byte{})
if err != nil {
panic(err)
panic(fmt.Sprintf("creating empty rle: %+v", err))
}
return BitField{
rle: rle,
bits: make(map[uint64]struct{}),
return bf
}
func NewBitFieldFromBytes(rle []byte) (BitField, error) {
bf := BitField{}
rlep, err := rlepluslazy.FromBuf(rle)
if err != nil {
return BitField{}, xerrors.Errorf("could not decode rle+: %w", err)
}
bf.rle = rlep
bf.bits = make(map[uint64]struct{})
return bf, nil
}
func BitFieldFromSet(setBits []uint64) BitField {
@@ -106,7 +118,14 @@ func (bf BitField) Count() (uint64, error) {
}
// All returns all set bits
func (bf BitField) All() ([]uint64, error) {
func (bf BitField) All(max uint64) ([]uint64, error) {
c, err := bf.Count()
if err != nil {
return nil, xerrors.Errorf("count errror: %w", err)
}
if c > max {
return nil, xerrors.Errorf("expected %d, got %d: %w", max, c, ErrBitFieldTooMany)
}
runs, err := bf.sum()
if err != nil {
@@ -121,7 +140,14 @@ func (bf BitField) All() ([]uint64, error) {
return res, nil
}
func (bf BitField) AllMap() (map[uint64]bool, error) {
func (bf BitField) AllMap(max uint64) (map[uint64]bool, error) {
c, err := bf.Count()
if err != nil {
return nil, xerrors.Errorf("count errror: %w", err)
}
if c > max {
return nil, xerrors.Errorf("expected %d, got %d: %w", max, c, ErrBitFieldTooMany)
}
runs, err := bf.sum()
if err != nil {
+20 -30
View File
@@ -2,16 +2,12 @@ package types
import (
"bytes"
"context"
"math/big"
"github.com/filecoin-project/go-sectorbuilder"
block "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
"github.com/minio/sha256-simd"
"github.com/multiformats/go-multihash"
"go.opencensus.io/trace"
xerrors "golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
@@ -36,29 +32,31 @@ type EPostProof struct {
}
type BlockHeader struct {
Miner address.Address
Miner address.Address // 0
Ticket *Ticket
Ticket *Ticket // 1
EPostProof EPostProof
EPostProof EPostProof // 2
Parents []cid.Cid
Parents []cid.Cid // 3
ParentWeight BigInt
ParentWeight BigInt // 4
Height uint64
Height uint64 // 5
ParentStateRoot cid.Cid
ParentStateRoot cid.Cid // 6
ParentMessageReceipts cid.Cid
ParentMessageReceipts cid.Cid // 7
Messages cid.Cid
Messages cid.Cid // 8
BLSAggregate Signature
BLSAggregate Signature // 9
Timestamp uint64
Timestamp uint64 // 10
BlockSig *Signature
BlockSig *Signature // 11
ForkSignaling uint64 // 12
}
func (b *BlockHeader) ToStorageBlock() (block.Block, error) {
@@ -114,18 +112,6 @@ func (blk *BlockHeader) SigningBytes() ([]byte, error) {
return blkcopy.Serialize()
}
func (blk *BlockHeader) CheckBlockSignature(ctx context.Context, worker address.Address) error {
_, span := trace.StartSpan(ctx, "checkBlockSignature")
defer span.End()
sigb, err := blk.SigningBytes()
if err != nil {
return xerrors.Errorf("failed to get block signing bytes: %w", err)
}
return blk.BlockSig.Verify(worker, sigb)
}
type MsgMeta struct {
BlsMessages cid.Cid
SecpkMessages cid.Cid
@@ -216,8 +202,12 @@ func IsTicketWinner(partialTicket []byte, ssizeI uint64, snum uint64, totpow Big
return lhs.Cmp(rhs) < 0
}
func ElectionPostChallengeCount(sectors uint64, faults int) uint64 {
return sectorbuilder.ElectionPostChallengeCount(sectors, faults)
func ElectionPostChallengeCount(sectors uint64, faults uint64) uint64 {
if sectors-faults == 0 {
return 0
}
// ceil(sectors / SectorChallengeRatioDiv)
return (sectors-faults-1)/build.SectorChallengeRatioDiv + 1
}
func (t *Ticket) Equals(ot *Ticket) bool {
+17 -2
View File
@@ -19,7 +19,7 @@ func (t *BlockHeader) MarshalCBOR(w io.Writer) error {
_, err := w.Write(cbg.CborNull)
return err
}
if _, err := w.Write([]byte{140}); err != nil {
if _, err := w.Write([]byte{141}); err != nil {
return err
}
@@ -94,6 +94,11 @@ func (t *BlockHeader) MarshalCBOR(w io.Writer) error {
if err := t.BlockSig.MarshalCBOR(w); err != nil {
return err
}
// t.ForkSignaling (uint64) (uint64)
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.ForkSignaling))); err != nil {
return err
}
return nil
}
@@ -108,7 +113,7 @@ func (t *BlockHeader) UnmarshalCBOR(r io.Reader) error {
return fmt.Errorf("cbor input should be of type array")
}
if extra != 12 {
if extra != 13 {
return fmt.Errorf("cbor input had wrong number of fields")
}
@@ -272,6 +277,16 @@ func (t *BlockHeader) UnmarshalCBOR(r io.Reader) error {
}
}
// t.ForkSignaling (uint64) (uint64)
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.ForkSignaling = uint64(extra)
return nil
}
+3
View File
@@ -116,5 +116,8 @@ func (s *Signature) UnmarshalCBOR(br io.Reader) error {
}
func (s *Signature) Equals(o *Signature) bool {
if s == nil || o == nil {
return s == o
}
return s.Type == o.Type && bytes.Equal(s.Data, o.Data)
}
-55
View File
@@ -1,55 +0,0 @@
//+build cgo
package types
import (
"fmt"
bls "github.com/filecoin-project/filecoin-ffi"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-crypto"
"github.com/minio/blake2b-simd"
)
func (s *Signature) Verify(addr address.Address, msg []byte) error {
if addr.Protocol() == address.ID {
return fmt.Errorf("must resolve ID addresses before using them to verify a signature")
}
b2sum := blake2b.Sum256(msg)
switch s.Type {
case KTSecp256k1:
pubk, err := crypto.EcRecover(b2sum[:], s.Data)
if err != nil {
return err
}
maybeaddr, err := address.NewSecp256k1Address(pubk)
if err != nil {
return err
}
if addr != maybeaddr {
return fmt.Errorf("signature did not match")
}
return nil
case KTBLS:
digests := []bls.Digest{bls.Hash(bls.Message(msg))}
var pubk bls.PublicKey
copy(pubk[:], addr.Payload())
pubkeys := []bls.PublicKey{pubk}
var sig bls.Signature
copy(sig[:], s.Data)
if !bls.Verify(&sig, digests, pubkeys) {
return fmt.Errorf("bls signature failed to verify")
}
return nil
default:
return fmt.Errorf("cannot verify signature of unsupported type: %s", s.Type)
}
}
+4 -1
View File
@@ -8,7 +8,7 @@ import (
"sort"
"github.com/ipfs/go-cid"
logging "github.com/ipfs/go-log"
logging "github.com/ipfs/go-log/v2"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
)
@@ -129,6 +129,9 @@ func (ts *TipSet) Cids() []cid.Cid {
}
func (ts *TipSet) Key() TipSetKey {
if ts == nil {
return EmptyTSK
}
return NewTipSetKey(ts.cids...)
}
+6
View File
@@ -9,6 +9,8 @@ import (
"github.com/multiformats/go-multihash"
)
var EmptyTSK = TipSetKey{}
// The length of a block header CID in bytes.
var blockHeaderCIDLen int
@@ -90,6 +92,10 @@ func (k *TipSetKey) UnmarshalJSON(b []byte) error {
return nil
}
func (k TipSetKey) IsEmpty() bool {
return len(k.value) == 0
}
func encodeKey(cids []cid.Cid) []byte {
buffer := new(bytes.Buffer)
for _, c := range cids {
+24 -1
View File
@@ -6,6 +6,7 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-amt-ipld"
"github.com/filecoin-project/lotus/chain/actors/aerrors"
cid "github.com/ipfs/go-cid"
hamt "github.com/ipfs/go-hamt-ipld"
cbg "github.com/whyrusleeping/cbor-gen"
@@ -45,8 +46,30 @@ type VMContext interface {
Context() context.Context
}
const CommitmentBytesLen = 32
type PublicSectorInfo struct {
SectorID uint64
CommR [CommitmentBytesLen]byte
}
type Candidate struct {
SectorID uint64
PartialTicket [32]byte
Ticket [32]byte
SectorChallengeIndex uint64
}
type VMSyscalls struct {
ValidatePoRep func(context.Context, address.Address, uint64, []byte, []byte, []byte, []byte, []byte, uint64) (bool, aerrors.ActorError)
ValidatePoRep func(context.Context, address.Address, uint64, []byte, []byte, []byte, []byte, []byte, uint64) (bool, aerrors.ActorError)
VerifyFallbackPost func(ctx context.Context,
sectorSize uint64,
sectorInfo []PublicSectorInfo,
challengeSeed []byte,
proof []byte,
candidates []Candidate,
proverID address.Address,
faults uint64) (bool, error)
}
type storageWrapper struct {
+2 -1
View File
@@ -2,6 +2,7 @@ package validation
import (
"context"
"github.com/filecoin-project/go-sectorbuilder"
vchain "github.com/filecoin-project/chain-validation/pkg/chain"
vstate "github.com/filecoin-project/chain-validation/pkg/state"
@@ -32,7 +33,7 @@ func (a *Applier) ApplyMessage(eCtx *vchain.ExecutionContext, state vstate.Wrapp
if err != nil {
return vchain.MessageReceipt{}, err
}
lotusVM, err := vm.NewVM(base, eCtx.Epoch, randSrc, minerAddr, st.bs)
lotusVM, err := vm.NewVM(base, eCtx.Epoch, randSrc, minerAddr, st.bs, vm.Syscalls(sectorbuilder.ProofVerifier))
if err != nil {
return vchain.MessageReceipt{}, err
}
+1
View File
@@ -16,6 +16,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet"
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
)
func TestMessageFactory(t *testing.T) {
+2 -2
View File
@@ -59,7 +59,7 @@ func NewState() *StateWrapper {
if err != nil {
panic(err) // Never returns error, the error return should be removed.
}
root, err := treeImpl.Flush()
root, err := treeImpl.Flush(context.TODO())
if err != nil {
panic(err)
}
@@ -208,7 +208,7 @@ func (s *StateWrapper) Signer() *keyStore {
// Flushes a state tree to storage and sets this state's root to that tree's root CID.
func (s *StateWrapper) flush(tree *state.StateTree) (err error) {
s.stateRoot, err = tree.Flush()
s.stateRoot, err = tree.Flush(context.TODO())
return
}
+15 -10
View File
@@ -23,20 +23,21 @@ type invoker struct {
type invokeFunc func(act *types.Actor, vmctx types.VMContext, params []byte) ([]byte, aerrors.ActorError)
type nativeCode []invokeFunc
func newInvoker() *invoker {
func NewInvoker() *invoker {
inv := &invoker{
builtInCode: make(map[cid.Cid]nativeCode),
builtInState: make(map[cid.Cid]reflect.Type),
}
// add builtInCode using: register(cid, singleton)
inv.register(actors.InitCodeCid, actors.InitActor{}, actors.InitActorState{})
inv.register(actors.CronCodeCid, actors.CronActor{}, actors.CronActorState{})
inv.register(actors.StoragePowerCodeCid, actors.StoragePowerActor{}, actors.StoragePowerState{})
inv.register(actors.StorageMarketCodeCid, actors.StorageMarketActor{}, actors.StorageMarketState{})
inv.register(actors.StorageMinerCodeCid, actors.StorageMinerActor{}, actors.StorageMinerActorState{})
inv.register(actors.MultisigCodeCid, actors.MultiSigActor{}, actors.MultiSigActorState{})
inv.register(actors.PaymentChannelCodeCid, actors.PaymentChannelActor{}, actors.PaymentChannelActorState{})
inv.Register(actors.InitCodeCid, actors.InitActor{}, actors.InitActorState{})
inv.Register(actors.CronCodeCid, actors.CronActor{}, actors.CronActorState{})
inv.Register(actors.StoragePowerCodeCid, actors.StoragePowerActor{}, actors.StoragePowerState{})
inv.Register(actors.StorageMarketCodeCid, actors.StorageMarketActor{}, actors.StorageMarketState{})
inv.Register(actors.StorageMinerCodeCid, actors.StorageMinerActor{}, actors.StorageMinerActorState{})
inv.Register(actors.StorageMiner2CodeCid, actors.StorageMinerActor2{}, actors.StorageMinerActorState{})
inv.Register(actors.MultisigCodeCid, actors.MultiSigActor{}, actors.MultiSigActorState{})
inv.Register(actors.PaymentChannelCodeCid, actors.PaymentChannelActor{}, actors.PaymentChannelActorState{})
return inv
}
@@ -59,7 +60,7 @@ func (inv *invoker) Invoke(act *types.Actor, vmctx types.VMContext, method uint6
}
func (inv *invoker) register(c cid.Cid, instance Invokee, state interface{}) {
func (inv *invoker) Register(c cid.Cid, instance Invokee, state interface{}) {
code, err := inv.transform(instance)
if err != nil {
panic(err)
@@ -160,7 +161,11 @@ func DecodeParams(b []byte, out interface{}) error {
}
func DumpActorState(code cid.Cid, b []byte) (interface{}, error) {
i := newInvoker() // TODO: register builtins in init block
if code == actors.AccountCodeCid { // Account code special case
return nil, nil
}
i := NewInvoker() // TODO: register builtins in init block
typ, ok := i.builtInState[code]
if !ok {
+57 -2
View File
@@ -1,14 +1,69 @@
package vm
import (
"context"
ffi "github.com/filecoin-project/filecoin-ffi"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-sectorbuilder"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/actors/aerrors"
"github.com/filecoin-project/lotus/chain/types"
"go.opencensus.io/trace"
)
// Actual type is defined in chain/types/vmcontext.go because the VMContext interface is there
func DefaultSyscalls() *types.VMSyscalls {
func Syscalls(verifier sectorbuilder.Verifier) *types.VMSyscalls {
return &types.VMSyscalls{
ValidatePoRep: actors.ValidatePoRep,
ValidatePoRep: func(ctx context.Context, maddr address.Address, ssize uint64, commD, commR, ticket, proof, seed []byte, sectorID uint64) (bool, actors.ActorError) {
_, span := trace.StartSpan(ctx, "ValidatePoRep")
defer span.End()
ok, err := verifier.VerifySeal(ssize, commR, commD, maddr, ticket, seed, sectorID, proof)
if err != nil {
return false, aerrors.Absorb(err, 25, "verify seal failed")
}
return ok, nil
},
VerifyFallbackPost: func(ctx context.Context,
sectorSize uint64,
sectorInfo []types.PublicSectorInfo,
challengeSeed []byte,
proof []byte,
candidates []types.Candidate,
proverID address.Address,
faults uint64) (bool, error) {
sI := make([]ffi.PublicSectorInfo, len(sectorInfo))
for i, v := range sectorInfo {
sI[i] = ffi.PublicSectorInfo{
SectorID: v.SectorID,
CommR: v.CommR,
}
}
cand := make([]sectorbuilder.EPostCandidate, len(candidates))
for i, v := range candidates {
cand[i] = sectorbuilder.EPostCandidate{
SectorID: v.SectorID,
PartialTicket: v.PartialTicket,
Ticket: v.Ticket,
SectorChallengeIndex: v.SectorChallengeIndex,
}
}
return verifier.VerifyFallbackPost(
ctx,
sectorSize,
sectorbuilder.NewSortedPublicSectorInfo(sI),
challengeSeed,
proof,
cand,
proverID,
faults,
)
},
}
}
+19 -11
View File
@@ -10,7 +10,7 @@ import (
cid "github.com/ipfs/go-cid"
hamt "github.com/ipfs/go-hamt-ipld"
blockstore "github.com/ipfs/go-ipfs-blockstore"
logging "github.com/ipfs/go-log"
logging "github.com/ipfs/go-log/v2"
cbg "github.com/whyrusleeping/cbor-gen"
"go.opencensus.io/trace"
"golang.org/x/xerrors"
@@ -22,6 +22,7 @@ import (
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/bufbstore"
"github.com/filecoin-project/lotus/lib/sigs"
)
var log = logging.Logger("vm")
@@ -196,7 +197,7 @@ func (vmctx *VMContext) VerifySignature(sig *types.Signature, act address.Addres
act = kaddr
}
if err := sig.Verify(act, data); err != nil {
if err := sigs.Verify(sig, act, data); err != nil {
return aerrors.New(2, "signature verification failed")
}
@@ -259,7 +260,7 @@ func (bs *gasChargingBlocks) GetBlock(ctx context.Context, c cid.Cid) (block.Blo
}
blk, err := bs.under.GetBlock(ctx, c)
if err != nil {
return nil, err
return nil, aerrors.Escalate(err, "failed to get block from blockstore")
}
if err := bs.chargeGas(uint64(len(blk.RawData())) * gasGetPerByte); err != nil {
return nil, err
@@ -272,7 +273,10 @@ func (bs *gasChargingBlocks) AddBlock(blk block.Block) error {
if err := bs.chargeGas(gasPutObj + uint64(len(blk.RawData()))*gasPutPerByte); err != nil {
return err
}
return bs.under.AddBlock(blk)
if err := bs.under.AddBlock(blk); err != nil {
return aerrors.Escalate(err, "failed to write data to disk")
}
return nil
}
func (vm *VM) makeVMContext(ctx context.Context, sroot cid.Cid, msg *types.Message, origin address.Address, usedGas types.BigInt) *VMContext {
@@ -309,7 +313,7 @@ type VM struct {
Syscalls *types.VMSyscalls
}
func NewVM(base cid.Cid, height uint64, r Rand, maddr address.Address, cbs blockstore.Blockstore) (*VM, error) {
func NewVM(base cid.Cid, height uint64, r Rand, maddr address.Address, cbs blockstore.Blockstore, syscalls *types.VMSyscalls) (*VM, error) {
buf := bufbstore.NewBufferedBstore(cbs)
cst := hamt.CSTFromBstore(buf)
state, err := state.LoadStateTree(cst, base)
@@ -324,9 +328,9 @@ func NewVM(base cid.Cid, height uint64, r Rand, maddr address.Address, cbs block
buf: buf,
blockHeight: height,
blockMiner: maddr,
inv: newInvoker(),
rand: r,
Syscalls: DefaultSyscalls(),
inv: NewInvoker(),
rand: r, // TODO: Probably should be a syscall
Syscalls: syscalls,
}, nil
}
@@ -427,7 +431,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
}
st := vm.cstate
if err := st.Snapshot(); err != nil {
if err := st.Snapshot(ctx); err != nil {
return nil, xerrors.Errorf("snapshot failed: %w", err)
}
@@ -464,7 +468,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
return nil, xerrors.Errorf("[from=%s,to=%s,n=%d,m=%d,h=%d] fatal error: %w", msg.From, msg.To, msg.Nonce, msg.Method, vm.blockHeight, actorErr)
}
if actorErr != nil {
log.Warnf("[from=%s,to=%s,n=%d,m=%d,h=%d] Send actor error: %+v", msg.From, msg.To, msg.Nonce, msg.Method, vm.blockHeight, actorErr)
log.Warnw("Send actor error", "from", msg.From, "to", msg.To, "nonce", msg.Nonce, "method", msg.Method, "height", vm.blockHeight, "error", fmt.Sprintf("%+v", actorErr))
}
var errcode uint8
@@ -531,7 +535,7 @@ func (vm *VM) Flush(ctx context.Context) (cid.Cid, error) {
from := vm.buf
to := vm.buf.Read()
root, err := vm.cstate.Flush()
root, err := vm.cstate.Flush(ctx)
if err != nil {
return cid.Undef, xerrors.Errorf("flushing vm: %w", err)
}
@@ -668,6 +672,10 @@ func Transfer(from, to *types.Actor, amt types.BigInt) error {
return nil
}
func (vm *VM) SetInvoker(i *invoker) {
vm.inv = i
}
func deductFunds(act *types.Actor, amt types.BigInt) error {
if act.Balance.LessThan(amt) {
return fmt.Errorf("not enough funds")
+2
View File
@@ -7,6 +7,8 @@ import (
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/types"
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
)
const HalvingPeriodEpochs = 6 * 365 * 24 * 60 * 2
+17 -64
View File
@@ -2,20 +2,16 @@ package wallet
import (
"context"
"fmt"
"sort"
"strings"
"sync"
bls "github.com/filecoin-project/filecoin-ffi"
logging "github.com/ipfs/go-log"
"github.com/minio/blake2b-simd"
logging "github.com/ipfs/go-log/v2"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-crypto"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/sigs"
)
var log = logging.Logger("wallet")
@@ -61,31 +57,7 @@ func (w *Wallet) Sign(ctx context.Context, addr address.Address, msg []byte) (*t
return nil, xerrors.Errorf("signing using key '%s': %w", addr.String(), types.ErrKeyInfoNotFound)
}
switch ki.Type {
case types.KTSecp256k1:
b2sum := blake2b.Sum256(msg)
sig, err := crypto.Sign(ki.PrivateKey, b2sum[:])
if err != nil {
return nil, err
}
return &types.Signature{
Type: types.KTSecp256k1,
Data: sig,
}, nil
case types.KTBLS:
var pk bls.PrivateKey
copy(pk[:], ki.PrivateKey)
sig := bls.PrivateKeySign(pk, msg)
return &types.Signature{
Type: types.KTBLS,
Data: sig[:],
}, nil
default:
return nil, fmt.Errorf("cannot sign with unsupported key type: %q", ki.Type)
}
return sigs.Sign(ki.Type, ki.PrivateKey, msg)
}
func (w *Wallet) findKey(addr address.Address) (*Key, error) {
@@ -204,29 +176,15 @@ func (w *Wallet) SetDefault(a address.Address) error {
}
func GenerateKey(typ string) (*Key, error) {
switch typ {
case types.KTSecp256k1:
priv, err := crypto.GenerateKey()
if err != nil {
return nil, err
}
ki := types.KeyInfo{
Type: typ,
PrivateKey: priv,
}
return NewKey(ki)
case types.KTBLS:
priv := bls.PrivateKeyGenerate()
ki := types.KeyInfo{
Type: typ,
PrivateKey: priv[:],
}
return NewKey(ki)
default:
return nil, xerrors.Errorf("invalid key type: %s", typ)
pk, err := sigs.Generate(typ)
if err != nil {
return nil, err
}
ki := types.KeyInfo{
Type: typ,
PrivateKey: pk,
}
return NewKey(ki)
}
func (w *Wallet) GenerateKey(typ string) (address.Address, error) {
@@ -277,28 +235,23 @@ func NewKey(keyinfo types.KeyInfo) (*Key, error) {
KeyInfo: keyinfo,
}
var err error
k.PublicKey, err = sigs.ToPublic(k.Type, k.PrivateKey)
if err != nil {
return nil, err
}
switch k.Type {
case types.KTSecp256k1:
k.PublicKey = crypto.PublicKey(k.PrivateKey)
var err error
k.Address, err = address.NewSecp256k1Address(k.PublicKey)
if err != nil {
return nil, xerrors.Errorf("converting Secp256k1 to address: %w", err)
}
case types.KTBLS:
var pk bls.PrivateKey
copy(pk[:], k.PrivateKey)
pub := bls.PrivateKeyPublicKey(pk)
k.PublicKey = pub[:]
var err error
k.Address, err = address.NewBLSAddress(k.PublicKey)
if err != nil {
return nil, xerrors.Errorf("converting BLS to address: %w", err)
}
default:
return nil, xerrors.Errorf("unknown key type")
}
+237 -3
View File
@@ -1,9 +1,13 @@
package cli
import (
"bytes"
"context"
"encoding/json"
"fmt"
"os"
"os/exec"
"strconv"
"strings"
"time"
@@ -12,6 +16,7 @@ import (
"gopkg.in/urfave/cli.v2"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors"
types "github.com/filecoin-project/lotus/chain/types"
)
@@ -26,6 +31,9 @@ var chainCmd = &cli.Command{
chainSetHeadCmd,
chainListCmd,
chainGetCmd,
chainBisectCmd,
chainExportCmd,
slashConsensusFault,
},
}
@@ -172,6 +180,10 @@ var chainGetMsgCmd = &cli.Command{
Name: "getmessage",
Usage: "Get and print a message by its cid",
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return fmt.Errorf("must pass a cid of a message to get")
}
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
@@ -238,7 +250,7 @@ var chainSetHeadCmd = &cli.Command{
ts, err = api.ChainGetGenesis(ctx)
}
if ts == nil && cctx.IsSet("epoch") {
ts, err = api.ChainGetTipSetByHeight(ctx, cctx.Uint64("epoch"), nil)
ts, err = api.ChainGetTipSetByHeight(ctx, cctx.Uint64("epoch"), types.EmptyTSK)
}
if ts == nil {
ts, err = parseTipSet(api, ctx, cctx.Args().Slice())
@@ -251,7 +263,7 @@ var chainSetHeadCmd = &cli.Command{
return fmt.Errorf("must pass cids for tipset to set as head")
}
if err := api.ChainSetHead(ctx, ts); err != nil {
if err := api.ChainSetHead(ctx, ts.Key()); err != nil {
return err
}
@@ -301,7 +313,7 @@ var chainListCmd = &cli.Command{
var head *types.TipSet
if cctx.IsSet("height") {
head, err = api.ChainGetTipSetByHeight(ctx, cctx.Uint64("height"), nil)
head, err = api.ChainGetTipSetByHeight(ctx, cctx.Uint64("height"), types.EmptyTSK)
} else {
head, err = api.ChainHead(ctx)
}
@@ -380,8 +392,230 @@ func printTipSet(format string, ts *types.TipSet) {
blks += fmt.Sprintf("%s: %s,", b.Cid(), b.Miner)
}
blks += " ]"
sCids := make([]string, 0, len(blks))
for _, c := range ts.Cids() {
sCids = append(sCids, c.String())
}
format = strings.ReplaceAll(format, "<tipset>", strings.Join(sCids, ","))
format = strings.ReplaceAll(format, "<blocks>", blks)
format = strings.ReplaceAll(format, "<weight>", fmt.Sprint(ts.Blocks()[0].ParentWeight))
fmt.Println(format)
}
var chainBisectCmd = &cli.Command{
Name: "bisect",
Usage: "bisect chain for an event",
Description: `Bisect the chain state tree:
lotus chain bisect [min height] [max height] '1/2/3/state/path' 'shell command' 'args'
Returns the first tipset in which condition is true
v
[start] FFFFFFFTTT [end]
Example: find height at which deal ID 100 000 appeared
- lotus chain bisect 1 32000 '@Ha:t03/1' jq -e '.[2] > 100000'
For special path elements see 'chain get' help
`,
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
if cctx.Args().Len() < 4 {
return xerrors.New("need at least 4 args")
}
start, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
if err != nil {
return err
}
end, err := strconv.ParseUint(cctx.Args().Get(1), 10, 64)
if err != nil {
return err
}
subPath := cctx.Args().Get(2)
highest, err := api.ChainGetTipSetByHeight(ctx, end, types.EmptyTSK)
if err != nil {
return err
}
prev := highest.Height()
for {
mid := (start + end) / 2
if end-start == 1 {
mid = end
start = end
}
midTs, err := api.ChainGetTipSetByHeight(ctx, mid, highest.Key())
if err != nil {
return err
}
path := "/ipld/" + midTs.ParentState().String() + "/" + subPath
fmt.Printf("* Testing %d (%d - %d) (%s): ", mid, start, end, path)
nd, err := api.ChainGetNode(ctx, path)
if err != nil {
return err
}
b, err := json.MarshalIndent(nd, "", "\t")
if err != nil {
return err
}
cmd := exec.CommandContext(ctx, cctx.Args().Get(3), cctx.Args().Slice()[4:]...)
cmd.Stdin = bytes.NewReader(b)
var out bytes.Buffer
cmd.Stdout = &out
switch cmd.Run().(type) {
case nil:
// it's lower
end = mid
highest = midTs
fmt.Println("true")
case *exec.ExitError:
start = mid
fmt.Println("false")
default:
return err
}
if start == end {
if strings.TrimSpace(out.String()) == "true" {
fmt.Println(midTs.Height())
} else {
fmt.Println(prev)
}
return nil
}
prev = mid
}
},
}
var chainExportCmd = &cli.Command{
Name: "export",
Usage: "export chain to a car file",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "tipset",
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
if !cctx.Args().Present() {
return fmt.Errorf("must specify filename to export chain to")
}
fi, err := os.Create(cctx.Args().First())
if err != nil {
return err
}
defer fi.Close()
ts, err := loadTipSet(ctx, cctx, api)
if err != nil {
return err
}
stream, err := api.ChainExport(ctx, ts.Key())
if err != nil {
return err
}
for b := range stream {
_, err := fi.Write(b)
if err != nil {
return err
}
}
return nil
},
}
var slashConsensusFault = &cli.Command{
Name: "slash-consensus",
Usage: "Report consensus fault",
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
c1, err := cid.Parse(cctx.Args().Get(0))
if err != nil {
return xerrors.Errorf("parsing cid 1: %w", err)
}
b1, err := api.ChainGetBlock(ctx, c1)
if err != nil {
return xerrors.Errorf("getting block 1: %w", err)
}
c2, err := cid.Parse(cctx.Args().Get(1))
if err != nil {
return xerrors.Errorf("parsing cid 2: %w", err)
}
b2, err := api.ChainGetBlock(ctx, c2)
if err != nil {
return xerrors.Errorf("getting block 2: %w", err)
}
def, err := api.WalletDefaultAddress(ctx)
if err != nil {
return err
}
params, err := actors.SerializeParams(&actors.ArbitrateConsensusFaultParams{
Block1: b1,
Block2: b2,
})
msg := &types.Message{
To: actors.StoragePowerAddress,
From: def,
Value: types.NewInt(0),
GasPrice: types.NewInt(1),
GasLimit: types.NewInt(10000000),
Method: actors.SPAMethods.ArbitrateConsensusFault,
Params: params,
}
smsg, err := api.MpoolPushMessage(ctx, msg)
if err != nil {
return err
}
fmt.Println(smsg.Cid())
return nil
},
}
+1 -1
View File
@@ -295,7 +295,7 @@ var clientQueryAskCmd = &cli.Command{
To: maddr,
From: maddr,
Method: actors.MAMethods.GetPeerID,
}, nil)
}, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("failed to get peerID for miner: %w", err)
}
+3 -1
View File
@@ -9,7 +9,7 @@ import (
"strings"
"syscall"
logging "github.com/ipfs/go-log"
logging "github.com/ipfs/go-log/v2"
"github.com/mitchellh/go-homedir"
"github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr-net"
@@ -202,6 +202,7 @@ var Commands = []*cli.Command{
clientCmd,
fetchParamCmd,
mpoolCmd,
multisigCmd,
netCmd,
paychCmd,
sendCmd,
@@ -209,4 +210,5 @@ var Commands = []*cli.Command{
syncCmd,
versionCmd,
walletCmd,
logCmd,
}
+101
View File
@@ -0,0 +1,101 @@
package cli
import (
"fmt"
"golang.org/x/xerrors"
"gopkg.in/urfave/cli.v2"
)
var logCmd = &cli.Command{
Name: "log",
Usage: "Manage logging",
Subcommands: []*cli.Command{
logList,
logSetLevel,
},
}
var logList = &cli.Command{
Name: "list",
Usage: "List log systems",
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
systems, err := api.LogList(ctx)
if err != nil {
return err
}
for _, system := range systems {
fmt.Println(system)
}
return nil
},
}
var logSetLevel = &cli.Command{
Name: "set-level",
Usage: "Set log level",
ArgsUsage: "<level>",
Description: `Set the log level for logging systems:
The system flag can be specified multiple times.
eg) log set-level --system chain --system blocksync debug
Available Levels:
debug
info
warn
error
Environment Variables:
GOLOG_LOG_LEVEL - Default log level for all log systems
GOLOG_LOG_FMT - Change output log format (json, nocolor)
GOLOG_FILE - Write logs to file in addition to stderr
`,
Flags: []cli.Flag{
&cli.StringSliceFlag{
Name: "system",
Usage: "limit to log system",
Value: &cli.StringSlice{},
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
if !cctx.Args().Present() {
return fmt.Errorf("level is required")
}
systems := cctx.StringSlice("system")
if len(systems) == 0 {
var err error
systems, err = api.LogList(ctx)
if err != nil {
return err
}
}
for _, system := range systems {
if err := api.LogSetLevel(ctx, system, cctx.Args().First()); err != nil {
return xerrors.Errorf("setting log level on %s: %w", system, err)
}
}
return nil
},
}
+5 -4
View File
@@ -33,7 +33,7 @@ var mpoolPending = &cli.Command{
ctx := ReqContext(cctx)
msgs, err := api.MpoolPending(ctx, nil)
msgs, err := api.MpoolPending(ctx, types.EmptyTSK)
if err != nil {
return err
}
@@ -103,7 +103,7 @@ var mpoolStat = &cli.Command{
return xerrors.Errorf("getting chain head: %w", err)
}
msgs, err := api.MpoolPending(ctx, nil)
msgs, err := api.MpoolPending(ctx, types.EmptyTSK)
if err != nil {
return err
}
@@ -122,9 +122,10 @@ var mpoolStat = &cli.Command{
bkt.msgs[v.Message.Nonce] = v
}
for a, bkt := range buckets {
act, err := api.StateGetActor(ctx, a, ts)
act, err := api.StateGetActor(ctx, a, ts.Key())
if err != nil {
return err
fmt.Printf("%s, err: %s\n", a, err)
continue
}
cur := act.Nonce
+400
View File
@@ -0,0 +1,400 @@
package cli
import (
"bytes"
"encoding/hex"
"fmt"
"os"
"strconv"
"text/tabwriter"
"github.com/filecoin-project/go-address"
actors "github.com/filecoin-project/lotus/chain/actors"
types "github.com/filecoin-project/lotus/chain/types"
cbg "github.com/whyrusleeping/cbor-gen"
"gopkg.in/urfave/cli.v2"
)
var multisigCmd = &cli.Command{
Name: "msig",
Usage: "Interact with a multisig wallet",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "source",
Usage: "specify the account to send propose from",
},
},
Subcommands: []*cli.Command{
msigCreateCmd,
msigInspectCmd,
msigProposeCmd,
msigApproveCmd,
},
}
var msigCreateCmd = &cli.Command{
Name: "create",
Usage: "Create a new multisig wallet",
Flags: []cli.Flag{
&cli.Uint64Flag{
Name: "required",
},
&cli.StringFlag{
Name: "value",
Usage: "initial funds to give to multisig",
Value: "0",
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
var addrs []address.Address
for _, a := range cctx.Args().Slice() {
addr, err := address.NewFromString(a)
if err != nil {
return err
}
addrs = append(addrs, addr)
}
// get the address we're going to use to create the multisig (can be one of the above, as long as they have funds)
sendAddr, err := api.WalletDefaultAddress(ctx)
if err != nil {
return err
}
val := cctx.String("value")
filval, err := types.ParseFIL(val)
if err != nil {
return err
}
required := cctx.Uint64("required")
if required == 0 {
required = uint64(len(addrs))
}
// Set up constructor parameters for multisig
msigParams := &actors.MultiSigConstructorParams{
Signers: addrs,
Required: required,
}
enc, err := actors.SerializeParams(msigParams)
if err != nil {
return err
}
// new actors are created by invoking 'exec' on the init actor with the constructor params
execParams := &actors.ExecParams{
Code: actors.MultisigCodeCid,
Params: enc,
}
enc, err = actors.SerializeParams(execParams)
if err != nil {
return err
}
// now we create the message to send this with
msg := types.Message{
To: actors.InitAddress,
From: sendAddr,
Method: actors.IAMethods.Exec,
Params: enc,
GasPrice: types.NewInt(1),
GasLimit: types.NewInt(1000000),
Value: types.BigInt(filval),
}
// send the message out to the network
smsg, err := api.MpoolPushMessage(ctx, &msg)
if err != nil {
return err
}
// wait for it to get mined into a block
wait, err := api.StateWaitMsg(ctx, smsg.Cid())
if err != nil {
return err
}
// check it executed successfully
if wait.Receipt.ExitCode != 0 {
fmt.Println("actor creation failed!")
return err
}
// get address of newly created miner
msigaddr, err := address.NewFromBytes(wait.Receipt.Return)
if err != nil {
return err
}
fmt.Println("Created new multisig: ", msigaddr.String())
// TODO: maybe register this somewhere
return nil
},
}
var msigInspectCmd = &cli.Command{
Name: "inspect",
Usage: "Inspect a multisig wallet",
Flags: []cli.Flag{},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
if !cctx.Args().Present() {
return fmt.Errorf("must specify address of multisig to inspect")
}
maddr, err := address.NewFromString(cctx.Args().First())
if err != nil {
return err
}
act, err := api.StateGetActor(ctx, maddr, types.EmptyTSK)
if err != nil {
return err
}
obj, err := api.ChainReadObj(ctx, act.Head)
if err != nil {
return err
}
var mstate actors.MultiSigActorState
if err := mstate.UnmarshalCBOR(bytes.NewReader(obj)); err != nil {
return err
}
fmt.Printf("Balance: %sfil\n", types.FIL(act.Balance))
fmt.Printf("Threshold: %d / %d\n", mstate.Required, len(mstate.Signers))
fmt.Println("Signers:")
for _, s := range mstate.Signers {
fmt.Printf("\t%s\n", s)
}
fmt.Println("Transactions: ", len(mstate.Transactions))
if len(mstate.Transactions) > 0 {
w := tabwriter.NewWriter(os.Stdout, 8, 4, 0, ' ', 0)
fmt.Fprintf(w, "ID\tState\tTo\tValue\tMethod\tParams\n")
for _, tx := range mstate.Transactions {
fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%d\t%x\n", tx.TxID, state(tx), tx.To, types.FIL(tx.Value), tx.Method, tx.Params)
}
w.Flush()
}
return nil
},
}
func state(tx actors.MTransaction) string {
if tx.Complete {
return "done"
}
if tx.Canceled {
return "canceled"
}
return "pending"
}
var msigProposeCmd = &cli.Command{
Name: "propose",
Usage: "Propose a multisig transaction",
Flags: []cli.Flag{},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
if cctx.Args().Len() < 3 {
return fmt.Errorf("must pass multisig address, destination, and value")
}
if cctx.Args().Len() > 3 && cctx.Args().Len() != 5 {
return fmt.Errorf("usage: msig propose <msig addr> <desination> <value> [ <method> <params> ]")
}
msig, err := address.NewFromString(cctx.Args().Get(0))
if err != nil {
return err
}
dest, err := address.NewFromString(cctx.Args().Get(1))
if err != nil {
return err
}
value, err := types.ParseFIL(cctx.Args().Get(2))
if err != nil {
return err
}
var method uint64
var params []byte
if cctx.Args().Len() == 5 {
m, err := strconv.ParseUint(cctx.Args().Get(3), 10, 64)
if err != nil {
return err
}
method = m
p, err := hex.DecodeString(cctx.Args().Get(4))
if err != nil {
return err
}
params = p
}
enc, err := actors.SerializeParams(&actors.MultiSigProposeParams{
To: dest,
Value: types.BigInt(value),
Method: method,
Params: params,
})
if err != nil {
return err
}
var from address.Address
if cctx.IsSet("source") {
f, err := address.NewFromString(cctx.String("source"))
if err != nil {
return err
}
from = f
} else {
defaddr, err := api.WalletDefaultAddress(ctx)
if err != nil {
return err
}
from = defaddr
}
msg := &types.Message{
To: msig,
From: from,
Value: types.NewInt(0),
Method: actors.MultiSigMethods.Propose,
Params: enc,
GasLimit: types.NewInt(100000),
GasPrice: types.NewInt(1),
}
smsg, err := api.MpoolPushMessage(ctx, msg)
if err != nil {
return err
}
fmt.Println("send proposal in message: ", smsg.Cid())
wait, err := api.StateWaitMsg(ctx, smsg.Cid())
if err != nil {
return err
}
if wait.Receipt.ExitCode != 0 {
return fmt.Errorf("proposal returned exit %d", wait.Receipt.ExitCode)
}
_, v, err := cbg.CborReadHeader(bytes.NewReader(wait.Receipt.Return))
if err != nil {
return err
}
fmt.Printf("Transaction ID: %d\n", v)
return nil
},
}
var msigApproveCmd = &cli.Command{
Name: "approve",
Usage: "Approve a multisig transaction",
Flags: []cli.Flag{},
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 fmt.Errorf("must pass multisig address and transaction ID")
}
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
}
enc, err := actors.SerializeParams(&actors.MultiSigTxID{
TxID: txid,
})
if err != nil {
return err
}
var from address.Address
if cctx.IsSet("source") {
f, err := address.NewFromString(cctx.String("source"))
if err != nil {
return err
}
from = f
} else {
defaddr, err := api.WalletDefaultAddress(ctx)
if err != nil {
return err
}
from = defaddr
}
msg := &types.Message{
To: msig,
From: from,
Value: types.NewInt(0),
Method: actors.MultiSigMethods.Approve,
Params: enc,
GasLimit: types.NewInt(100000),
GasPrice: types.NewInt(1),
}
smsg, err := api.MpoolPushMessage(ctx, msg)
if err != nil {
return err
}
fmt.Println("sent approval in message: ", smsg.Cid())
wait, err := api.StateWaitMsg(ctx, smsg.Cid())
if err != nil {
return err
}
if wait.Receipt.ExitCode != 0 {
return fmt.Errorf("approve returned exit %d", wait.Receipt.ExitCode)
}
return nil
},
}
+3 -1
View File
@@ -5,6 +5,8 @@ import (
paramfetch "github.com/filecoin-project/go-paramfetch"
"golang.org/x/xerrors"
"gopkg.in/urfave/cli.v2"
"github.com/filecoin-project/lotus/build"
)
var fetchParamCmd = &cli.Command{
@@ -22,7 +24,7 @@ var fetchParamCmd = &cli.Command{
return err
}
sectorSize := uint64(sectorSizeInt)
err = paramfetch.GetParams(sectorSize)
err = paramfetch.GetParams(build.ParametersJson(), sectorSize)
if err != nil {
return xerrors.Errorf("fetching proof parameters: %w", err)
}
+1 -1
View File
@@ -15,7 +15,7 @@ var sendCmd = &cli.Command{
Flags: []cli.Flag{
&cli.StringFlag{
Name: "source",
Usage: "optinally specifiy the account to send funds from",
Usage: "optionally specify the account to send funds from",
},
},
Action: func(cctx *cli.Context) error {

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