Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bb84acbc5 | ||
|
|
22f49f8946 | ||
|
|
1350079503 | ||
|
|
251374eca7 | ||
|
|
a50a5366b2 | ||
|
|
52800f5dca | ||
|
|
958f169267 | ||
|
|
df6f4a572c | ||
|
|
698b49b7ef | ||
|
|
7e5b1ac272 | ||
|
|
86e30729bf | ||
|
|
7ccb2aabf0 | ||
|
|
811f1304e6 | ||
|
|
6de82364e9 | ||
|
|
d02d4bc275 | ||
|
|
39670df6af | ||
|
|
28823fb8e9 | ||
|
|
ddade32bd3 | ||
|
|
15fe998c68 | ||
|
|
4b38809c0b | ||
|
|
e2fbbdcb15 | ||
|
|
bbc6de94fc | ||
|
|
ea1349205b | ||
|
|
470a565c34 | ||
|
|
04bbeface6 | ||
|
|
8df58064e3 | ||
|
|
01de4cb2ec | ||
|
|
b060569fe9 | ||
|
|
dfd6fbfaa4 | ||
|
|
d3d304bfd7 | ||
|
|
ab4f051b83 | ||
|
|
00a5083146 | ||
|
|
c6ed6a0d65 | ||
|
|
4ad8d85b13 | ||
|
|
465703b618 | ||
|
|
30dd5d9644 | ||
|
|
41bfeb56e2 | ||
|
|
2e7cd024df | ||
|
|
bf619862c3 | ||
|
|
29e54c40be | ||
|
|
308144ee6a | ||
|
|
ce54110228 | ||
|
|
458ea277fc | ||
|
|
58662b79b3 | ||
|
|
7dbc8965be | ||
|
|
2426700821 | ||
|
|
9c6ee802cc | ||
|
|
b61281ba4b | ||
|
|
d5cea9f402 | ||
|
|
ce548c8f95 | ||
|
|
8987defb9d | ||
|
|
1a70dbe37d | ||
|
|
87cd8c6725 | ||
|
|
1eb2d0ae50 | ||
|
|
5fd0bf11ba | ||
|
|
4edebcec2b | ||
|
|
07d0b67628 | ||
|
|
9b4cac9612 | ||
|
|
8232cc8415 | ||
|
|
be74a13736 | ||
|
|
195d96ccc0 | ||
|
|
49155ace62 | ||
|
|
83624a8858 | ||
|
|
96e1dfd8d7 | ||
|
|
61661fb1f0 | ||
|
|
6c08120628 | ||
|
|
8d769f0c07 | ||
|
|
79c5d2c6d2 | ||
|
|
224a96431f | ||
|
|
8001ed3030 | ||
|
|
2855c2bc49 | ||
|
|
65883cbb6b | ||
|
|
443131b214 | ||
|
|
8b648cf77c | ||
|
|
c0961fb63d | ||
|
|
dc4e73c737 | ||
|
|
a6b2180756 | ||
|
|
160f209f6a | ||
|
|
a9d8bc7c45 | ||
|
|
92177b5738 | ||
|
|
4ac2bee81c | ||
|
|
a2e0832a12 | ||
|
|
8fd9b5f235 | ||
|
|
a95e343dee | ||
|
|
c296e1bbca | ||
|
|
ae366972a9 | ||
|
|
b4215e5f46 | ||
|
|
df7ee610cd | ||
|
|
fda8b932ba | ||
|
|
7b4a5fc7ca | ||
|
|
d6c8276c7a | ||
|
|
2b21fdef33 | ||
|
|
6a232e7214 | ||
|
|
7ee6bafd23 | ||
|
|
753d7b71a9 | ||
|
|
bb6a354b62 | ||
|
|
8ae66d6c6a | ||
|
|
2c92157233 | ||
|
|
66d6113340 | ||
|
|
99791a6953 | ||
|
|
b35f9b56b4 | ||
|
|
23470bc38f | ||
|
|
40b2e2d0c1 | ||
|
|
85be11fb75 | ||
|
|
00620aac57 | ||
|
|
32d95fc97a | ||
|
|
a491fc97b9 | ||
|
|
151577f04e | ||
|
|
c463582528 | ||
|
|
7245ac2b69 | ||
|
|
58f13a7d5a | ||
|
|
e7d3b2503e | ||
|
|
ee8b8b8174 | ||
|
|
4fa6afad13 | ||
|
|
a80e98dc05 | ||
|
|
23f5a99117 | ||
|
|
651522cbaa | ||
|
|
388c9afce0 | ||
|
|
9a26896c69 | ||
|
|
2db8b7efa7 | ||
|
|
18e58467f8 | ||
|
|
1401efb115 | ||
|
|
f417d39a08 | ||
|
|
11e35cf911 | ||
|
|
10d464a1eb | ||
|
|
d84f5dabab | ||
|
|
f3abd1ae82 | ||
|
|
85abca4b16 | ||
|
|
6610a247cf | ||
|
|
a6d9b302fa | ||
|
|
f32b3bf99b | ||
|
|
114a1aaffd | ||
|
|
83ba7ec8cc | ||
|
|
83dfc460d4 | ||
|
|
283fd054e8 | ||
|
|
09bff14d85 | ||
|
|
3cb1abba4f | ||
|
|
e0dcb0ec49 | ||
|
|
d4c92942e7 | ||
|
|
f773ab4b28 | ||
|
|
c0182f8301 | ||
|
|
c06f394b81 | ||
|
|
748d2e82a7 | ||
|
|
a5c78371fd | ||
|
|
d80e7eda93 | ||
|
|
9f9d5cb2a5 | ||
|
|
fdaa9c14ad | ||
|
|
9d8932d395 | ||
|
|
105aa40007 | ||
|
|
110f033c83 | ||
|
|
f87d325b6f | ||
|
|
ab8286fa38 | ||
|
|
4cca3f19a3 | ||
|
|
feb4b3c8b4 | ||
|
|
7f7c9e978f | ||
|
|
200a95f824 | ||
|
|
d69e4c7cf2 | ||
|
|
b2834baa4b | ||
|
|
e9e27cbbb0 | ||
|
|
ef73b964fb | ||
|
|
7b1bec91ed | ||
|
|
b32d25c562 | ||
|
|
767611247c | ||
|
|
be09a8a00a | ||
|
|
2719adc1b1 | ||
|
|
f1b1d8cec6 | ||
|
|
8fa4c0a970 | ||
|
|
00a14de094 | ||
|
|
eec13ff8dc | ||
|
|
1ffdd7d5b3 | ||
|
|
e19cd9ed01 | ||
|
|
bacac245c7 | ||
|
|
e1792ffe4d | ||
|
|
9c35762966 | ||
|
|
356137439f | ||
|
|
6cc7559b04 | ||
|
|
3cd53ad9d9 | ||
|
|
6c54d2445d | ||
|
|
6a10af626c | ||
|
|
597d065e05 | ||
|
|
791aa5c6c8 | ||
|
|
82b15d2637 | ||
|
|
7d2f06cfbd | ||
|
|
6e8efb9d2c | ||
|
|
f3dc730b05 | ||
|
|
114776f2c5 | ||
|
|
4835109470 | ||
|
|
8783c7434e | ||
|
|
2d3b61675b | ||
|
|
a23ab123d7 | ||
|
|
26ed6af040 | ||
|
|
82bd7bd2ec | ||
|
|
cd0a43b7f4 | ||
|
|
b14632b750 | ||
|
|
ebcf77e830 | ||
|
|
344d30e960 | ||
|
|
efb13a0d9b | ||
|
|
0223582d41 | ||
|
|
973f61bc10 | ||
|
|
60768f4863 | ||
|
|
c60d13ee56 | ||
|
|
0f8fc119f3 | ||
|
|
e4d2e6e01d | ||
|
|
d55f10bed6 | ||
|
|
21de538d09 | ||
|
|
fe5b32026a | ||
|
|
91c10c2df5 | ||
|
|
c3420c0ceb | ||
|
|
7933cf094f | ||
|
|
4cd73f1560 | ||
|
|
8a175a7465 | ||
|
|
f7f229ae54 | ||
|
|
1323e07a2c | ||
|
|
2ad671649c | ||
|
|
d26ece10b8 | ||
|
|
4c8084dcb0 | ||
|
|
98d702fb5a | ||
|
|
17f61ac212 | ||
|
|
df67576b89 | ||
|
|
cdc2f86f5a | ||
|
|
67b3a55e30 | ||
|
|
3201e0eb8f | ||
|
|
8d2d74438b | ||
|
|
1f9446f91f | ||
|
|
4937ca1a96 | ||
|
|
264fe4edb9 | ||
|
|
cb7d99fcc7 | ||
|
|
7332a39f00 | ||
|
|
cd9af278b4 | ||
|
|
8f4911ac0d | ||
|
|
12cd478e11 | ||
|
|
e55b00f358 | ||
|
|
6f4a762664 | ||
|
|
c02daca9e9 | ||
|
|
5bd6a3cdad | ||
|
|
ef3987e2ab | ||
|
|
780f6dba34 | ||
|
|
f90cfda2e6 |
@@ -12,6 +12,7 @@
|
||||
/lotus-bench
|
||||
/lotus-gateway
|
||||
/lotus-pcr
|
||||
/lotus-wallet
|
||||
/bench.json
|
||||
/lotuspond/front/node_modules
|
||||
/lotuspond/front/build
|
||||
|
||||
@@ -1,5 +1,85 @@
|
||||
# Lotus changelog
|
||||
|
||||
# 0.10.2 / 2020-10-14
|
||||
|
||||
This is an optional release of Lotus that updates markets to 0.9.1, which fixes an issue affecting deals that were mid-transfer when the node was upgraded to 0.9.0. This release also includes some tweaks to default gas values and minor performance improvements.
|
||||
|
||||
## Changes
|
||||
|
||||
- Use updated stored ask API (https://github.com/filecoin-project/lotus/pull/4384)
|
||||
- tvx: trace puts to blockstore for inclusion in CAR. (https://github.com/filecoin-project/lotus/pull/4278)
|
||||
- Add propose remove (https://github.com/filecoin-project/lotus/pull/4311)
|
||||
- Update to 0.9.1 bugfix release (https://github.com/filecoin-project/lotus/pull/4402)
|
||||
- Update drand endpoints (https://github.com/filecoin-project/lotus/pull/4125)
|
||||
- fix: return true when deadlines changed (https://github.com/filecoin-project/lotus/pull/4403)
|
||||
- sync wait --watch (https://github.com/filecoin-project/lotus/pull/4396)
|
||||
- reduce garbage in blockstore (https://github.com/filecoin-project/lotus/pull/4406)
|
||||
- give the TimeCacheBS tests a bit more time (https://github.com/filecoin-project/lotus/pull/4407)
|
||||
- Improve gas defaults (https://github.com/filecoin-project/lotus/pull/4408)
|
||||
- Change default gas premium to for 10 block inclusion (https://github.com/filecoin-project/lotus/pull/4222)
|
||||
|
||||
# 0.10.1 / 2020-10-14
|
||||
|
||||
This is an optional release of Lotus that updates markets to 0.9.0, which adds the ability to restart data transfers. This release also introduces Ledger support, and various UX improvements.
|
||||
|
||||
## Changes
|
||||
|
||||
- Test the tape upgrade (https://github.com/filecoin-project/lotus/pull/4328)
|
||||
- Adding in Ledger support (https://github.com/filecoin-project/lotus/pull/4290)
|
||||
- Improve the UX for lotus-miner sealing workers (https://github.com/filecoin-project/lotus/pull/4329)
|
||||
- Add a CLI tool for miner's to repay debt (https://github.com/filecoin-project/lotus/pull/4319)
|
||||
- Rename params_testnet to params_mainnet (https://github.com/filecoin-project/lotus/pull/4336)
|
||||
- Use seal-duration in calculating the earliest StartEpoch (https://github.com/filecoin-project/lotus/pull/4337)
|
||||
- Reject deals that are > 7 days in the future in the BasicDealFilter (https://github.com/filecoin-project/lotus/pull/4173)
|
||||
- Add an API endpoint to calculate the exact circulating supply (https://github.com/filecoin-project/lotus/pull/4148)
|
||||
- lotus-pcr: ignore all other market messages (https://github.com/filecoin-project/lotus/pull/4341)
|
||||
- Add message CID to InvocResult (https://github.com/filecoin-project/lotus/pull/4382)
|
||||
- types: Add CID fields to messages in json marshalers (https://github.com/filecoin-project/lotus/pull/4338)
|
||||
- fix(sync state): set state height to actual tipset height (https://github.com/filecoin-project/lotus/pull/4347)
|
||||
- Fix off by one tipset in searchBackForMsg (https://github.com/filecoin-project/lotus/pull/4367)
|
||||
- fix a panic on startup when we fail to load the tipset (https://github.com/filecoin-project/lotus/pull/4376)
|
||||
- Avoid having the same message CID show up in execution traces (https://github.com/filecoin-project/lotus/pull/4350)
|
||||
- feat(markets): update markets 0.9.0 and add data transfer restart (https://github.com/filecoin-project/lotus/pull/4363)
|
||||
|
||||
# 0.10.0 / 2020-10-12
|
||||
|
||||
This is a consensus-breaking hotfix that addresses an issue in specs-actors v2.0.3 that made it impossible to pledge new 32GiB sectors. The change in Lotus is to update to actors v2.1.0, behind the new network version 5.
|
||||
|
||||
## Changes
|
||||
|
||||
- make pledge test pass with the race detector (https://github.com/filecoin-project/lotus/pull/4291)
|
||||
- fix a race in tipset cache usage (https://github.com/filecoin-project/lotus/pull/4282)
|
||||
- add an api for removing multisig signers (https://github.com/filecoin-project/lotus/pull/4274)
|
||||
- cli: Don't output errors to stdout (https://github.com/filecoin-project/lotus/pull/4298)
|
||||
- Fix panic in wallet export when key is not found (https://github.com/filecoin-project/lotus/pull/4299)
|
||||
- Dump the block validation cache whenever we perform an import (https://github.com/filecoin-project/lotus/pull/4287)
|
||||
- Fix two races (https://github.com/filecoin-project/lotus/pull/4301)
|
||||
- sync unmark-bad --all (https://github.com/filecoin-project/lotus/pull/4296)
|
||||
- decode parameters for multisig transactions in inspect (https://github.com/filecoin-project/lotus/pull/4312)
|
||||
- Chain is love (https://github.com/filecoin-project/lotus/pull/4321)
|
||||
- lotus-stats: optmize getting miner power (https://github.com/filecoin-project/lotus/pull/4315)
|
||||
- implement tape upgrade (https://github.com/filecoin-project/lotus/pull/4322)
|
||||
|
||||
# 0.9.1 / 2020-10-10
|
||||
|
||||
This release fixes an issue which may cause the actors v2 migration to compute the state incorrectly when more than one migration is running in parallel.
|
||||
|
||||
## Changes
|
||||
|
||||
- Make concurrent actor migrations safe (https://github.com/filecoin-project/lotus/pull/4293)
|
||||
- Remote wallet backends (https://github.com/filecoin-project/lotus/pull/3583)
|
||||
- Track funds in FundMgr correctly in case of AddFunds failing (https://github.com/filecoin-project/lotus/pull/4273)
|
||||
- Partial lite-node mode (https://github.com/filecoin-project/lotus/pull/4095)
|
||||
- Fix potential infinite loop in GetBestMiningCandidate (https://github.com/filecoin-project/lotus/pull/3444)
|
||||
- sync wait: Handle processed message offset (https://github.com/filecoin-project/lotus/pull/4253)
|
||||
- Add some new endpoints for querying Msig info (https://github.com/filecoin-project/lotus/pull/4250)
|
||||
- Update markets v0.7.1 (https://github.com/filecoin-project/lotus/pull/4254)
|
||||
- Optimize SearchForMessage and GetReceipt (https://github.com/filecoin-project/lotus/pull/4246)
|
||||
- Use FIL instead of attoFIL in CLI more consistently (https://github.com/filecoin-project/lotus/pull/4249)
|
||||
- fix: clash between daemon --api flag and cli tests (https://github.com/filecoin-project/lotus/pull/4241)
|
||||
- add more info to chain sync lookback failure (https://github.com/filecoin-project/lotus/pull/4245)
|
||||
- Add message counts to inspect chain output (https://github.com/filecoin-project/lotus/pull/4230)
|
||||
|
||||
# 0.9.0 / 2020-10-07
|
||||
|
||||
This consensus-breaking release of Lotus upgrades the actors version to v2.0.0. This requires migrating actor state from v0 to v2. The changes that break consensus are:
|
||||
|
||||
@@ -186,6 +186,12 @@ lotus-health:
|
||||
.PHONY: lotus-health
|
||||
BINS+=lotus-health
|
||||
|
||||
lotus-wallet:
|
||||
rm -f lotus-wallet
|
||||
go build -o lotus-wallet ./cmd/lotus-wallet
|
||||
.PHONY: lotus-wallet
|
||||
BINS+=lotus-wallet
|
||||
|
||||
testground:
|
||||
go build -tags testground -o /dev/null ./cmd/lotus
|
||||
.PHONY: testground
|
||||
|
||||
+3
-9
@@ -2,9 +2,7 @@
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
For *critical* bugs, please send an email to security@filecoin.org.
|
||||
|
||||
The bug reporting process differs between bugs that are critical and may crash the network, and others that are unlikely to cause problems if malicious parties know about it. For non-critical bugs, please simply file a GitHub [issue](https://github.com/filecoin-project/lotus/issues/new?template=bug_report.md).
|
||||
For *critical* bugs, please consult our Security Policy and Responsible Disclosure Program information at https://github.com/filecoin-project/community/blob/master/SECURITY.md
|
||||
|
||||
Please try to provide a clear description of any bugs reported, along with how to reproduce the bug if possible. More detailed bug reports (especially those with a PoC included) will help us move forward much faster. Additionally, please avoid reporting bugs that already have open issues. Take a moment to search the issue list of the related GitHub repositories before writing up a new report.
|
||||
|
||||
@@ -20,10 +18,6 @@ Here are some examples of bugs we would consider 'critical':
|
||||
|
||||
This is not an exhaustive list, but should provide some idea of what we consider 'critical'.
|
||||
|
||||
## Supported Versions
|
||||
## Reporting a non security bug
|
||||
|
||||
* TODO: This should be defined and set up by Mainnet launch.
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| Testnet | :white_check_mark: |
|
||||
For non-critical bugs, please simply file a GitHub [issue](https://github.com/filecoin-project/lotus/issues/new?template=bug_report.md).
|
||||
|
||||
+53
-6
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
@@ -172,6 +173,9 @@ type FullNode interface {
|
||||
// SyncUnmarkBad unmarks a blocks as bad, making it possible to be validated and synced again.
|
||||
SyncUnmarkBad(ctx context.Context, bcid cid.Cid) error
|
||||
|
||||
// SyncUnmarkAllBad purges bad block cache, making it possible to sync to chains previously marked as bad
|
||||
SyncUnmarkAllBad(ctx context.Context) error
|
||||
|
||||
// SyncCheckBad checks if a block was marked as bad, and if it was, returns
|
||||
// the reason.
|
||||
SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error)
|
||||
@@ -226,7 +230,9 @@ type FullNode interface {
|
||||
// MethodGroup: Wallet
|
||||
|
||||
// WalletNew creates a new address in the wallet with the given sigType.
|
||||
WalletNew(context.Context, crypto.SigType) (address.Address, error)
|
||||
// Available key types: bls, secp256k1, secp256k1-ledger
|
||||
// Support for numerical types: 1 - secp256k1, 2 - BLS is deprecated
|
||||
WalletNew(context.Context, types.KeyType) (address.Address, error)
|
||||
// WalletHas indicates whether the given address is in the wallet.
|
||||
WalletHas(context.Context, address.Address) (bool, error)
|
||||
// WalletList lists all the addresses in the wallet.
|
||||
@@ -293,6 +299,8 @@ type FullNode interface {
|
||||
// ClientListTransfers returns the status of all ongoing transfers of data
|
||||
ClientListDataTransfers(ctx context.Context) ([]DataTransferChannel, error)
|
||||
ClientDataTransferUpdates(ctx context.Context) (<-chan DataTransferChannel, error)
|
||||
// ClientRestartDataTransfer attempts to restart a data transfer with the given transfer ID and other peer
|
||||
ClientRestartDataTransfer(ctx context.Context, transferID datatransfer.TransferID, otherPeer peer.ID, isInitiator bool) error
|
||||
// ClientRetrieveTryRestartInsufficientFunds attempts to restart stalled retrievals on a given payment channel
|
||||
// which are stuck due to insufficient funds
|
||||
ClientRetrieveTryRestartInsufficientFunds(ctx context.Context, paymentChannel address.Address) error
|
||||
@@ -367,6 +375,10 @@ type FullNode interface {
|
||||
// StateWaitMsg looks back in the chain for a message. If not found, it blocks until the
|
||||
// message arrives on chain, and gets to the indicated confidence depth.
|
||||
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*MsgLookup, error)
|
||||
// StateWaitMsgLimited looks back up to limit epochs in the chain for a message.
|
||||
// If not found, it blocks until the message arrives on chain, and gets to the
|
||||
// indicated confidence depth.
|
||||
StateWaitMsgLimited(ctx context.Context, cid cid.Cid, confidence uint64, limit abi.ChainEpoch) (*MsgLookup, error)
|
||||
// StateListMiners returns the addresses of every miner that has claimed power in the Power Actor
|
||||
StateListMiners(context.Context, types.TipSetKey) ([]address.Address, error)
|
||||
// StateListActors returns the addresses of every actor in the state
|
||||
@@ -407,8 +419,12 @@ type FullNode interface {
|
||||
// can issue. It takes the deal size and verified status as parameters.
|
||||
StateDealProviderCollateralBounds(context.Context, abi.PaddedPieceSize, bool, types.TipSetKey) (DealCollateralBounds, error)
|
||||
|
||||
// StateCirculatingSupply returns the circulating supply of Filecoin at the given tipset
|
||||
StateCirculatingSupply(context.Context, types.TipSetKey) (CirculatingSupply, error)
|
||||
// StateCirculatingSupply returns the exact circulating supply of Filecoin at the given tipset.
|
||||
// This is not used anywhere in the protocol itself, and is only for external consumption.
|
||||
StateCirculatingSupply(context.Context, types.TipSetKey) (abi.TokenAmount, error)
|
||||
// StateVMCirculatingSupplyInternal returns an approximation of the circulating supply of Filecoin at the given tipset.
|
||||
// This is the value reported by the runtime interface to actors code.
|
||||
StateVMCirculatingSupplyInternal(context.Context, types.TipSetKey) (CirculatingSupply, error)
|
||||
// StateNetworkVersion returns the network version at the given tipset
|
||||
StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error)
|
||||
|
||||
@@ -418,6 +434,8 @@ type FullNode interface {
|
||||
|
||||
// MsigGetAvailableBalance returns the portion of a multisig's balance that can be withdrawn or spent
|
||||
MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
|
||||
// MsigGetVestingSchedule returns the vesting details of a given multisig.
|
||||
MsigGetVestingSchedule(context.Context, address.Address, types.TipSetKey) (MsigVesting, error)
|
||||
// MsigGetVested returns the amount of FIL that vested in a multisig in a certain period.
|
||||
// It takes the following params: <multisig address>, <start epoch>, <end epoch>
|
||||
MsigGetVested(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error)
|
||||
@@ -429,12 +447,21 @@ type FullNode interface {
|
||||
// It takes the following params: <multisig address>, <recipient address>, <value to transfer>,
|
||||
// <sender address of the propose msg>, <method to call in the proposed message>, <params to include in the proposed message>
|
||||
MsigPropose(context.Context, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
|
||||
// MsigApprove approves a previously-proposed multisig message
|
||||
|
||||
// MsigApprove approves a previously-proposed multisig message by transaction ID
|
||||
// It takes the following params: <multisig address>, <proposed transaction ID> <signer address>
|
||||
MsigApprove(context.Context, address.Address, uint64, address.Address) (cid.Cid, error)
|
||||
|
||||
// MsigApproveTxnHash approves a previously-proposed multisig message, specified
|
||||
// using both transaction ID and a hash of the parameters used in the
|
||||
// proposal. This method of approval can be used to ensure you only approve
|
||||
// exactly the transaction you think you are.
|
||||
// It takes the following params: <multisig address>, <proposed message ID>, <proposer address>, <recipient address>, <value to transfer>,
|
||||
// <sender address of the approve msg>, <method to call in the proposed message>, <params to include in the proposed message>
|
||||
MsigApprove(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
|
||||
MsigApproveTxnHash(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
|
||||
|
||||
// MsigCancel cancels a previously-proposed multisig message
|
||||
// It takes the following params: <multisig address>, <proposed message ID>, <recipient address>, <value to transfer>,
|
||||
// It takes the following params: <multisig address>, <proposed transaction ID>, <recipient address>, <value to transfer>,
|
||||
// <sender address of the cancel msg>, <method to call in the proposed message>, <params to include in the proposed message>
|
||||
MsigCancel(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
|
||||
// MsigAddPropose proposes adding a signer in the multisig
|
||||
@@ -462,6 +489,13 @@ type FullNode interface {
|
||||
// <old signer>, <new signer>
|
||||
MsigSwapCancel(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error)
|
||||
|
||||
// MsigRemoveSigner proposes the removal of a signer from the multisig.
|
||||
// It accepts the multisig to make the change on, the proposer address to
|
||||
// send the message from, the address to be removed, and a boolean
|
||||
// indicating whether or not the signing threshold should be lowered by one
|
||||
// along with the address removal.
|
||||
MsigRemoveSigner(ctx context.Context, msig address.Address, proposer address.Address, toRemove address.Address, decrease bool) (cid.Cid, error)
|
||||
|
||||
MarketEnsureAvailable(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error)
|
||||
// MarketFreeBalance
|
||||
|
||||
@@ -703,6 +737,7 @@ type RetrievalOrder struct {
|
||||
}
|
||||
|
||||
type InvocResult struct {
|
||||
MsgCid cid.Cid
|
||||
Msg *types.Message
|
||||
MsgRct *types.MessageReceipt
|
||||
ExecutionTrace types.ExecutionTrace
|
||||
@@ -871,3 +906,15 @@ type Fault struct {
|
||||
Miner address.Address
|
||||
Epoch abi.ChainEpoch
|
||||
}
|
||||
|
||||
var EmptyVesting = MsigVesting{
|
||||
InitialBalance: types.EmptyInt,
|
||||
StartEpoch: -1,
|
||||
UnlockDuration: -1,
|
||||
}
|
||||
|
||||
type MsigVesting struct {
|
||||
InitialBalance abi.TokenAmount
|
||||
StartEpoch abi.ChainEpoch
|
||||
UnlockDuration abi.ChainEpoch
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
type GatewayAPI interface {
|
||||
ChainHead(ctx context.Context) (*types.TipSet, error)
|
||||
ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error)
|
||||
ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error)
|
||||
GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *MessageSendSpec, tsk types.TipSetKey) (*types.Message, error)
|
||||
MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error)
|
||||
MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error)
|
||||
MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error)
|
||||
StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
|
||||
StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)
|
||||
StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
|
||||
StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*MsgLookup, error)
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
type MsgType string
|
||||
|
||||
const (
|
||||
MTUnknown = "unknown"
|
||||
|
||||
// Signing message CID. MsgMeta.Extra contains raw cbor message bytes
|
||||
MTChainMsg = "message"
|
||||
|
||||
// Signing a blockheader. signing raw cbor block bytes (MsgMeta.Extra is empty)
|
||||
MTBlock = "block"
|
||||
|
||||
// Signing a deal proposal. signing raw cbor proposal bytes (MsgMeta.Extra is empty)
|
||||
MTDealProposal = "dealproposal"
|
||||
|
||||
// TODO: Deals, Vouchers, VRF
|
||||
)
|
||||
|
||||
type MsgMeta struct {
|
||||
Type MsgType
|
||||
|
||||
// Additional data related to what is signed. Should be verifiable with the
|
||||
// signed bytes (e.g. CID(Extra).Bytes() == toSign)
|
||||
Extra []byte
|
||||
}
|
||||
|
||||
type WalletAPI interface {
|
||||
WalletNew(context.Context, types.KeyType) (address.Address, error)
|
||||
WalletHas(context.Context, address.Address) (bool, error)
|
||||
WalletList(context.Context) ([]address.Address, error)
|
||||
|
||||
WalletSign(ctx context.Context, signer address.Address, toSign []byte, meta MsgMeta) (*crypto.Signature, error)
|
||||
|
||||
WalletExport(context.Context, address.Address) (*types.KeyInfo, error)
|
||||
WalletImport(context.Context, *types.KeyInfo) (address.Address, error)
|
||||
WalletDelete(context.Context, address.Address) error
|
||||
}
|
||||
@@ -36,3 +36,9 @@ func PermissionedWorkerAPI(a api.WorkerAPI) api.WorkerAPI {
|
||||
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal)
|
||||
return &out
|
||||
}
|
||||
|
||||
func PermissionedWalletAPI(a api.WalletAPI) api.WalletAPI {
|
||||
var out WalletStruct
|
||||
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal)
|
||||
return &out
|
||||
}
|
||||
|
||||
+146
-7
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer"
|
||||
"github.com/filecoin-project/go-fil-markets/piecestore"
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
@@ -111,6 +112,7 @@ type FullNodeStruct struct {
|
||||
SyncCheckpoint func(ctx context.Context, key types.TipSetKey) error `perm:"admin"`
|
||||
SyncMarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"`
|
||||
SyncUnmarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"`
|
||||
SyncUnmarkAllBad func(ctx context.Context) error `perm:"admin"`
|
||||
SyncCheckBad func(ctx context.Context, bcid cid.Cid) (string, error) `perm:"read"`
|
||||
SyncValidateTipset func(ctx context.Context, tsk types.TipSetKey) (bool, error) `perm:"read"`
|
||||
|
||||
@@ -132,7 +134,7 @@ type FullNodeStruct struct {
|
||||
MinerGetBaseInfo func(context.Context, address.Address, abi.ChainEpoch, types.TipSetKey) (*api.MiningBaseInfo, error) `perm:"read"`
|
||||
MinerCreateBlock func(context.Context, *api.BlockTemplate) (*types.BlockMsg, error) `perm:"write"`
|
||||
|
||||
WalletNew func(context.Context, crypto.SigType) (address.Address, error) `perm:"write"`
|
||||
WalletNew func(context.Context, types.KeyType) (address.Address, error) `perm:"write"`
|
||||
WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"`
|
||||
WalletList func(context.Context) ([]address.Address, error) `perm:"write"`
|
||||
WalletBalance func(context.Context, address.Address) (types.BigInt, error) `perm:"read"`
|
||||
@@ -164,6 +166,7 @@ type FullNodeStruct struct {
|
||||
ClientDealSize func(ctx context.Context, root cid.Cid) (api.DataSize, error) `perm:"read"`
|
||||
ClientListDataTransfers func(ctx context.Context) ([]api.DataTransferChannel, error) `perm:"write"`
|
||||
ClientDataTransferUpdates func(ctx context.Context) (<-chan api.DataTransferChannel, error) `perm:"write"`
|
||||
ClientRestartDataTransfer func(ctx context.Context, transferID datatransfer.TransferID, otherPeer peer.ID, isInitiator bool) error `perm:"write"`
|
||||
ClientRetrieveTryRestartInsufficientFunds func(ctx context.Context, paymentChannel address.Address) error `perm:"write"`
|
||||
|
||||
StateNetworkName func(context.Context) (dtypes.NetworkName, error) `perm:"read"`
|
||||
@@ -190,6 +193,7 @@ type FullNodeStruct struct {
|
||||
StateReadState func(context.Context, address.Address, types.TipSetKey) (*api.ActorState, error) `perm:"read"`
|
||||
StateMsgGasCost func(context.Context, cid.Cid, types.TipSetKey) (*api.MsgGasCost, error) `perm:"read"`
|
||||
StateWaitMsg func(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) `perm:"read"`
|
||||
StateWaitMsgLimited func(context.Context, cid.Cid, uint64, abi.ChainEpoch) (*api.MsgLookup, error) `perm:"read"`
|
||||
StateSearchMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"`
|
||||
StateListMiners func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
|
||||
StateListActors func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
|
||||
@@ -208,14 +212,17 @@ type FullNodeStruct struct {
|
||||
StateVerifiedClientStatus func(context.Context, address.Address, types.TipSetKey) (*abi.StoragePower, error) `perm:"read"`
|
||||
StateVerifiedRegistryRootKey func(ctx context.Context, tsk types.TipSetKey) (address.Address, error) `perm:"read"`
|
||||
StateDealProviderCollateralBounds func(context.Context, abi.PaddedPieceSize, bool, types.TipSetKey) (api.DealCollateralBounds, error) `perm:"read"`
|
||||
StateCirculatingSupply func(context.Context, types.TipSetKey) (api.CirculatingSupply, error) `perm:"read"`
|
||||
StateCirculatingSupply func(context.Context, types.TipSetKey) (abi.TokenAmount, error) `perm:"read"`
|
||||
StateVMCirculatingSupplyInternal func(context.Context, types.TipSetKey) (api.CirculatingSupply, error) `perm:"read"`
|
||||
StateNetworkVersion func(context.Context, types.TipSetKey) (stnetwork.Version, error) `perm:"read"`
|
||||
|
||||
MsigGetAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
MsigGetVestingSchedule func(context.Context, address.Address, types.TipSetKey) (api.MsigVesting, error) `perm:"read"`
|
||||
MsigGetVested func(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
MsigCreate func(context.Context, uint64, []address.Address, abi.ChainEpoch, types.BigInt, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"`
|
||||
MsigPropose func(context.Context, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
||||
MsigApprove func(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
||||
MsigApprove func(context.Context, address.Address, uint64, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||
MsigApproveTxnHash func(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
||||
MsigCancel func(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
||||
MsigAddPropose func(context.Context, address.Address, address.Address, address.Address, bool) (cid.Cid, error) `perm:"sign"`
|
||||
MsigAddApprove func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, bool) (cid.Cid, error) `perm:"sign"`
|
||||
@@ -223,6 +230,7 @@ type FullNodeStruct struct {
|
||||
MsigSwapPropose func(context.Context, address.Address, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||
MsigSwapApprove func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||
MsigSwapCancel func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||
MsigRemoveSigner func(ctx context.Context, msig address.Address, proposer address.Address, toRemove address.Address, decrease bool) (cid.Cid, error) `perm:"sign"`
|
||||
|
||||
MarketEnsureAvailable func(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"`
|
||||
|
||||
@@ -360,6 +368,35 @@ type WorkerStruct struct {
|
||||
}
|
||||
}
|
||||
|
||||
type GatewayStruct struct {
|
||||
Internal struct {
|
||||
// TODO: does the gateway need perms?
|
||||
ChainGetTipSet func(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error)
|
||||
ChainGetTipSetByHeight func(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error)
|
||||
ChainHead func(ctx context.Context) (*types.TipSet, error)
|
||||
GasEstimateMessageGas func(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error)
|
||||
MpoolPush func(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error)
|
||||
MsigGetAvailableBalance func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error)
|
||||
MsigGetVested func(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error)
|
||||
StateAccountKey func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
|
||||
StateGetActor func(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)
|
||||
StateLookupID func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
|
||||
StateWaitMsg func(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error)
|
||||
}
|
||||
}
|
||||
|
||||
type WalletStruct struct {
|
||||
Internal struct {
|
||||
WalletNew func(context.Context, types.KeyType) (address.Address, error) `perm:"write"`
|
||||
WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"`
|
||||
WalletList func(context.Context) ([]address.Address, error) `perm:"write"`
|
||||
WalletSign func(context.Context, address.Address, []byte, api.MsgMeta) (*crypto.Signature, error) `perm:"sign"`
|
||||
WalletExport func(context.Context, address.Address) (*types.KeyInfo, error) `perm:"admin"`
|
||||
WalletImport func(context.Context, *types.KeyInfo) (address.Address, error) `perm:"admin"`
|
||||
WalletDelete func(context.Context, address.Address) error `perm:"write"`
|
||||
}
|
||||
}
|
||||
|
||||
// CommonStruct
|
||||
|
||||
func (c *CommonStruct) AuthVerify(ctx context.Context, token string) ([]auth.Permission, error) {
|
||||
@@ -517,6 +554,10 @@ func (c *FullNodeStruct) ClientDataTransferUpdates(ctx context.Context) (<-chan
|
||||
return c.Internal.ClientDataTransferUpdates(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientRestartDataTransfer(ctx context.Context, transferID datatransfer.TransferID, otherPeer peer.ID, isInitiator bool) error {
|
||||
return c.Internal.ClientRestartDataTransfer(ctx, transferID, otherPeer, isInitiator)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientRetrieveTryRestartInsufficientFunds(ctx context.Context, paymentChannel address.Address) error {
|
||||
return c.Internal.ClientRetrieveTryRestartInsufficientFunds(ctx, paymentChannel)
|
||||
}
|
||||
@@ -597,7 +638,7 @@ func (c *FullNodeStruct) ChainGetTipSetByHeight(ctx context.Context, h abi.Chain
|
||||
return c.Internal.ChainGetTipSetByHeight(ctx, h, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) WalletNew(ctx context.Context, typ crypto.SigType) (address.Address, error) {
|
||||
func (c *FullNodeStruct) WalletNew(ctx context.Context, typ types.KeyType) (address.Address, error) {
|
||||
return c.Internal.WalletNew(ctx, typ)
|
||||
}
|
||||
|
||||
@@ -749,6 +790,10 @@ func (c *FullNodeStruct) SyncUnmarkBad(ctx context.Context, bcid cid.Cid) error
|
||||
return c.Internal.SyncUnmarkBad(ctx, bcid)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) SyncUnmarkAllBad(ctx context.Context) error {
|
||||
return c.Internal.SyncUnmarkAllBad(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error) {
|
||||
return c.Internal.SyncCheckBad(ctx, bcid)
|
||||
}
|
||||
@@ -853,6 +898,10 @@ func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid, confide
|
||||
return c.Internal.StateWaitMsg(ctx, msgc, confidence)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateWaitMsgLimited(ctx context.Context, msgc cid.Cid, confidence uint64, limit abi.ChainEpoch) (*api.MsgLookup, error) {
|
||||
return c.Internal.StateWaitMsgLimited(ctx, msgc, confidence, limit)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateSearchMsg(ctx context.Context, msgc cid.Cid) (*api.MsgLookup, error) {
|
||||
return c.Internal.StateSearchMsg(ctx, msgc)
|
||||
}
|
||||
@@ -921,10 +970,14 @@ func (c *FullNodeStruct) StateDealProviderCollateralBounds(ctx context.Context,
|
||||
return c.Internal.StateDealProviderCollateralBounds(ctx, size, verified, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateCirculatingSupply(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) {
|
||||
func (c *FullNodeStruct) StateCirculatingSupply(ctx context.Context, tsk types.TipSetKey) (abi.TokenAmount, error) {
|
||||
return c.Internal.StateCirculatingSupply(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateVMCirculatingSupplyInternal(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) {
|
||||
return c.Internal.StateVMCirculatingSupplyInternal(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (stnetwork.Version, error) {
|
||||
return c.Internal.StateNetworkVersion(ctx, tsk)
|
||||
}
|
||||
@@ -933,6 +986,10 @@ func (c *FullNodeStruct) MsigGetAvailableBalance(ctx context.Context, a address.
|
||||
return c.Internal.MsigGetAvailableBalance(ctx, a, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigGetVestingSchedule(ctx context.Context, a address.Address, tsk types.TipSetKey) (api.MsigVesting, error) {
|
||||
return c.Internal.MsigGetVestingSchedule(ctx, a, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigGetVested(ctx context.Context, a address.Address, sTsk types.TipSetKey, eTsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.MsigGetVested(ctx, a, sTsk, eTsk)
|
||||
}
|
||||
@@ -945,8 +1002,12 @@ func (c *FullNodeStruct) MsigPropose(ctx context.Context, msig address.Address,
|
||||
return c.Internal.MsigPropose(ctx, msig, to, amt, src, method, params)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigApprove(ctx context.Context, msig address.Address, txID uint64, proposer address.Address, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) {
|
||||
return c.Internal.MsigApprove(ctx, msig, txID, proposer, to, amt, src, method, params)
|
||||
func (c *FullNodeStruct) MsigApprove(ctx context.Context, msig address.Address, txID uint64, signer address.Address) (cid.Cid, error) {
|
||||
return c.Internal.MsigApprove(ctx, msig, txID, signer)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigApproveTxnHash(ctx context.Context, msig address.Address, txID uint64, proposer address.Address, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) {
|
||||
return c.Internal.MsigApproveTxnHash(ctx, msig, txID, proposer, to, amt, src, method, params)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigCancel(ctx context.Context, msig address.Address, txID uint64, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) {
|
||||
@@ -977,6 +1038,10 @@ func (c *FullNodeStruct) MsigSwapCancel(ctx context.Context, msig address.Addres
|
||||
return c.Internal.MsigSwapCancel(ctx, msig, src, txID, oldAdd, newAdd)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigRemoveSigner(ctx context.Context, msig address.Address, proposer address.Address, toRemove address.Address, decrease bool) (cid.Cid, error) {
|
||||
return c.Internal.MsigRemoveSigner(ctx, msig, proposer, toRemove, decrease)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MarketEnsureAvailable(ctx context.Context, addr, wallet address.Address, amt types.BigInt) (cid.Cid, error) {
|
||||
return c.Internal.MarketEnsureAvailable(ctx, addr, wallet, amt)
|
||||
}
|
||||
@@ -1367,7 +1432,81 @@ func (w *WorkerStruct) Closing(ctx context.Context) (<-chan struct{}, error) {
|
||||
return w.Internal.Closing(ctx)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) ChainHead(ctx context.Context) (*types.TipSet, error) {
|
||||
return g.Internal.ChainHead(ctx)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
return g.Internal.ChainGetTipSet(ctx, tsk)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
return g.Internal.ChainGetTipSetByHeight(ctx, h, tsk)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) {
|
||||
return g.Internal.GasEstimateMessageGas(ctx, msg, spec, tsk)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) {
|
||||
return g.Internal.MpoolPush(ctx, sm)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return g.Internal.MsigGetAvailableBalance(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) {
|
||||
return g.Internal.MsigGetVested(ctx, addr, start, end)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
||||
return g.Internal.StateAccountKey(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) {
|
||||
return g.Internal.StateGetActor(ctx, actor, ts)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
||||
return g.Internal.StateLookupID(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) {
|
||||
return g.Internal.StateWaitMsg(ctx, msg, confidence)
|
||||
}
|
||||
|
||||
func (c *WalletStruct) WalletNew(ctx context.Context, typ types.KeyType) (address.Address, error) {
|
||||
return c.Internal.WalletNew(ctx, typ)
|
||||
}
|
||||
|
||||
func (c *WalletStruct) WalletHas(ctx context.Context, addr address.Address) (bool, error) {
|
||||
return c.Internal.WalletHas(ctx, addr)
|
||||
}
|
||||
|
||||
func (c *WalletStruct) WalletList(ctx context.Context) ([]address.Address, error) {
|
||||
return c.Internal.WalletList(ctx)
|
||||
}
|
||||
|
||||
func (c *WalletStruct) WalletSign(ctx context.Context, k address.Address, msg []byte, meta api.MsgMeta) (*crypto.Signature, error) {
|
||||
return c.Internal.WalletSign(ctx, k, msg, meta)
|
||||
}
|
||||
|
||||
func (c *WalletStruct) WalletExport(ctx context.Context, a address.Address) (*types.KeyInfo, error) {
|
||||
return c.Internal.WalletExport(ctx, a)
|
||||
}
|
||||
|
||||
func (c *WalletStruct) WalletImport(ctx context.Context, ki *types.KeyInfo) (address.Address, error) {
|
||||
return c.Internal.WalletImport(ctx, ki)
|
||||
}
|
||||
|
||||
func (c *WalletStruct) WalletDelete(ctx context.Context, addr address.Address) error {
|
||||
return c.Internal.WalletDelete(ctx, addr)
|
||||
}
|
||||
|
||||
var _ api.Common = &CommonStruct{}
|
||||
var _ api.FullNode = &FullNodeStruct{}
|
||||
var _ api.StorageMiner = &StorageMinerStruct{}
|
||||
var _ api.WorkerAPI = &WorkerStruct{}
|
||||
var _ api.GatewayAPI = &GatewayStruct{}
|
||||
var _ api.WalletAPI = &WalletStruct{}
|
||||
|
||||
@@ -82,3 +82,29 @@ func NewWorkerRPC(ctx context.Context, addr string, requestHeader http.Header) (
|
||||
|
||||
return &res, closer, err
|
||||
}
|
||||
|
||||
// NewGatewayRPC creates a new http jsonrpc client for a gateway node.
|
||||
func NewGatewayRPC(ctx context.Context, addr string, requestHeader http.Header, opts ...jsonrpc.Option) (api.GatewayAPI, jsonrpc.ClientCloser, error) {
|
||||
var res apistruct.GatewayStruct
|
||||
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
|
||||
[]interface{}{
|
||||
&res.Internal,
|
||||
},
|
||||
requestHeader,
|
||||
opts...,
|
||||
)
|
||||
|
||||
return &res, closer, err
|
||||
}
|
||||
|
||||
func NewWalletRPC(ctx context.Context, addr string, requestHeader http.Header) (api.WalletAPI, jsonrpc.ClientCloser, error) {
|
||||
var res apistruct.WalletStruct
|
||||
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
|
||||
[]interface{}{
|
||||
&res.Internal,
|
||||
},
|
||||
requestHeader,
|
||||
)
|
||||
|
||||
return &res, closer, err
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@ func init() {
|
||||
addExample(abi.RegisteredPoStProof_StackedDrgWindow32GiBV1)
|
||||
addExample(abi.ChainEpoch(10101))
|
||||
addExample(crypto.SigTypeBLS)
|
||||
addExample(types.KTBLS)
|
||||
addExample(int64(9))
|
||||
addExample(12.3)
|
||||
addExample(123)
|
||||
|
||||
@@ -12,10 +12,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node"
|
||||
"github.com/filecoin-project/lotus/node/impl"
|
||||
)
|
||||
|
||||
@@ -37,11 +34,7 @@ func TestCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
|
||||
func testCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration, upgradeHeight abi.ChainEpoch) {
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, OneMiner, node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{
|
||||
Network: build.ActorUpgradeNetworkVersion,
|
||||
Height: upgradeHeight,
|
||||
Migration: stmgr.UpgradeActorsV2,
|
||||
}}))
|
||||
n, sn := b(t, []FullNodeOpts{FullNodeWithUpgradeAt(upgradeHeight)}, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
|
||||
+4
-4
@@ -48,7 +48,7 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
n, sn := b(t, OneFull, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@@ -85,7 +85,7 @@ func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
n, sn := b(t, OneFull, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@@ -149,7 +149,7 @@ func TestFastRetrievalDealFlow(t *testing.T, b APIBuilder, blocktime time.Durati
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
n, sn := b(t, OneFull, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@@ -204,7 +204,7 @@ func TestSenondDealRetrieval(t *testing.T, b APIBuilder, blocktime time.Duration
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
n, sn := b(t, OneFull, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
|
||||
+3
-3
@@ -25,7 +25,7 @@ var log = logging.Logger("apitest")
|
||||
|
||||
func (ts *testSuite) testMining(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
apis, sn := ts.makeNodes(t, 1, OneMiner)
|
||||
apis, sn := ts.makeNodes(t, OneFull, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
newHeads, err := api.ChainNotify(ctx)
|
||||
@@ -54,7 +54,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
|
||||
}()
|
||||
|
||||
ctx := context.Background()
|
||||
apis, sn := ts.makeNodes(t, 1, OneMiner)
|
||||
apis, sn := ts.makeNodes(t, OneFull, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
newHeads, err := api.ChainNotify(ctx)
|
||||
@@ -93,7 +93,7 @@ func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExpo
|
||||
// test making a deal with a fresh miner, and see if it starts to mine
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, []StorageMiner{
|
||||
n, sn := b(t, OneFull, []StorageMiner{
|
||||
{Full: 0, Preseal: PresealGenesis},
|
||||
{Full: 0, Preseal: 0}, // TODO: Add support for miners on non-first full node
|
||||
})
|
||||
|
||||
+2
-3
@@ -26,14 +26,13 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/events"
|
||||
"github.com/filecoin-project/lotus/chain/events/state"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
)
|
||||
|
||||
func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 2, OneMiner)
|
||||
n, sn := b(t, TwoFull, OneMiner)
|
||||
|
||||
paymentCreator := n[0]
|
||||
paymentReceiver := n[1]
|
||||
@@ -58,7 +57,7 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
bm.MineBlocks()
|
||||
|
||||
// send some funds to register the receiver
|
||||
receiverAddr, err := paymentReceiver.WalletNew(ctx, wallet.ActSigType("secp256k1"))
|
||||
receiverAddr, err := paymentReceiver.WalletNew(ctx, types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
||||
"github.com/filecoin-project/lotus/node"
|
||||
"github.com/filecoin-project/lotus/node/impl"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestTapeFix(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
t.Run("before", func(t *testing.T) { testTapeFix(t, b, blocktime, false) })
|
||||
t.Run("after", func(t *testing.T) { testTapeFix(t, b, blocktime, true) })
|
||||
}
|
||||
func testTapeFix(t *testing.T, b APIBuilder, blocktime time.Duration, after bool) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
upgradeSchedule := stmgr.UpgradeSchedule{{
|
||||
Network: build.ActorUpgradeNetworkVersion,
|
||||
Height: 1,
|
||||
Migration: stmgr.UpgradeActorsV2,
|
||||
}}
|
||||
if after {
|
||||
upgradeSchedule = append(upgradeSchedule, stmgr.Upgrade{
|
||||
Network: network.Version5,
|
||||
Height: 2,
|
||||
})
|
||||
}
|
||||
|
||||
n, sn := b(t, []FullNodeOpts{{Opts: func(_ []TestNode) node.Option {
|
||||
return node.Override(new(stmgr.UpgradeSchedule), upgradeSchedule)
|
||||
}}}, OneMiner)
|
||||
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
addrinfo, err := client.NetAddrsListen(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := miner.NetConnect(ctx, addrinfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
build.Clock.Sleep(time.Second)
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
for ctx.Err() == nil {
|
||||
build.Clock.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, MineNext); err != nil {
|
||||
if ctx.Err() != nil {
|
||||
// context was canceled, ignore the error.
|
||||
return
|
||||
}
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
cancel()
|
||||
<-done
|
||||
}()
|
||||
|
||||
err = miner.PledgeSector(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Wait till done.
|
||||
var sectorNo abi.SectorNumber
|
||||
for {
|
||||
s, err := miner.SectorsList(ctx) // Note - the test builder doesn't import genesis sectors into FSM
|
||||
require.NoError(t, err)
|
||||
fmt.Printf("Sectors: %d\n", len(s))
|
||||
if len(s) == 1 {
|
||||
sectorNo = s[0]
|
||||
break
|
||||
}
|
||||
|
||||
build.Clock.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
fmt.Printf("All sectors is fsm\n")
|
||||
|
||||
// If before, we expect the precommit to fail
|
||||
successState := api.SectorState(sealing.CommitFailed)
|
||||
failureState := api.SectorState(sealing.Proving)
|
||||
if after {
|
||||
// otherwise, it should succeed.
|
||||
successState, failureState = failureState, successState
|
||||
}
|
||||
|
||||
for {
|
||||
st, err := miner.SectorsStatus(ctx, sectorNo, false)
|
||||
require.NoError(t, err)
|
||||
if st.State == successState {
|
||||
break
|
||||
}
|
||||
require.NotEqual(t, failureState, st.State)
|
||||
build.Clock.Sleep(100 * time.Millisecond)
|
||||
fmt.Println("WaitSeal")
|
||||
}
|
||||
|
||||
}
|
||||
+92
-4
@@ -3,12 +3,19 @@ package test
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/miner"
|
||||
@@ -35,17 +42,27 @@ var PresealGenesis = -1
|
||||
|
||||
const GenesisPreseals = 2
|
||||
|
||||
// Options for setting up a mock storage miner
|
||||
type StorageMiner struct {
|
||||
Full int
|
||||
Preseal int
|
||||
}
|
||||
|
||||
type OptionGenerator func([]TestNode) node.Option
|
||||
|
||||
// Options for setting up a mock full node
|
||||
type FullNodeOpts struct {
|
||||
Lite bool // run node in "lite" mode
|
||||
Opts OptionGenerator // generate dependency injection options
|
||||
}
|
||||
|
||||
// APIBuilder is a function which is invoked in test suite to provide
|
||||
// test nodes and networks
|
||||
//
|
||||
// fullOpts array defines options for each full node
|
||||
// storage array defines storage nodes, numbers in the array specify full node
|
||||
// index the storage node 'belongs' to
|
||||
type APIBuilder func(t *testing.T, nFull int, storage []StorageMiner, opts ...node.Option) ([]TestNode, []TestStorageNode)
|
||||
type APIBuilder func(t *testing.T, full []FullNodeOpts, storage []StorageMiner) ([]TestNode, []TestStorageNode)
|
||||
type testSuite struct {
|
||||
makeNodes APIBuilder
|
||||
}
|
||||
@@ -61,15 +78,43 @@ func TestApis(t *testing.T, b APIBuilder) {
|
||||
t.Run("testConnectTwo", ts.testConnectTwo)
|
||||
t.Run("testMining", ts.testMining)
|
||||
t.Run("testMiningReal", ts.testMiningReal)
|
||||
t.Run("testSearchMsg", ts.testSearchMsg)
|
||||
}
|
||||
|
||||
func DefaultFullOpts(nFull int) []FullNodeOpts {
|
||||
full := make([]FullNodeOpts, nFull)
|
||||
for i := range full {
|
||||
full[i] = FullNodeOpts{
|
||||
Opts: func(nodes []TestNode) node.Option {
|
||||
return node.Options()
|
||||
},
|
||||
}
|
||||
}
|
||||
return full
|
||||
}
|
||||
|
||||
var OneMiner = []StorageMiner{{Full: 0, Preseal: PresealGenesis}}
|
||||
var OneFull = DefaultFullOpts(1)
|
||||
var TwoFull = DefaultFullOpts(2)
|
||||
|
||||
var FullNodeWithUpgradeAt = func(upgradeHeight abi.ChainEpoch) FullNodeOpts {
|
||||
return FullNodeOpts{
|
||||
Opts: func(nodes []TestNode) node.Option {
|
||||
return node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{
|
||||
// Skip directly to tape height so precommits work.
|
||||
Network: network.Version5,
|
||||
Height: upgradeHeight,
|
||||
Migration: stmgr.UpgradeActorsV2,
|
||||
}})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (ts *testSuite) testVersion(t *testing.T) {
|
||||
build.RunningNodeType = build.NodeFull
|
||||
|
||||
ctx := context.Background()
|
||||
apis, _ := ts.makeNodes(t, 1, OneMiner)
|
||||
apis, _ := ts.makeNodes(t, OneFull, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
v, err := api.Version(ctx)
|
||||
@@ -79,9 +124,52 @@ func (ts *testSuite) testVersion(t *testing.T) {
|
||||
require.Equal(t, v.Version, build.BuildVersion)
|
||||
}
|
||||
|
||||
func (ts *testSuite) testSearchMsg(t *testing.T) {
|
||||
apis, miners := ts.makeNodes(t, OneFull, OneMiner)
|
||||
|
||||
api := apis[0]
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
senderAddr, err := api.WalletDefaultAddress(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
msg := &types.Message{
|
||||
From: senderAddr,
|
||||
To: senderAddr,
|
||||
Value: big.Zero(),
|
||||
}
|
||||
bm := NewBlockMiner(ctx, t, miners[0], 100*time.Millisecond)
|
||||
bm.MineBlocks()
|
||||
defer bm.Stop()
|
||||
|
||||
sm, err := api.MpoolPushMessage(ctx, msg, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
res, err := api.StateWaitMsg(ctx, sm.Cid(), 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if res.Receipt.ExitCode != 0 {
|
||||
t.Fatal("did not successfully send message")
|
||||
}
|
||||
|
||||
searchRes, err := api.StateSearchMsg(ctx, sm.Cid())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if searchRes.TipSet != res.TipSet {
|
||||
t.Fatalf("search ts: %s, different from wait ts: %s", searchRes.TipSet, res.TipSet)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (ts *testSuite) testID(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
apis, _ := ts.makeNodes(t, 1, OneMiner)
|
||||
apis, _ := ts.makeNodes(t, OneFull, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
id, err := api.ID(ctx)
|
||||
@@ -93,7 +181,7 @@ func (ts *testSuite) testID(t *testing.T) {
|
||||
|
||||
func (ts *testSuite) testConnectTwo(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
apis, _ := ts.makeNodes(t, 2, OneMiner)
|
||||
apis, _ := ts.makeNodes(t, TwoFull, OneMiner)
|
||||
|
||||
p, err := apis[0].NetPeers(ctx)
|
||||
if err != nil {
|
||||
|
||||
+9
-12
@@ -3,6 +3,7 @@ package test
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
|
||||
"os"
|
||||
"strings"
|
||||
@@ -15,11 +16,9 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/mock"
|
||||
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
||||
"github.com/filecoin-project/lotus/node"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
bminer "github.com/filecoin-project/lotus/miner"
|
||||
"github.com/filecoin-project/lotus/node/impl"
|
||||
@@ -33,8 +32,10 @@ func init() {
|
||||
}
|
||||
|
||||
func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) {
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
n, sn := b(t, OneFull, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@@ -48,11 +49,11 @@ func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSect
|
||||
}
|
||||
build.Clock.Sleep(time.Second)
|
||||
|
||||
mine := true
|
||||
mine := int64(1)
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
for mine {
|
||||
for atomic.LoadInt64(&mine) != 0 {
|
||||
build.Clock.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, bminer.MineReq{Done: func(bool, abi.ChainEpoch, error) {
|
||||
|
||||
@@ -64,7 +65,7 @@ func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSect
|
||||
|
||||
pledgeSectors(t, ctx, miner, nSectors, 0, nil)
|
||||
|
||||
mine = false
|
||||
atomic.StoreInt64(&mine, 0)
|
||||
<-done
|
||||
}
|
||||
|
||||
@@ -133,11 +134,7 @@ func testWindowPostUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration,
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
n, sn := b(t, 1, OneMiner, node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{
|
||||
Network: build.ActorUpgradeNetworkVersion,
|
||||
Height: upgradeHeight,
|
||||
Migration: stmgr.UpgradeActorsV2,
|
||||
}}))
|
||||
n, sn := b(t, []FullNodeOpts{FullNodeWithUpgradeAt(upgradeHeight)}, OneMiner)
|
||||
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
+1
-10
@@ -35,6 +35,7 @@ var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{
|
||||
"https://api.drand.sh",
|
||||
"https://api2.drand.sh",
|
||||
"https://api3.drand.sh",
|
||||
"https://drand.cloudflare.com",
|
||||
},
|
||||
Relays: []string{
|
||||
"/dnsaddr/api.drand.sh/",
|
||||
@@ -68,16 +69,6 @@ var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{
|
||||
ChainInfoJSON: `{"public_key":"8cda589f88914aa728fd183f383980b35789ce81b274e5daee1f338b77d02566ef4d3fb0098af1f844f10f9c803c1827","period":25,"genesis_time":1595348225,"hash":"e73b7dc3c4f6a236378220c0dd6aa110eb16eed26c11259606e07ee122838d4f","groupHash":"567d4785122a5a3e75a9bc9911d7ea807dd85ff76b78dc4ff06b075712898607"}`,
|
||||
},
|
||||
DrandIncentinet: {
|
||||
Servers: []string{
|
||||
"https://pl-eu.incentinet.drand.sh",
|
||||
"https://pl-us.incentinet.drand.sh",
|
||||
"https://pl-sin.incentinet.drand.sh",
|
||||
},
|
||||
Relays: []string{
|
||||
"/dnsaddr/pl-eu.incentinet.drand.sh/",
|
||||
"/dnsaddr/pl-us.incentinet.drand.sh/",
|
||||
"/dnsaddr/pl-sin.incentinet.drand.sh/",
|
||||
},
|
||||
ChainInfoJSON: `{"public_key":"8cad0c72c606ab27d36ee06de1d5b2db1faf92e447025ca37575ab3a8aac2eaae83192f846fc9e158bc738423753d000","period":30,"genesis_time":1595873820,"hash":"80c8b872c714f4c00fdd3daa465d5514049f457f01f85a4caf68cdcd394ba039","groupHash":"d9406aaed487f7af71851b4399448e311f2328923d454e971536c05398ce2d9b"}`,
|
||||
},
|
||||
}
|
||||
|
||||
+2
-1
@@ -17,9 +17,10 @@ const BreezeGasTampingDuration = 0
|
||||
const UpgradeSmokeHeight = -1
|
||||
const UpgradeIgnitionHeight = -2
|
||||
const UpgradeRefuelHeight = -3
|
||||
const UpgradeTapeHeight = -4
|
||||
|
||||
var UpgradeActorsV2Height = abi.ChainEpoch(10)
|
||||
var UpgradeLiftoffHeight = abi.ChainEpoch(-4)
|
||||
var UpgradeLiftoffHeight = abi.ChainEpoch(-5)
|
||||
|
||||
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandMainnet,
|
||||
|
||||
@@ -30,6 +30,8 @@ const UpgradeRefuelHeight = 130800
|
||||
|
||||
var UpgradeActorsV2Height = abi.ChainEpoch(138720)
|
||||
|
||||
const UpgradeTapeHeight = 140760
|
||||
|
||||
// This signals our tentative epoch for mainnet launch. Can make it later, but not earlier.
|
||||
// Miners, clients, developers, custodians all need time to prepare.
|
||||
// We still have upgrades and state changes to do, but can happen after signaling timing here.
|
||||
@@ -25,7 +25,7 @@ const UnixfsLinksPerLevel = 1024
|
||||
// Consensus / Network
|
||||
|
||||
const AllowableClockDriftSecs = uint64(1)
|
||||
const NewestNetworkVersion = network.Version4
|
||||
const NewestNetworkVersion = network.Version5
|
||||
const ActorUpgradeNetworkVersion = network.Version4
|
||||
|
||||
// Epochs
|
||||
|
||||
@@ -83,14 +83,15 @@ var (
|
||||
UpgradeSmokeHeight abi.ChainEpoch = -1
|
||||
UpgradeIgnitionHeight abi.ChainEpoch = -2
|
||||
UpgradeRefuelHeight abi.ChainEpoch = -3
|
||||
UpgradeTapeHeight abi.ChainEpoch = -4
|
||||
UpgradeActorsV2Height abi.ChainEpoch = 10
|
||||
UpgradeLiftoffHeight abi.ChainEpoch = -4
|
||||
UpgradeLiftoffHeight abi.ChainEpoch = -5
|
||||
|
||||
DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandMainnet,
|
||||
}
|
||||
|
||||
NewestNetworkVersion = network.Version4
|
||||
NewestNetworkVersion = network.Version5
|
||||
ActorUpgradeNetworkVersion = network.Version4
|
||||
|
||||
Devnet = true
|
||||
|
||||
+2
-2
@@ -29,7 +29,7 @@ func buildType() string {
|
||||
}
|
||||
|
||||
// BuildVersion is the local build version, set by build system
|
||||
const BuildVersion = "0.9.0"
|
||||
const BuildVersion = "0.10.2"
|
||||
|
||||
func UserVersion() string {
|
||||
return BuildVersion + buildType() + CurrentCommit
|
||||
@@ -83,7 +83,7 @@ func VersionForType(nodeType NodeType) (Version, error) {
|
||||
|
||||
// semver versions of the rpc api exposed
|
||||
var (
|
||||
FullAPIVersion = newVer(0, 16, 0)
|
||||
FullAPIVersion = newVer(0, 17, 0)
|
||||
MinerAPIVersion = newVer(0, 15, 0)
|
||||
WorkerAPIVersion = newVer(0, 15, 0)
|
||||
)
|
||||
|
||||
@@ -2,25 +2,28 @@ package builtin
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
smoothing2 "github.com/filecoin-project/specs-actors/v2/actors/util/smoothing"
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||
smoothing0 "github.com/filecoin-project/specs-actors/actors/util/smoothing"
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
smoothing2 "github.com/filecoin-project/specs-actors/v2/actors/util/smoothing"
|
||||
)
|
||||
|
||||
var SystemActorAddr = builtin0.SystemActorAddr
|
||||
var BurntFundsActorAddr = builtin0.BurntFundsActorAddr
|
||||
var CronActorAddr = builtin0.CronActorAddr
|
||||
var SaftAddress = makeAddress("t0122")
|
||||
var ReserveAddress = makeAddress("t090")
|
||||
var RootVerifierAddress = makeAddress("t080")
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
)
|
||||
|
||||
type DeadlinesDiff map[uint64]*DeadlineDiff
|
||||
type DeadlinesDiff map[uint64]DeadlineDiff
|
||||
|
||||
func DiffDeadlines(pre, cur State) (*DeadlinesDiff, error) {
|
||||
func DiffDeadlines(pre, cur State) (DeadlinesDiff, error) {
|
||||
changed, err := pre.DeadlinesChanged(cur)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -18,11 +18,7 @@ func DiffDeadlines(pre, cur State) (*DeadlinesDiff, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
numDl, err := pre.NumDeadlines()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dlDiff := make(DeadlinesDiff, numDl)
|
||||
dlDiff := make(DeadlinesDiff)
|
||||
if err := pre.ForEachDeadline(func(idx uint64, preDl Deadline) error {
|
||||
curDl, err := cur.LoadDeadline(idx)
|
||||
if err != nil {
|
||||
@@ -39,12 +35,12 @@ func DiffDeadlines(pre, cur State) (*DeadlinesDiff, error) {
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &dlDiff, nil
|
||||
return dlDiff, nil
|
||||
}
|
||||
|
||||
type DeadlineDiff map[uint64]*PartitionDiff
|
||||
|
||||
func DiffDeadline(pre, cur Deadline) (*DeadlineDiff, error) {
|
||||
func DiffDeadline(pre, cur Deadline) (DeadlineDiff, error) {
|
||||
changed, err := pre.PartitionsChanged(cur)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -104,7 +100,7 @@ func DiffDeadline(pre, cur Deadline) (*DeadlineDiff, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &partDiff, nil
|
||||
return partDiff, nil
|
||||
}
|
||||
|
||||
type PartitionDiff struct {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package miner
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
@@ -148,6 +149,20 @@ type MinerInfo struct {
|
||||
ConsensusFaultElapsed abi.ChainEpoch
|
||||
}
|
||||
|
||||
func (mi MinerInfo) IsController(addr address.Address) bool {
|
||||
if addr == mi.Owner || addr == mi.Worker {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, ca := range mi.ControlAddresses {
|
||||
if addr == ca {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
type SectorExpiration struct {
|
||||
OnTime abi.ChainEpoch
|
||||
|
||||
@@ -182,3 +197,7 @@ type LockedFunds struct {
|
||||
InitialPledgeRequirement abi.TokenAmount
|
||||
PreCommitDeposits abi.TokenAmount
|
||||
}
|
||||
|
||||
func (lf LockedFunds) TotalLockedFunds() abi.TokenAmount {
|
||||
return big.Add(lf.VestingFunds, big.Add(lf.InitialPledgeRequirement, lf.PreCommitDeposits))
|
||||
}
|
||||
|
||||
@@ -47,8 +47,16 @@ type partition0 struct {
|
||||
store adt.Store
|
||||
}
|
||||
|
||||
func (s *state0) AvailableBalance(bal abi.TokenAmount) (abi.TokenAmount, error) {
|
||||
return s.GetAvailableBalance(bal), nil
|
||||
func (s *state0) AvailableBalance(bal abi.TokenAmount) (available abi.TokenAmount, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = xerrors.Errorf("failed to get available balance: %w", r)
|
||||
available = abi.NewTokenAmount(0)
|
||||
}
|
||||
}()
|
||||
// this panics if the miner doesnt have enough funds to cover their locked pledge
|
||||
available = s.GetAvailableBalance(bal)
|
||||
return available, err
|
||||
}
|
||||
|
||||
func (s *state0) VestedFunds(epoch abi.ChainEpoch) (abi.TokenAmount, error) {
|
||||
@@ -266,7 +274,7 @@ func (s *state0) DeadlinesChanged(other State) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return s.State.Deadlines.Equals(other0.Deadlines), nil
|
||||
return !s.State.Deadlines.Equals(other0.Deadlines), nil
|
||||
}
|
||||
|
||||
func (s *state0) Info() (MinerInfo, error) {
|
||||
@@ -362,7 +370,7 @@ func (d *deadline0) PartitionsChanged(other Deadline) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return d.Deadline.Partitions.Equals(other0.Deadline.Partitions), nil
|
||||
return !d.Deadline.Partitions.Equals(other0.Deadline.Partitions), nil
|
||||
}
|
||||
|
||||
func (d *deadline0) PostSubmissions() (bitfield.BitField, error) {
|
||||
|
||||
@@ -45,8 +45,16 @@ type partition2 struct {
|
||||
store adt.Store
|
||||
}
|
||||
|
||||
func (s *state2) AvailableBalance(bal abi.TokenAmount) (abi.TokenAmount, error) {
|
||||
return s.GetAvailableBalance(bal)
|
||||
func (s *state2) AvailableBalance(bal abi.TokenAmount) (available abi.TokenAmount, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = xerrors.Errorf("failed to get available balance: %w", r)
|
||||
available = abi.NewTokenAmount(0)
|
||||
}
|
||||
}()
|
||||
// this panics if the miner doesnt have enough funds to cover their locked pledge
|
||||
available, err = s.GetAvailableBalance(bal)
|
||||
return available, err
|
||||
}
|
||||
|
||||
func (s *state2) VestedFunds(epoch abi.ChainEpoch) (abi.TokenAmount, error) {
|
||||
@@ -265,7 +273,7 @@ func (s *state2) DeadlinesChanged(other State) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return s.State.Deadlines.Equals(other2.Deadlines), nil
|
||||
return !s.State.Deadlines.Equals(other2.Deadlines), nil
|
||||
}
|
||||
|
||||
func (s *state2) Info() (MinerInfo, error) {
|
||||
@@ -361,7 +369,7 @@ func (d *deadline2) PartitionsChanged(other Deadline) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return d.Deadline.Partitions.Equals(other2.Deadline.Partitions), nil
|
||||
return !d.Deadline.Partitions.Equals(other2.Deadline.Partitions), nil
|
||||
}
|
||||
|
||||
func (d *deadline2) PostSubmissions() (bitfield.BitField, error) {
|
||||
|
||||
@@ -45,6 +45,7 @@ type MessageBuilder interface {
|
||||
|
||||
// this type is the same between v0 and v2
|
||||
type ProposalHashData = multisig2.ProposalHashData
|
||||
type ProposeReturn = multisig2.ProposeReturn
|
||||
|
||||
func txnParams(id uint64, data *ProposalHashData) ([]byte, error) {
|
||||
params := multisig2.TxnIDParams{ID: multisig2.TxnID(id)}
|
||||
|
||||
@@ -51,6 +51,7 @@ type State interface {
|
||||
MinerPower(address.Address) (Claim, bool, error)
|
||||
MinerNominalPowerMeetsConsensusMinimum(address.Address) (bool, error)
|
||||
ListAllMiners() ([]address.Address, error)
|
||||
ForEachClaim(func(miner address.Address, claim Claim) error) error
|
||||
}
|
||||
|
||||
type Claim struct {
|
||||
|
||||
@@ -96,3 +96,22 @@ func (s *state0) ListAllMiners() ([]address.Address, error) {
|
||||
|
||||
return miners, nil
|
||||
}
|
||||
|
||||
func (s *state0) ForEachClaim(cb func(miner address.Address, claim Claim) error) error {
|
||||
claims, err := adt0.AsMap(s.store, s.Claims)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var claim power0.Claim
|
||||
return claims.ForEach(&claim, func(k string) error {
|
||||
a, err := address.NewFromBytes([]byte(k))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return cb(a, Claim{
|
||||
RawBytePower: claim.RawBytePower,
|
||||
QualityAdjPower: claim.QualityAdjPower,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -96,3 +96,22 @@ func (s *state2) ListAllMiners() ([]address.Address, error) {
|
||||
|
||||
return miners, nil
|
||||
}
|
||||
|
||||
func (s *state2) ForEachClaim(cb func(miner address.Address, claim Claim) error) error {
|
||||
claims, err := adt2.AsMap(s.store, s.Claims)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var claim power2.Claim
|
||||
return claims.ForEach(&claim, func(k string) error {
|
||||
a, err := address.NewFromBytes([]byte(k))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return cb(a, Claim{
|
||||
RawBytePower: claim.RawBytePower,
|
||||
QualityAdjPower: claim.QualityAdjPower,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ func (s *state0) CumsumBaseline() (abi.StoragePower, error) {
|
||||
}
|
||||
|
||||
func (s *state0) CumsumRealized() (abi.StoragePower, error) {
|
||||
return s.State.CumsumBaseline, nil
|
||||
return s.State.CumsumRealized, nil
|
||||
}
|
||||
|
||||
func (s *state0) InitialPledgeForPower(sectorWeight abi.StoragePower, networkTotalPledge abi.TokenAmount, networkQAPower *builtin.FilterEstimate, circSupply abi.TokenAmount) (abi.TokenAmount, error) {
|
||||
|
||||
@@ -60,7 +60,7 @@ func (s *state2) CumsumBaseline() (abi.StoragePower, error) {
|
||||
}
|
||||
|
||||
func (s *state2) CumsumRealized() (abi.StoragePower, error) {
|
||||
return s.State.CumsumBaseline, nil
|
||||
return s.State.CumsumRealized, nil
|
||||
}
|
||||
|
||||
func (s *state2) InitialPledgeForPower(qaPower abi.StoragePower, networkTotalPledge abi.TokenAmount, networkQAPower *builtin.FilterEstimate, circSupply abi.TokenAmount) (abi.TokenAmount, error) {
|
||||
|
||||
@@ -18,7 +18,7 @@ func VersionForNetwork(version network.Version) Version {
|
||||
switch version {
|
||||
case network.Version0, network.Version1, network.Version2, network.Version3:
|
||||
return Version0
|
||||
case network.Version4:
|
||||
case network.Version4, network.Version5:
|
||||
return Version2
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported network version %d", version))
|
||||
|
||||
@@ -60,6 +60,10 @@ func (bts *BadBlockCache) Remove(c cid.Cid) {
|
||||
bts.badBlocks.Remove(c)
|
||||
}
|
||||
|
||||
func (bts *BadBlockCache) Purge() {
|
||||
bts.badBlocks.Purge()
|
||||
}
|
||||
|
||||
func (bts *BadBlockCache) Has(c cid.Cid) (BadBlockReason, bool) {
|
||||
rval, ok := bts.badBlocks.Get(c)
|
||||
if !ok {
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
func TestPrintGroupInfo(t *testing.T) {
|
||||
server := build.DrandConfigs[build.DrandIncentinet].Servers[0]
|
||||
server := build.DrandConfigs[build.DrandDevnet].Servers[0]
|
||||
c, err := hclient.New(server, nil, nil)
|
||||
assert.NoError(t, err)
|
||||
cg := c.(interface {
|
||||
|
||||
+24
-2
@@ -2,6 +2,7 @@ package events
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"golang.org/x/xerrors"
|
||||
@@ -17,6 +18,8 @@ type tsCacheAPI interface {
|
||||
// tipSetCache implements a simple ring-buffer cache to keep track of recent
|
||||
// tipsets
|
||||
type tipSetCache struct {
|
||||
mu sync.RWMutex
|
||||
|
||||
cache []*types.TipSet
|
||||
start int
|
||||
len int
|
||||
@@ -35,6 +38,9 @@ func newTSCache(cap abi.ChainEpoch, storage tsCacheAPI) *tipSetCache {
|
||||
}
|
||||
|
||||
func (tsc *tipSetCache) add(ts *types.TipSet) error {
|
||||
tsc.mu.Lock()
|
||||
defer tsc.mu.Unlock()
|
||||
|
||||
if tsc.len > 0 {
|
||||
if tsc.cache[tsc.start].Height() >= ts.Height() {
|
||||
return xerrors.Errorf("tipSetCache.add: expected new tipset height to be at least %d, was %d", tsc.cache[tsc.start].Height()+1, ts.Height())
|
||||
@@ -65,6 +71,13 @@ func (tsc *tipSetCache) add(ts *types.TipSet) error {
|
||||
}
|
||||
|
||||
func (tsc *tipSetCache) revert(ts *types.TipSet) error {
|
||||
tsc.mu.Lock()
|
||||
defer tsc.mu.Unlock()
|
||||
|
||||
return tsc.revertUnlocked(ts)
|
||||
}
|
||||
|
||||
func (tsc *tipSetCache) revertUnlocked(ts *types.TipSet) error {
|
||||
if tsc.len == 0 {
|
||||
return nil // this can happen, and it's fine
|
||||
}
|
||||
@@ -77,7 +90,7 @@ func (tsc *tipSetCache) revert(ts *types.TipSet) error {
|
||||
tsc.start = normalModulo(tsc.start-1, len(tsc.cache))
|
||||
tsc.len--
|
||||
|
||||
_ = tsc.revert(nil) // revert null block gap
|
||||
_ = tsc.revertUnlocked(nil) // revert null block gap
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -95,7 +108,10 @@ func (tsc *tipSetCache) getNonNull(height abi.ChainEpoch) (*types.TipSet, error)
|
||||
}
|
||||
|
||||
func (tsc *tipSetCache) get(height abi.ChainEpoch) (*types.TipSet, error) {
|
||||
tsc.mu.RLock()
|
||||
|
||||
if tsc.len == 0 {
|
||||
tsc.mu.RUnlock()
|
||||
log.Warnf("tipSetCache.get: cache is empty, requesting from storage (h=%d)", height)
|
||||
return tsc.storage.ChainGetTipSetByHeight(context.TODO(), height, types.EmptyTSK)
|
||||
}
|
||||
@@ -103,6 +119,7 @@ func (tsc *tipSetCache) get(height abi.ChainEpoch) (*types.TipSet, error) {
|
||||
headH := tsc.cache[tsc.start].Height()
|
||||
|
||||
if height > headH {
|
||||
tsc.mu.RUnlock()
|
||||
return nil, xerrors.Errorf("tipSetCache.get: requested tipset not in cache (req: %d, cache head: %d)", height, headH)
|
||||
}
|
||||
|
||||
@@ -116,15 +133,20 @@ func (tsc *tipSetCache) get(height abi.ChainEpoch) (*types.TipSet, error) {
|
||||
}
|
||||
|
||||
if height < tail.Height() {
|
||||
tsc.mu.RUnlock()
|
||||
log.Warnf("tipSetCache.get: requested tipset not in cache, requesting from storage (h=%d; tail=%d)", height, tail.Height())
|
||||
return tsc.storage.ChainGetTipSetByHeight(context.TODO(), height, tail.Key())
|
||||
}
|
||||
|
||||
return tsc.cache[normalModulo(tsc.start-int(headH-height), clen)], nil
|
||||
ts := tsc.cache[normalModulo(tsc.start-int(headH-height), clen)]
|
||||
tsc.mu.RUnlock()
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
func (tsc *tipSetCache) best() (*types.TipSet, error) {
|
||||
tsc.mu.RLock()
|
||||
best := tsc.cache[tsc.start]
|
||||
tsc.mu.RUnlock()
|
||||
if best == nil {
|
||||
return tsc.storage.ChainHead(context.TODO())
|
||||
}
|
||||
|
||||
+24
-12
@@ -39,6 +39,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/cmd/lotus-seed/seed"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/lotus/genesis"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/filecoin-project/lotus/lib/blockstore"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
@@ -71,7 +72,7 @@ type ChainGen struct {
|
||||
|
||||
GetMessages func(*ChainGen) ([]*types.SignedMessage, error)
|
||||
|
||||
w *wallet.Wallet
|
||||
w *wallet.LocalWallet
|
||||
|
||||
eppProvs map[address.Address]WinningPoStProver
|
||||
Miners []address.Address
|
||||
@@ -122,6 +123,7 @@ var DefaultRemainderAccountActor = genesis.Actor{
|
||||
}
|
||||
|
||||
func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
j := journal.NilJournal()
|
||||
// TODO: we really shouldn't modify a global variable here.
|
||||
policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1)
|
||||
|
||||
@@ -153,14 +155,14 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
return nil, xerrors.Errorf("creating memrepo wallet failed: %w", err)
|
||||
}
|
||||
|
||||
banker, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
banker, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to generate banker key: %w", err)
|
||||
}
|
||||
|
||||
receievers := make([]address.Address, msgsPerBlock)
|
||||
for r := range receievers {
|
||||
receievers[r], err = w.GenerateKey(crypto.SigTypeBLS)
|
||||
receievers[r], err = w.WalletNew(context.Background(), types.KTBLS)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to generate receiver key: %w", err)
|
||||
}
|
||||
@@ -190,11 +192,11 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mk1, err := w.Import(k1)
|
||||
mk1, err := w.WalletImport(context.Background(), k1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mk2, err := w.Import(k2)
|
||||
mk2, err := w.WalletImport(context.Background(), k2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -229,12 +231,12 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
Timestamp: uint64(build.Clock.Now().Add(-500 * time.Duration(build.BlockDelaySecs) * time.Second).Unix()),
|
||||
}
|
||||
|
||||
genb, err := genesis2.MakeGenesisBlock(context.TODO(), bs, sys, tpl)
|
||||
genb, err := genesis2.MakeGenesisBlock(context.TODO(), j, bs, sys, tpl)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("make genesis block failed: %w", err)
|
||||
}
|
||||
|
||||
cs := store.NewChainStore(bs, ds, sys)
|
||||
cs := store.NewChainStore(bs, ds, sys, j)
|
||||
|
||||
genfb := &types.FullBlock{Header: genb.Genesis}
|
||||
gents := store.NewFullTipSet([]*types.FullBlock{genfb})
|
||||
@@ -374,7 +376,13 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add
|
||||
return nil, nil, nil, xerrors.Errorf("get miner worker: %w", err)
|
||||
}
|
||||
|
||||
vrfout, err := ComputeVRF(ctx, cg.w.Sign, worker, ticketRand)
|
||||
sf := func(ctx context.Context, a address.Address, i []byte) (*crypto.Signature, error) {
|
||||
return cg.w.WalletSign(ctx, a, i, api.MsgMeta{
|
||||
Type: api.MTUnknown,
|
||||
})
|
||||
}
|
||||
|
||||
vrfout, err := ComputeVRF(ctx, sf, worker, ticketRand)
|
||||
if err != nil {
|
||||
return nil, nil, nil, xerrors.Errorf("compute VRF: %w", err)
|
||||
}
|
||||
@@ -506,7 +514,7 @@ func (cg *ChainGen) Banker() address.Address {
|
||||
return cg.banker
|
||||
}
|
||||
|
||||
func (cg *ChainGen) Wallet() *wallet.Wallet {
|
||||
func (cg *ChainGen) Wallet() *wallet.LocalWallet {
|
||||
return cg.w
|
||||
}
|
||||
|
||||
@@ -528,7 +536,9 @@ func getRandomMessages(cg *ChainGen) ([]*types.SignedMessage, error) {
|
||||
GasPremium: types.NewInt(0),
|
||||
}
|
||||
|
||||
sig, err := cg.w.Sign(context.TODO(), cg.banker, msg.Cid().Bytes())
|
||||
sig, err := cg.w.WalletSign(context.TODO(), cg.banker, msg.Cid().Bytes(), api.MsgMeta{
|
||||
Type: api.MTUnknown, // testing
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -559,7 +569,7 @@ type MiningCheckAPI interface {
|
||||
}
|
||||
|
||||
type mca struct {
|
||||
w *wallet.Wallet
|
||||
w *wallet.LocalWallet
|
||||
sm *stmgr.StateManager
|
||||
pv ffiwrapper.Verifier
|
||||
bcn beacon.Schedule
|
||||
@@ -588,7 +598,9 @@ func (mca mca) MinerGetBaseInfo(ctx context.Context, maddr address.Address, epoc
|
||||
}
|
||||
|
||||
func (mca mca) WalletSign(ctx context.Context, a address.Address, v []byte) (*crypto.Signature, error) {
|
||||
return mca.w.Sign(ctx, a, v)
|
||||
return mca.w.WalletSign(ctx, a, v, api.MsgMeta{
|
||||
Type: api.MTUnknown,
|
||||
})
|
||||
}
|
||||
|
||||
type WinningPoStProver interface {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
@@ -466,7 +467,10 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci
|
||||
return st, nil
|
||||
}
|
||||
|
||||
func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys vm.SyscallBuilder, template genesis.Template) (*GenesisBootstrap, error) {
|
||||
func MakeGenesisBlock(ctx context.Context, j journal.Journal, bs bstore.Blockstore, sys vm.SyscallBuilder, template genesis.Template) (*GenesisBootstrap, error) {
|
||||
if j == nil {
|
||||
j = journal.NilJournal()
|
||||
}
|
||||
st, keyIDs, err := MakeInitialStateTree(ctx, bs, template)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("make initial state tree failed: %w", err)
|
||||
@@ -478,7 +482,7 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys vm.SyscallB
|
||||
}
|
||||
|
||||
// temp chainstore
|
||||
cs := store.NewChainStore(bs, datastore.NewMapDatastore(), sys)
|
||||
cs := store.NewChainStore(bs, datastore.NewMapDatastore(), sys, j)
|
||||
|
||||
// Verify PreSealed Data
|
||||
stateroot, err = VerifyPreSealedData(ctx, cs, stateroot, template, keyIDs)
|
||||
|
||||
+4
-3
@@ -15,11 +15,10 @@ import (
|
||||
"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/chain/wallet"
|
||||
"github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
)
|
||||
|
||||
func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wallet, bt *api.BlockTemplate) (*types.FullBlock, error) {
|
||||
func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w api.WalletAPI, bt *api.BlockTemplate) (*types.FullBlock, error) {
|
||||
|
||||
pts, err := sm.ChainStore().LoadTipSet(bt.Parents)
|
||||
if err != nil {
|
||||
@@ -131,7 +130,9 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal
|
||||
return nil, xerrors.Errorf("failed to get signing bytes for block: %w", err)
|
||||
}
|
||||
|
||||
sig, err := w.Sign(ctx, waddr, nosigbytes)
|
||||
sig, err := w.WalletSign(ctx, waddr, nosigbytes, api.MsgMeta{
|
||||
Type: api.MTBlock,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to sign new block: %w", err)
|
||||
}
|
||||
|
||||
@@ -120,9 +120,10 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
|
||||
return cid.Undef, err
|
||||
}
|
||||
fm.lk.Lock()
|
||||
defer fm.lk.Unlock()
|
||||
|
||||
bal, err := fm.api.StateMarketBalance(ctx, addr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
fm.lk.Unlock()
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
@@ -138,7 +139,6 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
|
||||
toAdd = types.NewInt(0)
|
||||
}
|
||||
fm.available[idAddr] = big.Add(avail, toAdd)
|
||||
fm.lk.Unlock()
|
||||
|
||||
log.Infof("Funds operation w/ Expected Balance: %s, In State: %s, Requested: %s, Adding: %s", avail.String(), stateAvail.String(), amt.String(), toAdd.String())
|
||||
|
||||
@@ -148,6 +148,7 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
|
||||
|
||||
params, err := actors.SerializeParams(&addr)
|
||||
if err != nil {
|
||||
fm.available[idAddr] = avail
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
@@ -159,6 +160,7 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
|
||||
Params: params,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
fm.available[idAddr] = avail
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
|
||||
@@ -57,9 +57,10 @@ func addFundsMsg(toAdd abi.TokenAmount, addr address.Address, wallet address.Add
|
||||
}
|
||||
|
||||
type expectedResult struct {
|
||||
addAmt abi.TokenAmount
|
||||
shouldAdd bool
|
||||
err error
|
||||
addAmt abi.TokenAmount
|
||||
shouldAdd bool
|
||||
err error
|
||||
cachedAvailable abi.TokenAmount
|
||||
}
|
||||
|
||||
func TestAddFunds(t *testing.T) {
|
||||
@@ -88,8 +89,9 @@ func TestAddFunds(t *testing.T) {
|
||||
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
|
||||
expectedResults: []expectedResult{
|
||||
{
|
||||
shouldAdd: false,
|
||||
err: nil,
|
||||
shouldAdd: false,
|
||||
err: nil,
|
||||
cachedAvailable: abi.NewTokenAmount(100),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -102,18 +104,21 @@ func TestAddFunds(t *testing.T) {
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
addAmt: abi.NewTokenAmount(100),
|
||||
shouldAdd: true,
|
||||
err: nil,
|
||||
addAmt: abi.NewTokenAmount(100),
|
||||
shouldAdd: true,
|
||||
err: nil,
|
||||
cachedAvailable: abi.NewTokenAmount(200),
|
||||
},
|
||||
{
|
||||
addAmt: abi.NewTokenAmount(50),
|
||||
shouldAdd: true,
|
||||
err: nil,
|
||||
addAmt: abi.NewTokenAmount(50),
|
||||
shouldAdd: true,
|
||||
err: nil,
|
||||
cachedAvailable: abi.NewTokenAmount(250),
|
||||
},
|
||||
{
|
||||
shouldAdd: false,
|
||||
err: nil,
|
||||
shouldAdd: false,
|
||||
err: nil,
|
||||
cachedAvailable: abi.NewTokenAmount(250),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -132,7 +137,8 @@ func TestAddFunds(t *testing.T) {
|
||||
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
|
||||
expectedResults: []expectedResult{
|
||||
{
|
||||
err: errors.New("something went wrong"),
|
||||
err: errors.New("something went wrong"),
|
||||
cachedAvailable: abi.NewTokenAmount(0),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -183,6 +189,10 @@ func TestAddFunds(t *testing.T) {
|
||||
} else {
|
||||
require.EqualError(t, err, expected.err.Error())
|
||||
}
|
||||
|
||||
if !expected.cachedAvailable.Nil() {
|
||||
require.Equal(t, expected.cachedAvailable, fundMgr.available[addr])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -59,6 +59,8 @@ var MaxUntrustedActorPendingMessages = 10
|
||||
|
||||
var MaxNonceGap = uint64(4)
|
||||
|
||||
var DefaultMaxFee = abi.TokenAmount(types.MustParseFIL("0.007"))
|
||||
|
||||
var (
|
||||
ErrMessageTooBig = errors.New("message too big")
|
||||
|
||||
@@ -159,6 +161,7 @@ type MessagePool struct {
|
||||
sigValCache *lru.TwoQueueCache
|
||||
|
||||
evtTypes [3]journal.EventType
|
||||
journal journal.Journal
|
||||
}
|
||||
|
||||
type msgSet struct {
|
||||
@@ -182,7 +185,7 @@ func ComputeMinRBF(curPrem abi.TokenAmount) abi.TokenAmount {
|
||||
|
||||
func CapGasFee(msg *types.Message, maxFee abi.TokenAmount) {
|
||||
if maxFee.Equals(big.Zero()) {
|
||||
maxFee = types.NewInt(build.FilecoinPrecision / 10)
|
||||
maxFee = DefaultMaxFee
|
||||
}
|
||||
|
||||
gl := types.NewInt(uint64(msg.GasLimit))
|
||||
@@ -316,7 +319,7 @@ func (ms *msgSet) getRequiredFunds(nonce uint64) types.BigInt {
|
||||
return types.BigInt{Int: requiredFunds}
|
||||
}
|
||||
|
||||
func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*MessagePool, error) {
|
||||
func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName, j journal.Journal) (*MessagePool, error) {
|
||||
cache, _ := lru.New2Q(build.BlsSignatureCacheSize)
|
||||
verifcache, _ := lru.New2Q(build.VerifSigCacheSize)
|
||||
|
||||
@@ -325,6 +328,10 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa
|
||||
return nil, xerrors.Errorf("error loading mpool config: %w", err)
|
||||
}
|
||||
|
||||
if j == nil {
|
||||
j = journal.NilJournal()
|
||||
}
|
||||
|
||||
mp := &MessagePool{
|
||||
ds: ds,
|
||||
addSema: make(chan struct{}, 1),
|
||||
@@ -344,10 +351,11 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa
|
||||
netName: netName,
|
||||
cfg: cfg,
|
||||
evtTypes: [...]journal.EventType{
|
||||
evtTypeMpoolAdd: journal.J.RegisterEventType("mpool", "add"),
|
||||
evtTypeMpoolRemove: journal.J.RegisterEventType("mpool", "remove"),
|
||||
evtTypeMpoolRepub: journal.J.RegisterEventType("mpool", "repub"),
|
||||
evtTypeMpoolAdd: j.RegisterEventType("mpool", "add"),
|
||||
evtTypeMpoolRemove: j.RegisterEventType("mpool", "remove"),
|
||||
evtTypeMpoolRepub: j.RegisterEventType("mpool", "repub"),
|
||||
},
|
||||
journal: j,
|
||||
}
|
||||
|
||||
// enable initial prunes
|
||||
@@ -664,6 +672,10 @@ func (mp *MessagePool) addLoaded(m *types.SignedMessage) error {
|
||||
|
||||
curTs := mp.curTs
|
||||
|
||||
if curTs == nil {
|
||||
return xerrors.Errorf("current tipset not loaded")
|
||||
}
|
||||
|
||||
snonce, err := mp.getStateNonce(m.Message.From, curTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to look up actor state nonce: %s: %w", err, ErrSoftValidationFailure)
|
||||
@@ -744,7 +756,7 @@ func (mp *MessagePool) addLocked(m *types.SignedMessage, strict, untrusted bool)
|
||||
Message: m,
|
||||
}, localUpdates)
|
||||
|
||||
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolAdd], func() interface{} {
|
||||
mp.journal.RecordEvent(mp.evtTypes[evtTypeMpoolAdd], func() interface{} {
|
||||
return MessagePoolEvt{
|
||||
Action: "add",
|
||||
Messages: []MessagePoolEvtMessage{{Message: m.Message, CID: m.Cid()}},
|
||||
@@ -865,7 +877,7 @@ func (mp *MessagePool) remove(from address.Address, nonce uint64, applied bool)
|
||||
Message: m,
|
||||
}, localUpdates)
|
||||
|
||||
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolRemove], func() interface{} {
|
||||
mp.journal.RecordEvent(mp.evtTypes[evtTypeMpoolRemove], func() interface{} {
|
||||
return MessagePoolEvt{
|
||||
Action: "remove",
|
||||
Messages: []MessagePoolEvtMessage{{Message: m.Message, CID: m.Cid()}}}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||
@@ -225,14 +224,14 @@ func TestMessagePool(t *testing.T) {
|
||||
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
mp, err := New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a := tma.nextBlock()
|
||||
|
||||
sender, err := w.GenerateKey(crypto.SigTypeBLS)
|
||||
sender, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -266,14 +265,14 @@ func TestMessagePoolMessagesInEachBlock(t *testing.T) {
|
||||
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
mp, err := New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a := tma.nextBlock()
|
||||
|
||||
sender, err := w.GenerateKey(crypto.SigTypeBLS)
|
||||
sender, err := w.WalletNew(context.Background(), types.KTBLS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -315,7 +314,7 @@ func TestRevertMessages(t *testing.T) {
|
||||
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
mp, err := New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -323,7 +322,7 @@ func TestRevertMessages(t *testing.T) {
|
||||
a := tma.nextBlock()
|
||||
b := tma.nextBlock()
|
||||
|
||||
sender, err := w.GenerateKey(crypto.SigTypeBLS)
|
||||
sender, err := w.WalletNew(context.Background(), types.KTBLS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -378,7 +377,7 @@ func TestPruningSimple(t *testing.T) {
|
||||
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
mp, err := New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -386,7 +385,7 @@ func TestPruningSimple(t *testing.T) {
|
||||
a := tma.nextBlock()
|
||||
tma.applyBlock(t, a)
|
||||
|
||||
sender, err := w.GenerateKey(crypto.SigTypeBLS)
|
||||
sender, err := w.WalletNew(context.Background(), types.KTBLS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -422,7 +421,7 @@ func TestLoadLocal(t *testing.T) {
|
||||
tma := newTestMpoolAPI()
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
mp, err := New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -433,7 +432,7 @@ func TestLoadLocal(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -443,7 +442,7 @@ func TestLoadLocal(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -465,7 +464,7 @@ func TestLoadLocal(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mp, err = New(tma, ds, "mptest")
|
||||
mp, err = New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -494,7 +493,7 @@ func TestClearAll(t *testing.T) {
|
||||
tma := newTestMpoolAPI()
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
mp, err := New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -505,7 +504,7 @@ func TestClearAll(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -515,7 +514,7 @@ func TestClearAll(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -548,7 +547,7 @@ func TestClearNonLocal(t *testing.T) {
|
||||
tma := newTestMpoolAPI()
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
mp, err := New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -559,7 +558,7 @@ func TestClearNonLocal(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -569,7 +568,7 @@ func TestClearNonLocal(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -609,7 +608,7 @@ func TestUpdates(t *testing.T) {
|
||||
tma := newTestMpoolAPI()
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
mp, err := New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -620,7 +619,7 @@ func TestUpdates(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -630,7 +629,7 @@ func TestUpdates(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
@@ -148,14 +147,14 @@ loop:
|
||||
}
|
||||
|
||||
if len(msgs) > 0 {
|
||||
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolRepub], func() interface{} {
|
||||
msgs := make([]MessagePoolEvtMessage, 0, len(msgs))
|
||||
mp.journal.RecordEvent(mp.evtTypes[evtTypeMpoolRepub], func() interface{} {
|
||||
msgsEv := make([]MessagePoolEvtMessage, 0, len(msgs))
|
||||
for _, m := range msgs {
|
||||
msgs = append(msgs, MessagePoolEvtMessage{Message: m.Message, CID: m.Cid()})
|
||||
msgsEv = append(msgsEv, MessagePoolEvtMessage{Message: m.Message, CID: m.Cid()})
|
||||
}
|
||||
return MessagePoolEvt{
|
||||
Action: "repub",
|
||||
Messages: msgs,
|
||||
Messages: msgsEv,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package messagepool
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/ipfs/go-datastore"
|
||||
@@ -21,7 +22,7 @@ func TestRepubMessages(t *testing.T) {
|
||||
tma := newTestMpoolAPI()
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
mp, err := New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -32,7 +33,7 @@ func TestRepubMessages(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -42,7 +43,7 @@ func TestRepubMessages(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -13,20 +13,21 @@ import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
logging "github.com/ipfs/go-log"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
logging "github.com/ipfs/go-log"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -34,7 +35,7 @@ func init() {
|
||||
MaxActorPendingMessages = 1000000
|
||||
}
|
||||
|
||||
func makeTestMessage(w *wallet.Wallet, from, to address.Address, nonce uint64, gasLimit int64, gasPrice uint64) *types.SignedMessage {
|
||||
func makeTestMessage(w *wallet.LocalWallet, from, to address.Address, nonce uint64, gasLimit int64, gasPrice uint64) *types.SignedMessage {
|
||||
msg := &types.Message{
|
||||
From: from,
|
||||
To: to,
|
||||
@@ -45,7 +46,7 @@ func makeTestMessage(w *wallet.Wallet, from, to address.Address, nonce uint64, g
|
||||
GasFeeCap: types.NewInt(100 + gasPrice),
|
||||
GasPremium: types.NewInt(gasPrice),
|
||||
}
|
||||
sig, err := w.Sign(context.TODO(), from, msg.Cid().Bytes())
|
||||
sig, err := w.WalletSign(context.TODO(), from, msg.Cid().Bytes(), api.MsgMeta{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -58,7 +59,7 @@ func makeTestMessage(w *wallet.Wallet, from, to address.Address, nonce uint64, g
|
||||
func makeTestMpool() (*MessagePool, *testMpoolAPI) {
|
||||
tma := newTestMpoolAPI()
|
||||
ds := datastore.NewMapDatastore()
|
||||
mp, err := New(tma, ds, "test")
|
||||
mp, err := New(tma, ds, "test", nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -75,7 +76,7 @@ func TestMessageChains(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -85,7 +86,7 @@ func TestMessageChains(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -313,7 +314,7 @@ func TestMessageChainSkipping(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -323,7 +324,7 @@ func TestMessageChainSkipping(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -389,7 +390,7 @@ func TestBasicMessageSelection(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -399,7 +400,7 @@ func TestBasicMessageSelection(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -533,7 +534,7 @@ func TestMessageSelectionTrimming(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -543,7 +544,7 @@ func TestMessageSelectionTrimming(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -596,7 +597,7 @@ func TestPriorityMessageSelection(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -606,7 +607,7 @@ func TestPriorityMessageSelection(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -675,7 +676,7 @@ func TestPriorityMessageSelection2(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -685,7 +686,7 @@ func TestPriorityMessageSelection2(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -744,7 +745,7 @@ func TestPriorityMessageSelection3(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -754,7 +755,7 @@ func TestPriorityMessageSelection3(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -841,7 +842,7 @@ func TestOptimalMessageSelection1(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -851,7 +852,7 @@ func TestOptimalMessageSelection1(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -908,7 +909,7 @@ func TestOptimalMessageSelection2(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -918,7 +919,7 @@ func TestOptimalMessageSelection2(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -984,7 +985,7 @@ func TestOptimalMessageSelection3(t *testing.T) {
|
||||
nActors := 10
|
||||
// the actors
|
||||
var actors []address.Address
|
||||
var wallets []*wallet.Wallet
|
||||
var wallets []*wallet.LocalWallet
|
||||
|
||||
for i := 0; i < nActors; i++ {
|
||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
@@ -992,7 +993,7 @@ func TestOptimalMessageSelection3(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1064,7 +1065,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu
|
||||
nActors := 300
|
||||
// the actors
|
||||
var actors []address.Address
|
||||
var wallets []*wallet.Wallet
|
||||
var wallets []*wallet.LocalWallet
|
||||
|
||||
for i := 0; i < nActors; i++ {
|
||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
@@ -1072,7 +1073,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1330,7 +1331,7 @@ readLoop:
|
||||
}
|
||||
|
||||
actorMap := make(map[address.Address]address.Address)
|
||||
actorWallets := make(map[address.Address]*wallet.Wallet)
|
||||
actorWallets := make(map[address.Address]api.WalletAPI)
|
||||
|
||||
for _, m := range msgs {
|
||||
baseNonce := baseNonces[m.Message.From]
|
||||
@@ -1342,7 +1343,7 @@ readLoop:
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1360,7 +1361,7 @@ readLoop:
|
||||
m.Message.From = localActor
|
||||
m.Message.Nonce -= baseNonce
|
||||
|
||||
sig, err := w.Sign(context.TODO(), localActor, m.Message.Cid().Bytes())
|
||||
sig, err := w.WalletSign(context.TODO(), localActor, m.Message.Cid().Bytes(), api.MsgMeta{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -5,40 +5,37 @@ import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/ipfs/go-datastore"
|
||||
"github.com/ipfs/go-datastore/namespace"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
)
|
||||
|
||||
const dsKeyActorNonce = "ActorNextNonce"
|
||||
|
||||
var log = logging.Logger("messagesigner")
|
||||
|
||||
type mpoolAPI interface {
|
||||
type MpoolNonceAPI interface {
|
||||
GetNonce(address.Address) (uint64, error)
|
||||
}
|
||||
|
||||
// MessageSigner keeps track of nonces per address, and increments the nonce
|
||||
// when signing a message
|
||||
type MessageSigner struct {
|
||||
wallet *wallet.Wallet
|
||||
wallet api.WalletAPI
|
||||
lk sync.Mutex
|
||||
mpool mpoolAPI
|
||||
mpool MpoolNonceAPI
|
||||
ds datastore.Batching
|
||||
}
|
||||
|
||||
func NewMessageSigner(wallet *wallet.Wallet, mpool *messagepool.MessagePool, ds dtypes.MetadataDS) *MessageSigner {
|
||||
return newMessageSigner(wallet, mpool, ds)
|
||||
}
|
||||
|
||||
func newMessageSigner(wallet *wallet.Wallet, mpool mpoolAPI, ds dtypes.MetadataDS) *MessageSigner {
|
||||
func NewMessageSigner(wallet api.WalletAPI, mpool MpoolNonceAPI, ds dtypes.MetadataDS) *MessageSigner {
|
||||
ds = namespace.Wrap(ds, datastore.NewKey("/message-signer/"))
|
||||
return &MessageSigner{
|
||||
wallet: wallet,
|
||||
@@ -61,7 +58,16 @@ func (ms *MessageSigner) SignMessage(ctx context.Context, msg *types.Message, cb
|
||||
|
||||
// Sign the message with the nonce
|
||||
msg.Nonce = nonce
|
||||
sig, err := ms.wallet.Sign(ctx, msg.From, msg.Cid().Bytes())
|
||||
|
||||
mb, err := msg.ToStorageBlock()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("serializing message: %w", err)
|
||||
}
|
||||
|
||||
sig, err := ms.wallet.WalletSign(ctx, msg.From, mb.Cid().Bytes(), api.MsgMeta{
|
||||
Type: api.MTChainMsg,
|
||||
Extra: mb.RawData(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to sign message: %w", err)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
ds_sync "github.com/ipfs/go-datastore/sync"
|
||||
@@ -47,13 +46,13 @@ func TestMessageSignerSignMessage(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
from1, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
from1, err := w.WalletNew(ctx, types.KTSecp256k1)
|
||||
require.NoError(t, err)
|
||||
from2, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
from2, err := w.WalletNew(ctx, types.KTSecp256k1)
|
||||
require.NoError(t, err)
|
||||
to1, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
to1, err := w.WalletNew(ctx, types.KTSecp256k1)
|
||||
require.NoError(t, err)
|
||||
to2, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
to2, err := w.WalletNew(ctx, types.KTSecp256k1)
|
||||
require.NoError(t, err)
|
||||
|
||||
type msgSpec struct {
|
||||
@@ -177,7 +176,7 @@ func TestMessageSignerSignMessage(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mpool := newMockMpool()
|
||||
ds := ds_sync.MutexWrap(datastore.NewMapDatastore())
|
||||
ms := newMessageSigner(w, mpool, ds)
|
||||
ms := NewMessageSigner(w, mpool, ds)
|
||||
|
||||
for _, m := range tt.msgs {
|
||||
if len(m.mpoolNonce) == 1 {
|
||||
|
||||
+4
-2
@@ -61,7 +61,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.
|
||||
Rand: store.NewChainRand(sm.cs, ts.Cids()),
|
||||
Bstore: sm.cs.Blockstore(),
|
||||
Syscalls: sm.cs.VMSys(),
|
||||
CircSupplyCalc: sm.GetCirculatingSupply,
|
||||
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: types.NewInt(0),
|
||||
}
|
||||
@@ -113,6 +113,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.
|
||||
}
|
||||
|
||||
return &api.InvocResult{
|
||||
MsgCid: msg.Cid(),
|
||||
Msg: msg,
|
||||
MsgRct: &ret.MessageReceipt,
|
||||
ExecutionTrace: ret.ExecutionTrace,
|
||||
@@ -174,7 +175,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
||||
Rand: r,
|
||||
Bstore: sm.cs.Blockstore(),
|
||||
Syscalls: sm.cs.VMSys(),
|
||||
CircSupplyCalc: sm.GetCirculatingSupply,
|
||||
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||
}
|
||||
@@ -228,6 +229,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
||||
}
|
||||
|
||||
return &api.InvocResult{
|
||||
MsgCid: msg.Cid(),
|
||||
Msg: msg,
|
||||
MsgRct: &ret.MessageReceipt,
|
||||
ExecutionTrace: ret.ExecutionTrace,
|
||||
|
||||
+108
-61
@@ -24,7 +24,6 @@ import (
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/migration/nv3"
|
||||
m2 "github.com/filecoin-project/specs-actors/v2/actors/migration"
|
||||
states2 "github.com/filecoin-project/specs-actors/v2/actors/states"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
@@ -80,9 +79,12 @@ func DefaultUpgradeSchedule() UpgradeSchedule {
|
||||
Network: network.Version4,
|
||||
Expensive: true,
|
||||
Migration: UpgradeActorsV2,
|
||||
}, {
|
||||
Height: build.UpgradeTapeHeight,
|
||||
Network: network.Version5,
|
||||
}, {
|
||||
Height: build.UpgradeLiftoffHeight,
|
||||
Network: network.Version4,
|
||||
Network: network.Version5,
|
||||
Migration: UpgradeLiftoff,
|
||||
}}
|
||||
|
||||
@@ -166,7 +168,7 @@ func (sm *StateManager) hasExpensiveFork(ctx context.Context, height abi.ChainEp
|
||||
return ok
|
||||
}
|
||||
|
||||
func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address, amt abi.TokenAmount) error {
|
||||
func doTransfer(tree types.StateTree, from, to address.Address, amt abi.TokenAmount, cb func(trace types.ExecutionTrace)) error {
|
||||
fromAct, err := tree.GetActor(from)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get 'from' actor for transfer: %w", err)
|
||||
@@ -199,7 +201,6 @@ func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address,
|
||||
From: from,
|
||||
To: to,
|
||||
Value: amt,
|
||||
Nonce: math.MaxUint64,
|
||||
}
|
||||
fakeRct := &types.MessageReceipt{
|
||||
ExitCode: 0,
|
||||
@@ -207,22 +208,14 @@ func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address,
|
||||
GasUsed: 0,
|
||||
}
|
||||
|
||||
if err := cb(fakeMsg.Cid(), fakeMsg, &vm.ApplyRet{
|
||||
MessageReceipt: *fakeRct,
|
||||
ActorErr: nil,
|
||||
ExecutionTrace: types.ExecutionTrace{
|
||||
Msg: fakeMsg,
|
||||
MsgRct: fakeRct,
|
||||
Error: "",
|
||||
Duration: 0,
|
||||
GasCharges: nil,
|
||||
Subcalls: nil,
|
||||
},
|
||||
Duration: 0,
|
||||
GasCosts: vm.ZeroGasOutputs(),
|
||||
}); err != nil {
|
||||
return xerrors.Errorf("recording transfer: %w", err)
|
||||
}
|
||||
cb(types.ExecutionTrace{
|
||||
Msg: fakeMsg,
|
||||
MsgRct: fakeRct,
|
||||
Error: "",
|
||||
Duration: 0,
|
||||
GasCharges: nil,
|
||||
Subcalls: nil,
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -263,11 +256,6 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
return cid.Undef, xerrors.Errorf("loading state tree failed: %w", err)
|
||||
}
|
||||
|
||||
ReserveAddress, err := address.NewFromString("t090")
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to parse reserve address: %w", err)
|
||||
}
|
||||
|
||||
tree, err := sm.StateTree(root)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||
@@ -280,6 +268,10 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
}
|
||||
|
||||
var transfers []transfer
|
||||
subcalls := make([]types.ExecutionTrace, 0)
|
||||
transferCb := func(trace types.ExecutionTrace) {
|
||||
subcalls = append(subcalls, trace)
|
||||
}
|
||||
|
||||
// Take all excess funds away, put them into the reserve account
|
||||
err = tree.ForEach(func(addr address.Address, act *types.Actor) error {
|
||||
@@ -293,7 +285,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
if !sysAcc {
|
||||
transfers = append(transfers, transfer{
|
||||
From: addr,
|
||||
To: ReserveAddress,
|
||||
To: builtin.ReserveAddress,
|
||||
Amt: act.Balance,
|
||||
})
|
||||
}
|
||||
@@ -315,11 +307,13 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
available = st.GetAvailableBalance(act.Balance)
|
||||
}
|
||||
|
||||
transfers = append(transfers, transfer{
|
||||
From: addr,
|
||||
To: ReserveAddress,
|
||||
Amt: available,
|
||||
})
|
||||
if !available.IsZero() {
|
||||
transfers = append(transfers, transfer{
|
||||
From: addr,
|
||||
To: builtin.ReserveAddress,
|
||||
Amt: available,
|
||||
})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -329,7 +323,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
|
||||
// Execute transfers from previous step
|
||||
for _, t := range transfers {
|
||||
if err := doTransfer(cb, tree, t.From, t.To, t.Amt); err != nil {
|
||||
if err := doTransfer(tree, t.From, t.To, t.Amt, transferCb); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err)
|
||||
}
|
||||
}
|
||||
@@ -368,7 +362,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
nbalance := big.Min(prevBalance, AccountCap)
|
||||
if nbalance.Sign() != 0 {
|
||||
transfersBack = append(transfersBack, transfer{
|
||||
From: ReserveAddress,
|
||||
From: builtin.ReserveAddress,
|
||||
To: addr,
|
||||
Amt: nbalance,
|
||||
})
|
||||
@@ -395,7 +389,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
|
||||
mfunds := minerFundsAlloc(power, totalPower)
|
||||
transfersBack = append(transfersBack, transfer{
|
||||
From: ReserveAddress,
|
||||
From: builtin.ReserveAddress,
|
||||
To: minfo.Worker,
|
||||
Amt: mfunds,
|
||||
})
|
||||
@@ -415,7 +409,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
|
||||
if lbsectors.Length() > 0 {
|
||||
transfersBack = append(transfersBack, transfer{
|
||||
From: ReserveAddress,
|
||||
From: builtin.ReserveAddress,
|
||||
To: minfo.Worker,
|
||||
Amt: BaseMinerBalance,
|
||||
})
|
||||
@@ -432,7 +426,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
}
|
||||
|
||||
for _, t := range transfersBack {
|
||||
if err := doTransfer(cb, tree, t.From, t.To, t.Amt); err != nil {
|
||||
if err := doTransfer(tree, t.From, t.To, t.Amt, transferCb); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err)
|
||||
}
|
||||
}
|
||||
@@ -442,7 +436,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to load burnt funds actor: %w", err)
|
||||
}
|
||||
if err := doTransfer(cb, tree, builtin0.BurntFundsActorAddr, ReserveAddress, burntAct.Balance); err != nil {
|
||||
if err := doTransfer(tree, builtin0.BurntFundsActorAddr, builtin.ReserveAddress, burntAct.Balance, transferCb); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to unburn funds: %w", err)
|
||||
}
|
||||
|
||||
@@ -458,7 +452,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
}
|
||||
|
||||
difference := types.BigSub(DesiredReimbursementBalance, reimb.Balance)
|
||||
if err := doTransfer(cb, tree, ReserveAddress, reimbAddr, difference); err != nil {
|
||||
if err := doTransfer(tree, builtin.ReserveAddress, reimbAddr, difference, transferCb); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to top up reimbursement account: %w", err)
|
||||
}
|
||||
|
||||
@@ -477,6 +471,39 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
return cid.Undef, xerrors.Errorf("resultant state tree account balance was not correct: %s", total)
|
||||
}
|
||||
|
||||
if cb != nil {
|
||||
// record the transfer in execution traces
|
||||
|
||||
fakeMsg := &types.Message{
|
||||
From: builtin.SystemActorAddr,
|
||||
To: builtin.SystemActorAddr,
|
||||
Value: big.Zero(),
|
||||
Nonce: uint64(epoch),
|
||||
}
|
||||
fakeRct := &types.MessageReceipt{
|
||||
ExitCode: 0,
|
||||
Return: nil,
|
||||
GasUsed: 0,
|
||||
}
|
||||
|
||||
if err := cb(fakeMsg.Cid(), fakeMsg, &vm.ApplyRet{
|
||||
MessageReceipt: *fakeRct,
|
||||
ActorErr: nil,
|
||||
ExecutionTrace: types.ExecutionTrace{
|
||||
Msg: fakeMsg,
|
||||
MsgRct: fakeRct,
|
||||
Error: "",
|
||||
Duration: 0,
|
||||
GasCharges: nil,
|
||||
Subcalls: subcalls,
|
||||
},
|
||||
Duration: 0,
|
||||
GasCosts: vm.ZeroGasOutputs(),
|
||||
}); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("recording transfers: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return tree.Flush(ctx)
|
||||
}
|
||||
|
||||
@@ -517,12 +544,12 @@ func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, roo
|
||||
return cid.Undef, xerrors.Errorf("resetting genesis msig start epochs: %w", err)
|
||||
}
|
||||
|
||||
err = splitGenesisMultisig(ctx, cb, split1, store, tree, 50)
|
||||
err = splitGenesisMultisig(ctx, cb, split1, store, tree, 50, epoch)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("splitting first msig: %w", err)
|
||||
}
|
||||
|
||||
err = splitGenesisMultisig(ctx, cb, split2, store, tree, 50)
|
||||
err = splitGenesisMultisig(ctx, cb, split2, store, tree, 50, epoch)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("splitting second msig: %w", err)
|
||||
}
|
||||
@@ -543,12 +570,7 @@ func UpgradeRefuel(ctx context.Context, sm *StateManager, cb ExecCallback, root
|
||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||
}
|
||||
|
||||
addr, err := address.NewFromString("t0122")
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting address: %w", err)
|
||||
}
|
||||
|
||||
err = resetMultisigVesting(ctx, store, tree, addr, 0, 0, big.Zero())
|
||||
err = resetMultisigVesting(ctx, store, tree, builtin.SaftAddress, 0, 0, big.Zero())
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("tweaking msig vesting: %w", err)
|
||||
}
|
||||
@@ -580,19 +602,6 @@ func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, roo
|
||||
return cid.Undef, xerrors.Errorf("upgrading to actors v2: %w", err)
|
||||
}
|
||||
|
||||
newStateTree, err := states2.LoadTree(store, newHamtRoot)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to load new state tree: %w", err)
|
||||
}
|
||||
|
||||
// Check all state-tree invariants.
|
||||
if msgs, err := states2.CheckStateInvariants(newStateTree, types.TotalFilecoinInt); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to check new state tree: %w", err)
|
||||
} else if !msgs.IsEmpty() {
|
||||
// This error is going to be really nasty.
|
||||
return cid.Undef, xerrors.Errorf("network upgrade failed: %v", msgs.Messages())
|
||||
}
|
||||
|
||||
newRoot, err := store.Put(ctx, &types.StateRoot{
|
||||
Version: types.StateTreeVersion1,
|
||||
Actors: newHamtRoot,
|
||||
@@ -666,7 +675,7 @@ func setNetworkName(ctx context.Context, store adt.Store, tree *state.StateTree,
|
||||
return nil
|
||||
}
|
||||
|
||||
func splitGenesisMultisig(ctx context.Context, cb ExecCallback, addr address.Address, store adt0.Store, tree *state.StateTree, portions uint64) error {
|
||||
func splitGenesisMultisig(ctx context.Context, cb ExecCallback, addr address.Address, store adt0.Store, tree *state.StateTree, portions uint64, epoch abi.ChainEpoch) error {
|
||||
if portions < 1 {
|
||||
return xerrors.Errorf("cannot split into 0 portions")
|
||||
}
|
||||
@@ -735,6 +744,11 @@ func splitGenesisMultisig(ctx context.Context, cb ExecCallback, addr address.Add
|
||||
}
|
||||
|
||||
i := uint64(0)
|
||||
subcalls := make([]types.ExecutionTrace, 0, portions)
|
||||
transferCb := func(trace types.ExecutionTrace) {
|
||||
subcalls = append(subcalls, trace)
|
||||
}
|
||||
|
||||
for i < portions {
|
||||
keyAddr, err := makeKeyAddr(addr, i)
|
||||
if err != nil {
|
||||
@@ -751,13 +765,46 @@ func splitGenesisMultisig(ctx context.Context, cb ExecCallback, addr address.Add
|
||||
return xerrors.Errorf("setting new msig actor state: %w", err)
|
||||
}
|
||||
|
||||
if err := doTransfer(cb, tree, addr, idAddr, newIbal); err != nil {
|
||||
if err := doTransfer(tree, addr, idAddr, newIbal, transferCb); err != nil {
|
||||
return xerrors.Errorf("transferring split msig balance: %w", err)
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
if cb != nil {
|
||||
// record the transfer in execution traces
|
||||
|
||||
fakeMsg := &types.Message{
|
||||
From: builtin.SystemActorAddr,
|
||||
To: addr,
|
||||
Value: big.Zero(),
|
||||
Nonce: uint64(epoch),
|
||||
}
|
||||
fakeRct := &types.MessageReceipt{
|
||||
ExitCode: 0,
|
||||
Return: nil,
|
||||
GasUsed: 0,
|
||||
}
|
||||
|
||||
if err := cb(fakeMsg.Cid(), fakeMsg, &vm.ApplyRet{
|
||||
MessageReceipt: *fakeRct,
|
||||
ActorErr: nil,
|
||||
ExecutionTrace: types.ExecutionTrace{
|
||||
Msg: fakeMsg,
|
||||
MsgRct: fakeRct,
|
||||
Error: "",
|
||||
Duration: 0,
|
||||
GasCharges: nil,
|
||||
Subcalls: subcalls,
|
||||
},
|
||||
Duration: 0,
|
||||
GasCosts: vm.ZeroGasOutputs(),
|
||||
}); err != nil {
|
||||
return xerrors.Errorf("recording transfers: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -6,15 +6,21 @@ import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
ipldcbor "github.com/ipfs/go-ipld-cbor"
|
||||
logging "github.com/ipfs/go-log"
|
||||
"github.com/stretchr/testify/require"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||
lotusinit "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||
@@ -25,11 +31,6 @@ import (
|
||||
"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"
|
||||
ipldcbor "github.com/ipfs/go-ipld-cbor"
|
||||
logging "github.com/ipfs/go-log"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -186,7 +187,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
Params: enc,
|
||||
GasLimit: types.TestGasLimit,
|
||||
}
|
||||
sig, err := cg.Wallet().Sign(ctx, cg.Banker(), m.Cid().Bytes())
|
||||
sig, err := cg.Wallet().WalletSign(ctx, cg.Banker(), m.Cid().Bytes(), api.MsgMeta{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -214,7 +215,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
}
|
||||
nonce++
|
||||
|
||||
sig, err := cg.Wallet().Sign(ctx, cg.Banker(), m.Cid().Bytes())
|
||||
sig, err := cg.Wallet().WalletSign(ctx, cg.Banker(), m.Cid().Bytes(), api.MsgMeta{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+167
-59
@@ -2,10 +2,16 @@ package stmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/verifreg"
|
||||
|
||||
_init "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||
@@ -37,8 +43,16 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
)
|
||||
|
||||
const LookbackNoLimit = abi.ChainEpoch(-1)
|
||||
|
||||
var log = logging.Logger("statemgr")
|
||||
|
||||
type StateManagerAPI interface {
|
||||
LoadActorTsk(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*types.Actor, error)
|
||||
LookupID(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error)
|
||||
ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error)
|
||||
}
|
||||
|
||||
type versionSpec struct {
|
||||
networkVersion network.Version
|
||||
atOrBelow abi.ChainEpoch
|
||||
@@ -186,6 +200,7 @@ func (sm *StateManager) TipSetState(ctx context.Context, ts *types.TipSet) (st c
|
||||
func traceFunc(trace *[]*api.InvocResult) func(mcid cid.Cid, msg *types.Message, ret *vm.ApplyRet) error {
|
||||
return func(mcid cid.Cid, msg *types.Message, ret *vm.ApplyRet) error {
|
||||
ir := &api.InvocResult{
|
||||
MsgCid: mcid,
|
||||
Msg: msg,
|
||||
MsgRct: &ret.MessageReceipt,
|
||||
ExecutionTrace: ret.ExecutionTrace,
|
||||
@@ -220,7 +235,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
Rand: r,
|
||||
Bstore: sm.cs.Blockstore(),
|
||||
Syscalls: sm.cs.VMSys(),
|
||||
CircSupplyCalc: sm.GetCirculatingSupply,
|
||||
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: baseFee,
|
||||
}
|
||||
@@ -233,17 +248,12 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("making vm: %w", err)
|
||||
}
|
||||
|
||||
runCron := func() error {
|
||||
// TODO: this nonce-getting is a tiny bit ugly
|
||||
ca, err := vmi.StateTree().GetActor(builtin0.SystemActorAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
runCron := func(epoch abi.ChainEpoch) error {
|
||||
|
||||
cronMsg := &types.Message{
|
||||
To: builtin0.CronActorAddr,
|
||||
From: builtin0.SystemActorAddr,
|
||||
Nonce: ca.Nonce,
|
||||
Nonce: uint64(epoch),
|
||||
Value: types.NewInt(0),
|
||||
GasFeeCap: types.NewInt(0),
|
||||
GasPremium: types.NewInt(0),
|
||||
@@ -270,7 +280,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
for i := parentEpoch; i < epoch; i++ {
|
||||
if i > parentEpoch {
|
||||
// run cron for null rounds if any
|
||||
if err := runCron(); err != nil {
|
||||
if err := runCron(i); err != nil {
|
||||
return cid.Undef, cid.Undef, err
|
||||
}
|
||||
|
||||
@@ -299,7 +309,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
}
|
||||
|
||||
var receipts []cbg.CBORMarshaler
|
||||
processedMsgs := map[cid.Cid]bool{}
|
||||
processedMsgs := make(map[cid.Cid]struct{})
|
||||
for _, b := range bms {
|
||||
penalty := types.NewInt(0)
|
||||
gasReward := big.Zero()
|
||||
@@ -323,7 +333,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
return cid.Undef, cid.Undef, err
|
||||
}
|
||||
}
|
||||
processedMsgs[m.Cid()] = true
|
||||
processedMsgs[m.Cid()] = struct{}{}
|
||||
}
|
||||
|
||||
params, err := actors.SerializeParams(&reward.AwardBlockRewardParams{
|
||||
@@ -336,15 +346,10 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to serialize award params: %w", err)
|
||||
}
|
||||
|
||||
sysAct, actErr := vmi.StateTree().GetActor(builtin0.SystemActorAddr)
|
||||
if actErr != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to get system actor: %w", actErr)
|
||||
}
|
||||
|
||||
rwMsg := &types.Message{
|
||||
From: builtin0.SystemActorAddr,
|
||||
To: reward.Address,
|
||||
Nonce: sysAct.Nonce,
|
||||
Nonce: uint64(epoch),
|
||||
Value: types.NewInt(0),
|
||||
GasFeeCap: types.NewInt(0),
|
||||
GasPremium: types.NewInt(0),
|
||||
@@ -367,7 +372,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
}
|
||||
}
|
||||
|
||||
if err := runCron(); err != nil {
|
||||
if err := runCron(epoch); err != nil {
|
||||
return cid.Cid{}, cid.Cid{}, err
|
||||
}
|
||||
|
||||
@@ -421,12 +426,7 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, ts *types.TipSet
|
||||
parentEpoch = parent.Height
|
||||
}
|
||||
|
||||
cids := make([]cid.Cid, len(blks))
|
||||
for i, v := range blks {
|
||||
cids[i] = v.Cid()
|
||||
}
|
||||
|
||||
r := store.NewChainRand(sm.cs, cids)
|
||||
r := store.NewChainRand(sm.cs, ts.Cids())
|
||||
|
||||
blkmsgs, err := sm.cs.BlockMsgsForTipset(ts)
|
||||
if err != nil {
|
||||
@@ -507,16 +507,7 @@ func (sm *StateManager) GetReceipt(ctx context.Context, msg cid.Cid, ts *types.T
|
||||
return nil, fmt.Errorf("failed to load message: %w", err)
|
||||
}
|
||||
|
||||
r, _, err := sm.tipsetExecutedMessage(ts, msg, m.VMMessage())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
_, r, _, err = sm.searchBackForMsg(ctx, ts, m)
|
||||
_, r, _, err := sm.searchBackForMsg(ctx, ts, m, LookbackNoLimit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to look back through chain for message: %w", err)
|
||||
}
|
||||
@@ -525,9 +516,9 @@ func (sm *StateManager) GetReceipt(ctx context.Context, msg cid.Cid, ts *types.T
|
||||
}
|
||||
|
||||
// WaitForMessage blocks until a message appears on chain. It looks backwards in the chain to see if this has already
|
||||
// happened. It guarantees that the message has been on chain for at least confidence epochs without being reverted
|
||||
// before returning.
|
||||
func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confidence uint64) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
|
||||
// happened, with an optional limit to how many epochs it will search. It guarantees that the message has been on
|
||||
// chain for at least confidence epochs without being reverted before returning.
|
||||
func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confidence uint64, lookbackLimit abi.ChainEpoch) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
@@ -565,7 +556,7 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confid
|
||||
var backFm cid.Cid
|
||||
backSearchWait := make(chan struct{})
|
||||
go func() {
|
||||
fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head[0].Val, msg)
|
||||
fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head[0].Val, msg, lookbackLimit)
|
||||
if err != nil {
|
||||
log.Warnf("failed to look back through chain for message: %w", err)
|
||||
return
|
||||
@@ -657,7 +648,7 @@ func (sm *StateManager) SearchForMessage(ctx context.Context, mcid cid.Cid) (*ty
|
||||
return head, r, foundMsg, nil
|
||||
}
|
||||
|
||||
fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head, msg)
|
||||
fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head, msg, LookbackNoLimit)
|
||||
|
||||
if err != nil {
|
||||
log.Warnf("failed to look back through chain for message %s", mcid)
|
||||
@@ -671,11 +662,33 @@ func (sm *StateManager) SearchForMessage(ctx context.Context, mcid cid.Cid) (*ty
|
||||
return fts, r, foundMsg, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet, m types.ChainMsg) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
|
||||
// searchBackForMsg searches up to limit tipsets backwards from the given
|
||||
// tipset for a message receipt.
|
||||
// If limit is
|
||||
// - 0 then no tipsets are searched
|
||||
// - 5 then five tipset are searched
|
||||
// - LookbackNoLimit then there is no limit
|
||||
func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet, m types.ChainMsg, limit abi.ChainEpoch) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
|
||||
limitHeight := from.Height() - limit
|
||||
noLimit := limit == LookbackNoLimit
|
||||
|
||||
cur := from
|
||||
curActor, err := sm.LoadActor(ctx, m.VMMessage().From, cur)
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, xerrors.Errorf("failed to load initital tipset")
|
||||
}
|
||||
|
||||
mFromId, err := sm.LookupID(ctx, m.VMMessage().From, from)
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, xerrors.Errorf("looking up From id address: %w", err)
|
||||
}
|
||||
|
||||
mNonce := m.VMMessage().Nonce
|
||||
|
||||
for {
|
||||
if cur.Height() == 0 {
|
||||
// If we've reached the genesis block, or we've reached the limit of
|
||||
// how far back to look
|
||||
if cur.Height() == 0 || !noLimit && cur.Height() <= limitHeight {
|
||||
// it ain't here!
|
||||
return nil, nil, cid.Undef, nil
|
||||
}
|
||||
@@ -686,32 +699,37 @@ func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet
|
||||
default:
|
||||
}
|
||||
|
||||
act, err := sm.LoadActor(ctx, m.VMMessage().From, cur)
|
||||
if err != nil {
|
||||
return nil, nil, cid.Cid{}, err
|
||||
}
|
||||
|
||||
// we either have no messages from the sender, or the latest message we found has a lower nonce than the one being searched for,
|
||||
// either way, no reason to lookback, it ain't there
|
||||
if act.Nonce == 0 || act.Nonce < m.VMMessage().Nonce {
|
||||
if curActor == nil || curActor.Nonce == 0 || curActor.Nonce < mNonce {
|
||||
return nil, nil, cid.Undef, nil
|
||||
}
|
||||
|
||||
ts, err := sm.cs.LoadTipSet(cur.Parents())
|
||||
pts, err := sm.cs.LoadTipSet(cur.Parents())
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, fmt.Errorf("failed to load tipset during msg wait searchback: %w", err)
|
||||
return nil, nil, cid.Undef, xerrors.Errorf("failed to load tipset during msg wait searchback: %w", err)
|
||||
}
|
||||
|
||||
r, foundMsg, err := sm.tipsetExecutedMessage(ts, m.Cid(), m.VMMessage())
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, fmt.Errorf("checking for message execution during lookback: %w", err)
|
||||
act, err := sm.LoadActor(ctx, mFromId, pts)
|
||||
actorNoExist := errors.Is(err, types.ErrActorNotFound)
|
||||
if err != nil && !actorNoExist {
|
||||
return nil, nil, cid.Cid{}, xerrors.Errorf("failed to load the actor: %w", err)
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
return ts, r, foundMsg, nil
|
||||
// check that between cur and parent tipset the nonce fell into range of our message
|
||||
if actorNoExist || (curActor.Nonce > mNonce && act.Nonce <= mNonce) {
|
||||
r, foundMsg, err := sm.tipsetExecutedMessage(cur, m.Cid(), m.VMMessage())
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, xerrors.Errorf("checking for message execution during lookback: %w", err)
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
return cur, r, foundMsg, nil
|
||||
}
|
||||
}
|
||||
|
||||
cur = ts
|
||||
cur = pts
|
||||
curActor = act
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1267,7 +1285,16 @@ func GetFilBurnt(ctx context.Context, st *state.StateTree) (abi.TokenAmount, err
|
||||
return burnt.Balance, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetCirculatingSupplyDetailed(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (api.CirculatingSupply, error) {
|
||||
func (sm *StateManager) GetVMCirculatingSupply(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
cs, err := sm.GetVMCirculatingSupplyDetailed(ctx, height, st)
|
||||
if err != nil {
|
||||
return types.EmptyInt, err
|
||||
}
|
||||
|
||||
return cs.FilCirculating, err
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetVMCirculatingSupplyDetailed(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (api.CirculatingSupply, error) {
|
||||
sm.genesisMsigLk.Lock()
|
||||
defer sm.genesisMsigLk.Unlock()
|
||||
if sm.preIgnitionGenInfos == nil {
|
||||
@@ -1330,12 +1357,91 @@ func (sm *StateManager) GetCirculatingSupplyDetailed(ctx context.Context, height
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
csi, err := sm.GetCirculatingSupplyDetailed(ctx, height, st)
|
||||
circ := big.Zero()
|
||||
unCirc := big.Zero()
|
||||
err := st.ForEach(func(a address.Address, actor *types.Actor) error {
|
||||
switch {
|
||||
case actor.Balance.IsZero():
|
||||
// Do nothing for zero-balance actors
|
||||
break
|
||||
case a == _init.Address ||
|
||||
a == reward.Address ||
|
||||
a == verifreg.Address ||
|
||||
// The power actor itself should never receive funds
|
||||
a == power.Address ||
|
||||
a == builtin.SystemActorAddr ||
|
||||
a == builtin.CronActorAddr ||
|
||||
a == builtin.BurntFundsActorAddr ||
|
||||
a == builtin.SaftAddress ||
|
||||
a == builtin.ReserveAddress:
|
||||
|
||||
unCirc = big.Add(unCirc, actor.Balance)
|
||||
|
||||
case a == market.Address:
|
||||
mst, err := market.Load(sm.cs.Store(ctx), actor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lb, err := mst.TotalLocked()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
circ = big.Add(circ, big.Sub(actor.Balance, lb))
|
||||
unCirc = big.Add(unCirc, lb)
|
||||
|
||||
case builtin.IsAccountActor(actor.Code) || builtin.IsPaymentChannelActor(actor.Code):
|
||||
circ = big.Add(circ, actor.Balance)
|
||||
|
||||
case builtin.IsStorageMinerActor(actor.Code):
|
||||
mst, err := miner.Load(sm.cs.Store(ctx), actor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ab, err := mst.AvailableBalance(actor.Balance)
|
||||
|
||||
if err == nil {
|
||||
circ = big.Add(circ, ab)
|
||||
unCirc = big.Add(unCirc, big.Sub(actor.Balance, ab))
|
||||
} else {
|
||||
// Assume any error is because the miner state is "broken" (lower actor balance than locked funds)
|
||||
// In this case, the actor's entire balance is considered "uncirculating"
|
||||
unCirc = big.Add(unCirc, actor.Balance)
|
||||
}
|
||||
|
||||
case builtin.IsMultisigActor(actor.Code):
|
||||
mst, err := multisig.Load(sm.cs.Store(ctx), actor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lb, err := mst.LockedBalance(height)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ab := big.Sub(actor.Balance, lb)
|
||||
circ = big.Add(circ, big.Max(ab, big.Zero()))
|
||||
unCirc = big.Add(unCirc, big.Min(actor.Balance, lb))
|
||||
default:
|
||||
return xerrors.Errorf("unexpected actor: %s", a)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return big.Zero(), err
|
||||
return types.EmptyInt, err
|
||||
}
|
||||
|
||||
return csi.FilCirculating, nil
|
||||
total := big.Add(circ, unCirc)
|
||||
if !total.Equals(types.TotalFilecoinInt) {
|
||||
return types.EmptyInt, xerrors.Errorf("total filecoin didn't add to expected amount: %s != %s", total, types.TotalFilecoinInt)
|
||||
}
|
||||
|
||||
return circ, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) network.Version {
|
||||
@@ -1384,3 +1490,5 @@ func (sm *StateManager) GetMarketState(ctx context.Context, ts *types.TipSet) (m
|
||||
}
|
||||
return actState, nil
|
||||
}
|
||||
|
||||
var _ StateManagerAPI = (*StateManager)(nil)
|
||||
|
||||
@@ -383,7 +383,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
||||
Rand: r,
|
||||
Bstore: sm.cs.Blockstore(),
|
||||
Syscalls: sm.cs.VMSys(),
|
||||
CircSupplyCalc: sm.GetCirculatingSupply,
|
||||
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ func TestIndexSeeks(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
|
||||
nbs := blockstore.NewTemporarySync()
|
||||
cs := store.NewChainStore(nbs, syncds.MutexWrap(datastore.NewMapDatastore()), nil)
|
||||
cs := store.NewChainStore(nbs, syncds.MutexWrap(datastore.NewMapDatastore()), nil, nil)
|
||||
|
||||
_, err = cs.Import(bytes.NewReader(gencar))
|
||||
if err != nil {
|
||||
|
||||
+59
-4
@@ -8,6 +8,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
@@ -38,7 +39,9 @@ import (
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
block "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
dstore "github.com/ipfs/go-datastore"
|
||||
"github.com/ipfs/go-datastore/query"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
car "github.com/ipld/go-car"
|
||||
@@ -102,7 +105,7 @@ type HeadChangeEvt struct {
|
||||
// 2. a block => messages references cache.
|
||||
type ChainStore struct {
|
||||
bs bstore.Blockstore
|
||||
ds dstore.Datastore
|
||||
ds dstore.Batching
|
||||
|
||||
heaviestLk sync.Mutex
|
||||
heaviest *types.TipSet
|
||||
@@ -124,11 +127,15 @@ type ChainStore struct {
|
||||
vmcalls vm.SyscallBuilder
|
||||
|
||||
evtTypes [1]journal.EventType
|
||||
journal journal.Journal
|
||||
}
|
||||
|
||||
func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls vm.SyscallBuilder) *ChainStore {
|
||||
func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls vm.SyscallBuilder, j journal.Journal) *ChainStore {
|
||||
c, _ := lru.NewARC(DefaultMsgMetaCacheSize)
|
||||
tsc, _ := lru.NewARC(DefaultTipSetCacheSize)
|
||||
if j == nil {
|
||||
j = journal.NilJournal()
|
||||
}
|
||||
cs := &ChainStore{
|
||||
bs: bs,
|
||||
ds: ds,
|
||||
@@ -137,10 +144,11 @@ func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls vm.SyscallB
|
||||
mmCache: c,
|
||||
tsCache: tsc,
|
||||
vmcalls: vmcalls,
|
||||
journal: j,
|
||||
}
|
||||
|
||||
cs.evtTypes = [1]journal.EventType{
|
||||
evtTypeHeadChange: journal.J.RegisterEventType("sync", "head_change"),
|
||||
evtTypeHeadChange: j.RegisterEventType("sync", "head_change"),
|
||||
}
|
||||
|
||||
ci := NewChainIndex(cs.LoadTipSet)
|
||||
@@ -379,7 +387,7 @@ func (cs *ChainStore) reorgWorker(ctx context.Context, initialNotifees []ReorgNo
|
||||
continue
|
||||
}
|
||||
|
||||
journal.J.RecordEvent(cs.evtTypes[evtTypeHeadChange], func() interface{} {
|
||||
cs.journal.RecordEvent(cs.evtTypes[evtTypeHeadChange], func() interface{} {
|
||||
return HeadChangeEvt{
|
||||
From: r.old.Key(),
|
||||
FromHeight: r.old.Height(),
|
||||
@@ -441,6 +449,53 @@ func (cs *ChainStore) takeHeaviestTipSet(ctx context.Context, ts *types.TipSet)
|
||||
return nil
|
||||
}
|
||||
|
||||
// FlushValidationCache removes all results of block validation from the
|
||||
// chain metadata store. Usually the first step after a new chain import.
|
||||
func (cs *ChainStore) FlushValidationCache() error {
|
||||
log.Infof("clearing block validation cache...")
|
||||
|
||||
dsWalk, err := cs.ds.Query(query.Query{
|
||||
// Potential TODO: the validation cache is not a namespace on its own
|
||||
// but is rather constructed as prefixed-key `foo:bar` via .Instance(), which
|
||||
// in turn does not work with the filter, which can match only on `foo/bar`
|
||||
//
|
||||
// If this is addressed (blockcache goes into its own sub-namespace) then
|
||||
// strings.HasPrefix(...) below can be skipped
|
||||
//
|
||||
//Prefix: blockValidationCacheKeyPrefix.String()
|
||||
KeysOnly: true,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to initialize key listing query: %w", err)
|
||||
}
|
||||
|
||||
allKeys, err := dsWalk.Rest()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to run key listing query: %w", err)
|
||||
}
|
||||
|
||||
batch, err := cs.ds.Batch()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to open a DS batch: %w", err)
|
||||
}
|
||||
|
||||
delCnt := 0
|
||||
for _, k := range allKeys {
|
||||
if strings.HasPrefix(k.Key, blockValidationCacheKeyPrefix.String()) {
|
||||
delCnt++
|
||||
batch.Delete(datastore.RawKey(k.Key)) // nolint:errcheck
|
||||
}
|
||||
}
|
||||
|
||||
if err := batch.Commit(); err != nil {
|
||||
return xerrors.Errorf("failed to commit the DS batch: %w", err)
|
||||
}
|
||||
|
||||
log.Infof("%d block validation entries cleared.", delCnt)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetHead sets the chainstores current 'best' head node.
|
||||
// This should only be called if something is broken and needs fixing
|
||||
func (cs *ChainStore) SetHead(ts *types.TipSet) error {
|
||||
|
||||
@@ -62,7 +62,7 @@ func BenchmarkGetRandomness(b *testing.B) {
|
||||
|
||||
bs := blockstore.NewBlockstore(bds)
|
||||
|
||||
cs := store.NewChainStore(bs, mds, nil)
|
||||
cs := store.NewChainStore(bs, mds, nil, nil)
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
@@ -96,7 +96,7 @@ func TestChainExportImport(t *testing.T) {
|
||||
}
|
||||
|
||||
nbs := blockstore.NewTemporary()
|
||||
cs := store.NewChainStore(nbs, datastore.NewMapDatastore(), nil)
|
||||
cs := store.NewChainStore(nbs, datastore.NewMapDatastore(), nil, nil)
|
||||
|
||||
root, err := cs.Import(buf)
|
||||
if err != nil {
|
||||
|
||||
+39
-34
@@ -37,6 +37,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/lib/bufbstore"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
"github.com/filecoin-project/lotus/metrics"
|
||||
"github.com/filecoin-project/lotus/node/impl/client"
|
||||
)
|
||||
|
||||
var log = logging.Logger("sub")
|
||||
@@ -44,6 +45,13 @@ var log = logging.Logger("sub")
|
||||
var ErrSoftFailure = errors.New("soft validation failure")
|
||||
var ErrInsufficientPower = errors.New("incoming block's miner does not have minimum power")
|
||||
|
||||
var msgCidPrefix = cid.Prefix{
|
||||
Version: 1,
|
||||
Codec: cid.DagCBOR,
|
||||
MhType: client.DefaultHashFunction,
|
||||
MhLength: 32,
|
||||
}
|
||||
|
||||
func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *chain.Syncer, bs bserv.BlockService, cmgr connmgr.ConnManager) {
|
||||
// Timeout after (block time + propagation delay). This is useless at
|
||||
// this point.
|
||||
@@ -120,12 +128,6 @@ func FetchMessagesByCids(
|
||||
return err
|
||||
}
|
||||
|
||||
// FIXME: We already sort in `fetchCids`, we are duplicating too much work,
|
||||
// we don't need to pass the index.
|
||||
if out[i] != nil {
|
||||
return fmt.Errorf("received duplicate message")
|
||||
}
|
||||
|
||||
out[i] = msg
|
||||
return nil
|
||||
})
|
||||
@@ -149,10 +151,6 @@ func FetchSignedMessagesByCids(
|
||||
return err
|
||||
}
|
||||
|
||||
if out[i] != nil {
|
||||
return fmt.Errorf("received duplicate message")
|
||||
}
|
||||
|
||||
out[i] = smsg
|
||||
return nil
|
||||
})
|
||||
@@ -172,37 +170,44 @@ func fetchCids(
|
||||
cids []cid.Cid,
|
||||
cb func(int, blocks.Block) error,
|
||||
) error {
|
||||
fetchedBlocks := bserv.GetBlocks(ctx, cids)
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
cidIndex := make(map[cid.Cid]int)
|
||||
for i, c := range cids {
|
||||
if c.Prefix() != msgCidPrefix {
|
||||
return fmt.Errorf("invalid msg CID: %s", c)
|
||||
}
|
||||
cidIndex[c] = i
|
||||
}
|
||||
if len(cids) != len(cidIndex) {
|
||||
return fmt.Errorf("duplicate CIDs in fetchCids input")
|
||||
}
|
||||
|
||||
for i := 0; i < len(cids); i++ {
|
||||
select {
|
||||
case block, ok := <-fetchedBlocks:
|
||||
if !ok {
|
||||
// Closed channel, no more blocks fetched, check if we have all
|
||||
// of the CIDs requested.
|
||||
// FIXME: Review this check. We don't call the callback on the
|
||||
// last index?
|
||||
if i == len(cids)-1 {
|
||||
break
|
||||
}
|
||||
|
||||
return fmt.Errorf("failed to fetch all messages")
|
||||
}
|
||||
|
||||
ix, ok := cidIndex[block.Cid()]
|
||||
if !ok {
|
||||
return fmt.Errorf("received message we didnt ask for")
|
||||
}
|
||||
|
||||
if err := cb(ix, block); err != nil {
|
||||
return err
|
||||
}
|
||||
for block := range bserv.GetBlocks(ctx, cids) {
|
||||
ix, ok := cidIndex[block.Cid()]
|
||||
if !ok {
|
||||
// Ignore duplicate/unexpected blocks. This shouldn't
|
||||
// happen, but we can be safe.
|
||||
log.Errorw("received duplicate/unexpected block when syncing", "cid", block.Cid())
|
||||
continue
|
||||
}
|
||||
|
||||
// Record that we've received the block.
|
||||
delete(cidIndex, block.Cid())
|
||||
|
||||
if err := cb(ix, block); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(cidIndex) > 0 {
|
||||
err := ctx.Err()
|
||||
if err == nil {
|
||||
err = fmt.Errorf("failed to fetch %d messages for unknown reasons", len(cidIndex))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package sub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
address "github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
blocks "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
type getter struct {
|
||||
msgs []*types.Message
|
||||
}
|
||||
|
||||
func (g *getter) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) { panic("NYI") }
|
||||
|
||||
func (g *getter) GetBlocks(ctx context.Context, ks []cid.Cid) <-chan blocks.Block {
|
||||
ch := make(chan blocks.Block, len(g.msgs))
|
||||
for _, m := range g.msgs {
|
||||
by, err := m.Serialize()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
b, err := blocks.NewBlockWithCid(by, m.Cid())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ch <- b
|
||||
}
|
||||
close(ch)
|
||||
return ch
|
||||
}
|
||||
|
||||
func TestFetchCidsWithDedup(t *testing.T) {
|
||||
msgs := []*types.Message{}
|
||||
for i := 0; i < 10; i++ {
|
||||
msgs = append(msgs, &types.Message{
|
||||
From: address.TestAddress,
|
||||
To: address.TestAddress,
|
||||
|
||||
Nonce: uint64(i),
|
||||
})
|
||||
}
|
||||
cids := []cid.Cid{}
|
||||
for _, m := range msgs {
|
||||
cids = append(cids, m.Cid())
|
||||
}
|
||||
g := &getter{msgs}
|
||||
|
||||
// the cids have a duplicate
|
||||
res, err := FetchMessagesByCids(context.TODO(), g, append(cids, cids[0]))
|
||||
|
||||
t.Logf("err: %+v", err)
|
||||
t.Logf("res: %+v", res)
|
||||
if err == nil {
|
||||
t.Errorf("there should be an error")
|
||||
}
|
||||
if err == nil && (res[0] == nil || res[len(res)-1] == nil) {
|
||||
t.Fatalf("there is a nil message: first %p, last %p", res[0], res[len(res)-1])
|
||||
}
|
||||
}
|
||||
+72
-48
@@ -217,6 +217,12 @@ func (syncer *Syncer) Stop() {
|
||||
// This should be called when connecting to new peers, and additionally
|
||||
// when receiving new blocks from the network
|
||||
func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Errorf("panic in InformNewHead: ", err)
|
||||
}
|
||||
}()
|
||||
|
||||
ctx := context.Background()
|
||||
if fts == nil {
|
||||
log.Errorf("got nil tipset in InformNewHead")
|
||||
@@ -317,25 +323,35 @@ func (syncer *Syncer) ValidateMsgMeta(fblk *types.FullBlock) error {
|
||||
return xerrors.Errorf("block %s has too many messages (%d)", fblk.Header.Cid(), msgc)
|
||||
}
|
||||
|
||||
// Collect the CIDs of both types of messages separately: BLS and Secpk.
|
||||
var bcids, scids []cid.Cid
|
||||
for _, m := range fblk.BlsMessages {
|
||||
bcids = append(bcids, m.Cid())
|
||||
}
|
||||
|
||||
for _, m := range fblk.SecpkMessages {
|
||||
scids = append(scids, m.Cid())
|
||||
}
|
||||
|
||||
// TODO: IMPORTANT(GARBAGE). These message puts and the msgmeta
|
||||
// computation need to go into the 'temporary' side of the blockstore when
|
||||
// we implement that
|
||||
blockstore := syncer.store.Blockstore()
|
||||
|
||||
bs := cbor.NewCborStore(blockstore)
|
||||
// We use a temporary bstore here to avoid writing intermediate pieces
|
||||
// into the blockstore.
|
||||
blockstore := bstore.NewTemporary()
|
||||
cst := cbor.NewCborStore(blockstore)
|
||||
|
||||
var bcids, scids []cid.Cid
|
||||
|
||||
for _, m := range fblk.BlsMessages {
|
||||
c, err := store.PutMessage(blockstore, m)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("putting bls message to blockstore after msgmeta computation: %w", err)
|
||||
}
|
||||
bcids = append(bcids, c)
|
||||
}
|
||||
|
||||
for _, m := range fblk.SecpkMessages {
|
||||
c, err := store.PutMessage(blockstore, m)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("putting bls message to blockstore after msgmeta computation: %w", err)
|
||||
}
|
||||
scids = append(scids, c)
|
||||
}
|
||||
|
||||
// Compute the root CID of the combined message trie.
|
||||
smroot, err := computeMsgMeta(bs, bcids, scids)
|
||||
smroot, err := computeMsgMeta(cst, bcids, scids)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("validating msgmeta, compute failed: %w", err)
|
||||
}
|
||||
@@ -345,21 +361,8 @@ func (syncer *Syncer) ValidateMsgMeta(fblk *types.FullBlock) error {
|
||||
return xerrors.Errorf("messages in full block did not match msgmeta root in header (%s != %s)", fblk.Header.Messages, smroot)
|
||||
}
|
||||
|
||||
for _, m := range fblk.BlsMessages {
|
||||
_, err := store.PutMessage(blockstore, m)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("putting bls message to blockstore after msgmeta computation: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, m := range fblk.SecpkMessages {
|
||||
_, err := store.PutMessage(blockstore, m)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("putting bls message to blockstore after msgmeta computation: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
// Finally, flush.
|
||||
return vm.Copy(context.TODO(), blockstore, syncer.store.Blockstore(), smroot)
|
||||
}
|
||||
|
||||
func (syncer *Syncer) LocalPeer() peer.ID {
|
||||
@@ -731,7 +734,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock, use
|
||||
|
||||
lbst, _, err := syncer.sm.TipSetState(ctx, lbts)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to compute lookback tipset state: %w", err)
|
||||
return xerrors.Errorf("failed to compute lookback tipset state (epoch %d): %w", lbts.Height(), err)
|
||||
}
|
||||
|
||||
prevBeacon, err := syncer.store.GetLatestBeaconEntry(baseTs)
|
||||
@@ -1058,8 +1061,7 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
|
||||
return err
|
||||
}
|
||||
|
||||
cst := cbor.NewCborStore(syncer.store.Blockstore())
|
||||
st, err := state.LoadStateTree(cst, stateroot)
|
||||
st, err := state.LoadStateTree(syncer.store.Store(ctx), stateroot)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to load base state tree: %w", err)
|
||||
}
|
||||
@@ -1105,21 +1107,28 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
|
||||
return nil
|
||||
}
|
||||
|
||||
store := adt0.WrapStore(ctx, cst)
|
||||
// Validate message arrays in a temporary blockstore.
|
||||
tmpbs := bstore.NewTemporary()
|
||||
tmpstore := adt0.WrapStore(ctx, cbor.NewCborStore(tmpbs))
|
||||
|
||||
bmArr := adt0.MakeEmptyArray(store)
|
||||
bmArr := adt0.MakeEmptyArray(tmpstore)
|
||||
for i, m := range b.BlsMessages {
|
||||
if err := checkMsg(m); err != nil {
|
||||
return xerrors.Errorf("block had invalid bls message at index %d: %w", i, err)
|
||||
}
|
||||
|
||||
c := cbg.CborCid(m.Cid())
|
||||
if err := bmArr.Set(uint64(i), &c); err != nil {
|
||||
c, err := store.PutMessage(tmpbs, m)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to store message %s: %w", m.Cid(), err)
|
||||
}
|
||||
|
||||
k := cbg.CborCid(c)
|
||||
if err := bmArr.Set(uint64(i), &k); err != nil {
|
||||
return xerrors.Errorf("failed to put bls message at index %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
smArr := adt0.MakeEmptyArray(store)
|
||||
smArr := adt0.MakeEmptyArray(tmpstore)
|
||||
for i, m := range b.SecpkMessages {
|
||||
if err := checkMsg(m); err != nil {
|
||||
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
|
||||
@@ -1136,8 +1145,12 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
|
||||
return xerrors.Errorf("secpk message %s has invalid signature: %w", m.Cid(), err)
|
||||
}
|
||||
|
||||
c := cbg.CborCid(m.Cid())
|
||||
if err := smArr.Set(uint64(i), &c); err != nil {
|
||||
c, err := store.PutMessage(tmpbs, m)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to store message %s: %w", m.Cid(), err)
|
||||
}
|
||||
k := cbg.CborCid(c)
|
||||
if err := smArr.Set(uint64(i), &k); err != nil {
|
||||
return xerrors.Errorf("failed to put secpk message at index %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
@@ -1152,7 +1165,7 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
|
||||
return err
|
||||
}
|
||||
|
||||
mrcid, err := cst.Put(ctx, &types.MsgMeta{
|
||||
mrcid, err := tmpstore.Put(ctx, &types.MsgMeta{
|
||||
BlsMessages: bmroot,
|
||||
SecpkMessages: smroot,
|
||||
})
|
||||
@@ -1164,7 +1177,8 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
|
||||
return fmt.Errorf("messages didnt match message root in header")
|
||||
}
|
||||
|
||||
return nil
|
||||
// Finally, flush.
|
||||
return vm.Copy(ctx, tmpbs, syncer.store.Blockstore(), mrcid)
|
||||
}
|
||||
|
||||
func (syncer *Syncer) verifyBlsAggregate(ctx context.Context, sig *crypto.Signature, msgs []cid.Cid, pubks [][]byte) error {
|
||||
@@ -1281,9 +1295,11 @@ func (syncer *Syncer) collectHeaders(ctx context.Context, incoming *types.TipSet
|
||||
|
||||
blockSet := []*types.TipSet{incoming}
|
||||
|
||||
// Parent of the new (possibly better) tipset that we need to fetch next.
|
||||
at := incoming.Parents()
|
||||
|
||||
// we want to sync all the blocks until the height above the block we have
|
||||
// we want to sync all the blocks until the height above our
|
||||
// best tipset so far
|
||||
untilHeight := known.Height() + 1
|
||||
|
||||
ss.SetHeight(blockSet[len(blockSet)-1].Height())
|
||||
@@ -1377,13 +1393,17 @@ loop:
|
||||
}
|
||||
|
||||
base := blockSet[len(blockSet)-1]
|
||||
if base.Parents() == known.Parents() {
|
||||
// common case: receiving a block thats potentially part of the same tipset as our best block
|
||||
if base.IsChildOf(known) {
|
||||
// common case: receiving blocks that are building on top of our best tipset
|
||||
return blockSet, nil
|
||||
}
|
||||
|
||||
if types.CidArrsEqual(base.Parents().Cids(), known.Cids()) {
|
||||
// common case: receiving blocks that are building on top of our best tipset
|
||||
knownParent, err := syncer.store.LoadTipSet(known.Parents())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load next local tipset: %w", err)
|
||||
}
|
||||
if base.IsChildOf(knownParent) {
|
||||
// common case: receiving a block thats potentially part of the same tipset as our best block
|
||||
return blockSet, nil
|
||||
}
|
||||
|
||||
@@ -1466,7 +1486,7 @@ func (syncer *Syncer) syncFork(ctx context.Context, incoming *types.TipSet, know
|
||||
|
||||
func (syncer *Syncer) syncMessagesAndCheckState(ctx context.Context, headers []*types.TipSet) error {
|
||||
ss := extractSyncState(ctx)
|
||||
ss.SetHeight(0)
|
||||
ss.SetHeight(headers[len(headers)-1].Height())
|
||||
|
||||
return syncer.iterFullTipsets(ctx, headers, func(ctx context.Context, fts *store.FullTipSet) error {
|
||||
log.Debugw("validating tipset", "height", fts.TipSet().Height(), "size", len(fts.TipSet().Cids()))
|
||||
@@ -1514,7 +1534,7 @@ func (syncer *Syncer) iterFullTipsets(ctx context.Context, headers []*types.TipS
|
||||
ss.SetStage(api.StageMessages)
|
||||
|
||||
if batchErr != nil {
|
||||
return xerrors.Errorf("failed to fetch messages: %w", err)
|
||||
return xerrors.Errorf("failed to fetch messages: %w", batchErr)
|
||||
}
|
||||
|
||||
for bsi := 0; bsi < len(bstout); bsi++ {
|
||||
@@ -1714,7 +1734,7 @@ func VerifyElectionPoStVRF(ctx context.Context, worker address.Address, rand []b
|
||||
return gen.VerifyVRF(ctx, worker, rand, evrf)
|
||||
}
|
||||
|
||||
func (syncer *Syncer) State() []SyncerState {
|
||||
func (syncer *Syncer) State() []SyncerStateSnapshot {
|
||||
return syncer.syncmgr.State()
|
||||
}
|
||||
|
||||
@@ -1728,6 +1748,10 @@ func (syncer *Syncer) UnmarkBad(blk cid.Cid) {
|
||||
syncer.bad.Remove(blk)
|
||||
}
|
||||
|
||||
func (syncer *Syncer) UnmarkAllBad() {
|
||||
syncer.bad.Purge()
|
||||
}
|
||||
|
||||
func (syncer *Syncer) CheckBadBlockCache(blk cid.Cid) (string, bool) {
|
||||
bbr, ok := syncer.bad.Has(blk)
|
||||
return bbr.String(), ok
|
||||
|
||||
@@ -38,7 +38,7 @@ type SyncManager interface {
|
||||
SetPeerHead(ctx context.Context, p peer.ID, ts *types.TipSet)
|
||||
|
||||
// State retrieves the state of the sync workers.
|
||||
State() []SyncerState
|
||||
State() []SyncerStateSnapshot
|
||||
}
|
||||
|
||||
type syncManager struct {
|
||||
@@ -79,7 +79,7 @@ type syncResult struct {
|
||||
const syncWorkerCount = 3
|
||||
|
||||
func NewSyncManager(sync SyncFunc) SyncManager {
|
||||
return &syncManager{
|
||||
sm := &syncManager{
|
||||
bspThresh: 1,
|
||||
peerHeads: make(map[peer.ID]*types.TipSet),
|
||||
syncTargets: make(chan *types.TipSet),
|
||||
@@ -90,6 +90,10 @@ func NewSyncManager(sync SyncFunc) SyncManager {
|
||||
doSync: sync,
|
||||
stop: make(chan struct{}),
|
||||
}
|
||||
for i := range sm.syncStates {
|
||||
sm.syncStates[i] = new(SyncerState)
|
||||
}
|
||||
return sm
|
||||
}
|
||||
|
||||
func (sm *syncManager) Start() {
|
||||
@@ -128,8 +132,8 @@ func (sm *syncManager) SetPeerHead(ctx context.Context, p peer.ID, ts *types.Tip
|
||||
sm.incomingTipSets <- ts
|
||||
}
|
||||
|
||||
func (sm *syncManager) State() []SyncerState {
|
||||
ret := make([]SyncerState, 0, len(sm.syncStates))
|
||||
func (sm *syncManager) State() []SyncerStateSnapshot {
|
||||
ret := make([]SyncerStateSnapshot, 0, len(sm.syncStates))
|
||||
for _, s := range sm.syncStates {
|
||||
ret = append(ret, s.Snapshot())
|
||||
}
|
||||
@@ -405,8 +409,7 @@ func (sm *syncManager) scheduleWorkSent() {
|
||||
}
|
||||
|
||||
func (sm *syncManager) syncWorker(id int) {
|
||||
ss := &SyncerState{}
|
||||
sm.syncStates[id] = ss
|
||||
ss := sm.syncStates[id]
|
||||
for {
|
||||
select {
|
||||
case ts, ok := <-sm.syncTargets:
|
||||
|
||||
+6
-6
@@ -221,8 +221,7 @@ func (tu *syncTestUtil) addSourceNode(gen int) {
|
||||
sourceRepo, genesis, blocks := tu.repoWithChain(tu.t, gen)
|
||||
var out api.FullNode
|
||||
|
||||
// TODO: Don't ignore stop
|
||||
_, err := node.New(tu.ctx,
|
||||
stop, err := node.New(tu.ctx,
|
||||
node.FullAPI(&out),
|
||||
node.Online(),
|
||||
node.Repo(sourceRepo),
|
||||
@@ -232,6 +231,7 @@ func (tu *syncTestUtil) addSourceNode(gen int) {
|
||||
node.Override(new(modules.Genesis), modules.LoadGenesis(genesis)),
|
||||
)
|
||||
require.NoError(tu.t, err)
|
||||
tu.t.Cleanup(func() { _ = stop(context.Background()) })
|
||||
|
||||
lastTs := blocks[len(blocks)-1].Blocks
|
||||
for _, lastB := range lastTs {
|
||||
@@ -253,8 +253,7 @@ func (tu *syncTestUtil) addClientNode() int {
|
||||
|
||||
var out api.FullNode
|
||||
|
||||
// TODO: Don't ignore stop
|
||||
_, err := node.New(tu.ctx,
|
||||
stop, err := node.New(tu.ctx,
|
||||
node.FullAPI(&out),
|
||||
node.Online(),
|
||||
node.Repo(repo.NewMemory(nil)),
|
||||
@@ -264,6 +263,7 @@ func (tu *syncTestUtil) addClientNode() int {
|
||||
node.Override(new(modules.Genesis), modules.LoadGenesis(tu.genesis)),
|
||||
)
|
||||
require.NoError(tu.t, err)
|
||||
tu.t.Cleanup(func() { _ = stop(context.Background()) })
|
||||
|
||||
tu.nds = append(tu.nds, out)
|
||||
return len(tu.nds) - 1
|
||||
@@ -593,7 +593,7 @@ func TestDuplicateNonce(t *testing.T) {
|
||||
GasPremium: types.NewInt(0),
|
||||
}
|
||||
|
||||
sig, err := tu.g.Wallet().Sign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes())
|
||||
sig, err := tu.g.Wallet().WalletSign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes(), api.MsgMeta{})
|
||||
require.NoError(t, err)
|
||||
|
||||
return &types.SignedMessage{
|
||||
@@ -685,7 +685,7 @@ func TestBadNonce(t *testing.T) {
|
||||
GasPremium: types.NewInt(0),
|
||||
}
|
||||
|
||||
sig, err := tu.g.Wallet().Sign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes())
|
||||
sig, err := tu.g.Wallet().WalletSign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes(), api.MsgMeta{})
|
||||
require.NoError(t, err)
|
||||
|
||||
return &types.SignedMessage{
|
||||
|
||||
+21
-25
@@ -11,8 +11,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
type SyncerState struct {
|
||||
lk sync.Mutex
|
||||
type SyncerStateSnapshot struct {
|
||||
Target *types.TipSet
|
||||
Base *types.TipSet
|
||||
Stage api.SyncStateStage
|
||||
@@ -22,6 +21,11 @@ type SyncerState struct {
|
||||
End time.Time
|
||||
}
|
||||
|
||||
type SyncerState struct {
|
||||
lk sync.Mutex
|
||||
data SyncerStateSnapshot
|
||||
}
|
||||
|
||||
func (ss *SyncerState) SetStage(v api.SyncStateStage) {
|
||||
if ss == nil {
|
||||
return
|
||||
@@ -29,9 +33,9 @@ func (ss *SyncerState) SetStage(v api.SyncStateStage) {
|
||||
|
||||
ss.lk.Lock()
|
||||
defer ss.lk.Unlock()
|
||||
ss.Stage = v
|
||||
ss.data.Stage = v
|
||||
if v == api.StageSyncComplete {
|
||||
ss.End = build.Clock.Now()
|
||||
ss.data.End = build.Clock.Now()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,13 +46,13 @@ func (ss *SyncerState) Init(base, target *types.TipSet) {
|
||||
|
||||
ss.lk.Lock()
|
||||
defer ss.lk.Unlock()
|
||||
ss.Target = target
|
||||
ss.Base = base
|
||||
ss.Stage = api.StageHeaders
|
||||
ss.Height = 0
|
||||
ss.Message = ""
|
||||
ss.Start = build.Clock.Now()
|
||||
ss.End = time.Time{}
|
||||
ss.data.Target = target
|
||||
ss.data.Base = base
|
||||
ss.data.Stage = api.StageHeaders
|
||||
ss.data.Height = 0
|
||||
ss.data.Message = ""
|
||||
ss.data.Start = build.Clock.Now()
|
||||
ss.data.End = time.Time{}
|
||||
}
|
||||
|
||||
func (ss *SyncerState) SetHeight(h abi.ChainEpoch) {
|
||||
@@ -58,7 +62,7 @@ func (ss *SyncerState) SetHeight(h abi.ChainEpoch) {
|
||||
|
||||
ss.lk.Lock()
|
||||
defer ss.lk.Unlock()
|
||||
ss.Height = h
|
||||
ss.data.Height = h
|
||||
}
|
||||
|
||||
func (ss *SyncerState) Error(err error) {
|
||||
@@ -68,21 +72,13 @@ func (ss *SyncerState) Error(err error) {
|
||||
|
||||
ss.lk.Lock()
|
||||
defer ss.lk.Unlock()
|
||||
ss.Message = err.Error()
|
||||
ss.Stage = api.StageSyncErrored
|
||||
ss.End = build.Clock.Now()
|
||||
ss.data.Message = err.Error()
|
||||
ss.data.Stage = api.StageSyncErrored
|
||||
ss.data.End = build.Clock.Now()
|
||||
}
|
||||
|
||||
func (ss *SyncerState) Snapshot() SyncerState {
|
||||
func (ss *SyncerState) Snapshot() SyncerStateSnapshot {
|
||||
ss.lk.Lock()
|
||||
defer ss.lk.Unlock()
|
||||
return SyncerState{
|
||||
Base: ss.Base,
|
||||
Target: ss.Target,
|
||||
Stage: ss.Stage,
|
||||
Height: ss.Height,
|
||||
Message: ss.Message,
|
||||
Start: ss.Start,
|
||||
End: ss.End,
|
||||
}
|
||||
return ss.data
|
||||
}
|
||||
|
||||
+15
-2
@@ -12,11 +12,15 @@ import (
|
||||
type FIL BigInt
|
||||
|
||||
func (f FIL) String() string {
|
||||
return f.Unitless() + " FIL"
|
||||
}
|
||||
|
||||
func (f FIL) Unitless() string {
|
||||
r := new(big.Rat).SetFrac(f.Int, big.NewInt(int64(build.FilecoinPrecision)))
|
||||
if r.Sign() == 0 {
|
||||
return "0 FIL"
|
||||
return "0"
|
||||
}
|
||||
return strings.TrimRight(strings.TrimRight(r.FloatString(18), "0"), ".") + " FIL"
|
||||
return strings.TrimRight(strings.TrimRight(r.FloatString(18), "0"), ".")
|
||||
}
|
||||
|
||||
func (f FIL) Format(s fmt.State, ch rune) {
|
||||
@@ -77,5 +81,14 @@ func ParseFIL(s string) (FIL, error) {
|
||||
return FIL{r.Num()}, nil
|
||||
}
|
||||
|
||||
func MustParseFIL(s string) FIL {
|
||||
n, err := ParseFIL(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
var _ encoding.TextMarshaler = (*FIL)(nil)
|
||||
var _ encoding.TextUnmarshaler = (*FIL)(nil)
|
||||
|
||||
+45
-1
@@ -1,7 +1,10 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -9,9 +12,50 @@ var (
|
||||
ErrKeyExists = fmt.Errorf("key already exists")
|
||||
)
|
||||
|
||||
// KeyType defines a type of a key
|
||||
type KeyType string
|
||||
|
||||
func (kt *KeyType) UnmarshalJSON(bb []byte) error {
|
||||
{
|
||||
// first option, try unmarshaling as string
|
||||
var s string
|
||||
err := json.Unmarshal(bb, &s)
|
||||
if err == nil {
|
||||
*kt = KeyType(s)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var b byte
|
||||
err := json.Unmarshal(bb, &b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not unmarshal KeyType either as string nor integer: %w", err)
|
||||
}
|
||||
bst := crypto.SigType(b)
|
||||
|
||||
switch bst {
|
||||
case crypto.SigTypeBLS:
|
||||
*kt = KTBLS
|
||||
case crypto.SigTypeSecp256k1:
|
||||
*kt = KTSecp256k1
|
||||
default:
|
||||
return fmt.Errorf("unknown sigtype: %d", bst)
|
||||
}
|
||||
log.Warnf("deprecation: integer style 'KeyType' is deprecated, switch to string style")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
KTBLS KeyType = "bls"
|
||||
KTSecp256k1 KeyType = "secp256k1"
|
||||
KTSecp256k1Ledger KeyType = "secp256k1-ledger"
|
||||
)
|
||||
|
||||
// KeyInfo is used for storing keys in KeyStore
|
||||
type KeyInfo struct {
|
||||
Type string
|
||||
Type KeyType
|
||||
PrivateKey []byte
|
||||
}
|
||||
|
||||
|
||||
+16
-1
@@ -2,6 +2,7 @@ package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
@@ -106,6 +107,20 @@ func (m *Message) Cid() cid.Cid {
|
||||
return b.Cid()
|
||||
}
|
||||
|
||||
type mCid struct {
|
||||
*RawMessage
|
||||
CID cid.Cid
|
||||
}
|
||||
|
||||
type RawMessage Message
|
||||
|
||||
func (m *Message) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(&mCid{
|
||||
RawMessage: (*RawMessage)(m),
|
||||
CID: m.Cid(),
|
||||
})
|
||||
}
|
||||
|
||||
func (m *Message) RequiredFunds() BigInt {
|
||||
return BigMul(m.GasFeeCap, NewInt(uint64(m.GasLimit)))
|
||||
}
|
||||
@@ -180,7 +195,7 @@ func (m *Message) ValidForBlockInclusion(minGas int64) error {
|
||||
|
||||
// since prices might vary with time, this is technically semantic validation
|
||||
if m.GasLimit < minGas {
|
||||
return xerrors.New("'GasLimit' field cannot be less than the cost of storing a message on chain")
|
||||
return xerrors.Errorf("'GasLimit' field cannot be less than the cost of storing a message on chain %d < %d", m.GasLimit, minGas)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
)
|
||||
|
||||
@@ -70,3 +73,66 @@ func TestEqualCall(t *testing.T) {
|
||||
require.True(t, m1.EqualCall(m3))
|
||||
require.False(t, m1.EqualCall(m4))
|
||||
}
|
||||
|
||||
func TestMessageJson(t *testing.T) {
|
||||
m := &Message{
|
||||
To: builtin.StoragePowerActorAddr,
|
||||
From: builtin.SystemActorAddr,
|
||||
Nonce: 34,
|
||||
Value: big.Zero(),
|
||||
|
||||
GasLimit: 123,
|
||||
GasFeeCap: big.NewInt(234),
|
||||
GasPremium: big.NewInt(234),
|
||||
|
||||
Method: 6,
|
||||
Params: []byte("hai"),
|
||||
}
|
||||
|
||||
b, err := json.Marshal(m)
|
||||
require.NoError(t, err)
|
||||
|
||||
exp := []byte("{\"Version\":0,\"To\":\"f04\",\"From\":\"f00\",\"Nonce\":34,\"Value\":\"0\",\"GasLimit\":123,\"GasFeeCap\":\"234\",\"GasPremium\":\"234\",\"Method\":6,\"Params\":\"aGFp\",\"CID\":{\"/\":\"bafy2bzaced5rdpz57e64sc7mdwjn3blicglhpialnrph2dlbufhf6iha63dmc\"}}")
|
||||
fmt.Println(string(b))
|
||||
|
||||
require.Equal(t, exp, b)
|
||||
|
||||
var um Message
|
||||
require.NoError(t, json.Unmarshal(b, &um))
|
||||
|
||||
require.EqualValues(t, *m, um)
|
||||
}
|
||||
|
||||
func TestSignedMessageJson(t *testing.T) {
|
||||
m := Message{
|
||||
To: builtin.StoragePowerActorAddr,
|
||||
From: builtin.SystemActorAddr,
|
||||
Nonce: 34,
|
||||
Value: big.Zero(),
|
||||
|
||||
GasLimit: 123,
|
||||
GasFeeCap: big.NewInt(234),
|
||||
GasPremium: big.NewInt(234),
|
||||
|
||||
Method: 6,
|
||||
Params: []byte("hai"),
|
||||
}
|
||||
|
||||
sm := &SignedMessage{
|
||||
Message: m,
|
||||
Signature: crypto.Signature{},
|
||||
}
|
||||
|
||||
b, err := json.Marshal(sm)
|
||||
require.NoError(t, err)
|
||||
|
||||
exp := []byte("{\"Message\":{\"Version\":0,\"To\":\"f04\",\"From\":\"f00\",\"Nonce\":34,\"Value\":\"0\",\"GasLimit\":123,\"GasFeeCap\":\"234\",\"GasPremium\":\"234\",\"Method\":6,\"Params\":\"aGFp\",\"CID\":{\"/\":\"bafy2bzaced5rdpz57e64sc7mdwjn3blicglhpialnrph2dlbufhf6iha63dmc\"}},\"Signature\":{\"Type\":0,\"Data\":null},\"CID\":{\"/\":\"bafy2bzacea5ainifngxj3rygaw2hppnyz2cw72x5pysqty2x6dxmjs5qg2uus\"}}")
|
||||
fmt.Println(string(b))
|
||||
|
||||
require.Equal(t, exp, b)
|
||||
|
||||
var um SignedMessage
|
||||
require.NoError(t, json.Unmarshal(b, &um))
|
||||
|
||||
require.EqualValues(t, *sm, um)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
@@ -22,7 +23,7 @@ func Address(i uint64) address.Address {
|
||||
return a
|
||||
}
|
||||
|
||||
func MkMessage(from, to address.Address, nonce uint64, w *wallet.Wallet) *types.SignedMessage {
|
||||
func MkMessage(from, to address.Address, nonce uint64, w *wallet.LocalWallet) *types.SignedMessage {
|
||||
msg := &types.Message{
|
||||
To: to,
|
||||
From: from,
|
||||
@@ -33,7 +34,7 @@ func MkMessage(from, to address.Address, nonce uint64, w *wallet.Wallet) *types.
|
||||
GasPremium: types.NewInt(1),
|
||||
}
|
||||
|
||||
sig, err := w.Sign(context.TODO(), from, msg.Cid().Bytes())
|
||||
sig, err := w.WalletSign(context.TODO(), from, msg.Cid().Bytes(), api.MsgMeta{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -59,9 +60,11 @@ func MkBlock(parents *types.TipSet, weightInc uint64, ticketNonce uint64) *types
|
||||
var pcids []cid.Cid
|
||||
var height abi.ChainEpoch
|
||||
weight := types.NewInt(weightInc)
|
||||
var timestamp uint64
|
||||
if parents != nil {
|
||||
pcids = parents.Cids()
|
||||
height = parents.Height() + 1
|
||||
timestamp = parents.MinTimestamp() + build.BlockDelaySecs
|
||||
weight = types.BigAdd(parents.Blocks()[0].ParentWeight, weight)
|
||||
}
|
||||
|
||||
@@ -79,6 +82,7 @@ func MkBlock(parents *types.TipSet, weightInc uint64, ticketNonce uint64) *types
|
||||
ParentWeight: weight,
|
||||
Messages: c,
|
||||
Height: height,
|
||||
Timestamp: timestamp,
|
||||
ParentStateRoot: pstateRoot,
|
||||
BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte("boo! im a signature")},
|
||||
ParentBaseFee: types.NewInt(uint64(build.MinimumBaseFee)),
|
||||
|
||||
@@ -2,6 +2,7 @@ package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
@@ -62,8 +63,29 @@ func (sm *SignedMessage) Serialize() ([]byte, error) {
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
type smCid struct {
|
||||
*RawSignedMessage
|
||||
CID cid.Cid
|
||||
}
|
||||
|
||||
type RawSignedMessage SignedMessage
|
||||
|
||||
func (sm *SignedMessage) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(&smCid{
|
||||
RawSignedMessage: (*RawSignedMessage)(sm),
|
||||
CID: sm.Cid(),
|
||||
})
|
||||
}
|
||||
|
||||
func (sm *SignedMessage) ChainLength() int {
|
||||
ser, err := sm.Serialize()
|
||||
var ser []byte
|
||||
var err error
|
||||
if sm.Signature.Type == crypto.SigTypeBLS {
|
||||
// BLS chain message length doesn't include signature
|
||||
ser, err = sm.Message.Serialize()
|
||||
} else {
|
||||
ser, err = sm.Serialize()
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
@@ -10,7 +11,6 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@@ -61,11 +61,11 @@ func MakeMessageSigningVectors() []vectors.MessageSigningVector {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
blsk, err := w.GenerateKey(crypto.SigTypeBLS)
|
||||
blsk, err := w.WalletNew(context.Background(), types.KTBLS)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
bki, err := w.Export(blsk)
|
||||
bki, err := w.WalletExport(context.Background(), blsk)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -85,11 +85,11 @@ func MakeMessageSigningVectors() []vectors.MessageSigningVector {
|
||||
Signature: &bmsg.Signature,
|
||||
}
|
||||
|
||||
secpk, err := w.GenerateKey(crypto.SigTypeBLS)
|
||||
secpk, err := w.WalletNew(context.Background(), types.KTBLS)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ski, err := w.Export(secpk)
|
||||
ski, err := w.WalletExport(context.Background(), secpk)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package wallet
|
||||
|
||||
import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
)
|
||||
|
||||
func GenerateKey(typ types.KeyType) (*Key, error) {
|
||||
ctyp := ActSigType(typ)
|
||||
if ctyp == crypto.SigTypeUnknown {
|
||||
return nil, xerrors.Errorf("unknown sig type: %s", typ)
|
||||
}
|
||||
pk, err := sigs.Generate(ctyp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ki := types.KeyInfo{
|
||||
Type: typ,
|
||||
PrivateKey: pk,
|
||||
}
|
||||
return NewKey(ki)
|
||||
}
|
||||
|
||||
type Key struct {
|
||||
types.KeyInfo
|
||||
|
||||
PublicKey []byte
|
||||
Address address.Address
|
||||
}
|
||||
|
||||
func NewKey(keyinfo types.KeyInfo) (*Key, error) {
|
||||
k := &Key{
|
||||
KeyInfo: keyinfo,
|
||||
}
|
||||
|
||||
var err error
|
||||
k.PublicKey, err = sigs.ToPublic(ActSigType(k.Type), k.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch k.Type {
|
||||
case types.KTSecp256k1:
|
||||
k.Address, err = address.NewSecp256k1Address(k.PublicKey)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("converting Secp256k1 to address: %w", err)
|
||||
}
|
||||
case types.KTBLS:
|
||||
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("unsupported key type: %s", k.Type)
|
||||
}
|
||||
return k, nil
|
||||
|
||||
}
|
||||
|
||||
func ActSigType(typ types.KeyType) crypto.SigType {
|
||||
switch typ {
|
||||
case types.KTBLS:
|
||||
return crypto.SigTypeBLS
|
||||
case types.KTSecp256k1:
|
||||
return crypto.SigTypeSecp256k1
|
||||
default:
|
||||
return crypto.SigTypeUnknown
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
package ledgerwallet
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
"github.com/ipfs/go-datastore/query"
|
||||
logging "github.com/ipfs/go-log"
|
||||
ledgerfil "github.com/whyrusleeping/ledger-filecoin-go"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
)
|
||||
|
||||
var log = logging.Logger("wallet-ledger")
|
||||
|
||||
type LedgerWallet struct {
|
||||
ds datastore.Datastore
|
||||
}
|
||||
|
||||
func NewWallet(ds dtypes.MetadataDS) *LedgerWallet {
|
||||
return &LedgerWallet{ds}
|
||||
}
|
||||
|
||||
type LedgerKeyInfo struct {
|
||||
Address address.Address
|
||||
Path []uint32
|
||||
}
|
||||
|
||||
var _ api.WalletAPI = (*LedgerWallet)(nil)
|
||||
|
||||
func (lw LedgerWallet) WalletSign(ctx context.Context, signer address.Address, toSign []byte, meta api.MsgMeta) (*crypto.Signature, error) {
|
||||
ki, err := lw.getKeyInfo(signer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fl, err := ledgerfil.FindLedgerFilecoinApp()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fl.Close() // nolint:errcheck
|
||||
if meta.Type != api.MTChainMsg {
|
||||
return nil, fmt.Errorf("ledger can only sign chain messages")
|
||||
}
|
||||
|
||||
{
|
||||
var cmsg types.Message
|
||||
if err := cmsg.UnmarshalCBOR(bytes.NewReader(meta.Extra)); err != nil {
|
||||
return nil, xerrors.Errorf("unmarshalling message: %w", err)
|
||||
}
|
||||
|
||||
_, bc, err := cid.CidFromBytes(toSign)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting cid from signing bytes: %w", err)
|
||||
}
|
||||
|
||||
if !cmsg.Cid().Equals(bc) {
|
||||
return nil, xerrors.Errorf("cid(meta.Extra).bytes() != toSign")
|
||||
}
|
||||
}
|
||||
|
||||
sig, err := fl.SignSECP256K1(ki.Path, meta.Extra)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &crypto.Signature{
|
||||
Type: crypto.SigTypeSecp256k1,
|
||||
Data: sig.SignatureBytes(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (lw LedgerWallet) getKeyInfo(addr address.Address) (*LedgerKeyInfo, error) {
|
||||
kib, err := lw.ds.Get(keyForAddr(addr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var out LedgerKeyInfo
|
||||
if err := json.Unmarshal(kib, &out); err != nil {
|
||||
return nil, xerrors.Errorf("unmarshalling ledger key info: %w", err)
|
||||
}
|
||||
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
func (lw LedgerWallet) WalletDelete(ctx context.Context, k address.Address) error {
|
||||
return lw.ds.Delete(keyForAddr(k))
|
||||
}
|
||||
|
||||
func (lw LedgerWallet) WalletExport(ctx context.Context, k address.Address) (*types.KeyInfo, error) {
|
||||
return nil, fmt.Errorf("cannot export keys from ledger wallets")
|
||||
}
|
||||
|
||||
func (lw LedgerWallet) WalletHas(ctx context.Context, k address.Address) (bool, error) {
|
||||
_, err := lw.ds.Get(keyForAddr(k))
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if err == datastore.ErrNotFound {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (lw LedgerWallet) WalletImport(ctx context.Context, kinfo *types.KeyInfo) (address.Address, error) {
|
||||
var ki LedgerKeyInfo
|
||||
if err := json.Unmarshal(kinfo.PrivateKey, &ki); err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
return lw.importKey(ki)
|
||||
}
|
||||
|
||||
func (lw LedgerWallet) importKey(ki LedgerKeyInfo) (address.Address, error) {
|
||||
if ki.Address == address.Undef {
|
||||
return address.Undef, fmt.Errorf("no address given in imported key info")
|
||||
}
|
||||
if len(ki.Path) != filHdPathLen {
|
||||
return address.Undef, fmt.Errorf("bad hd path len: %d, expected: %d", len(ki.Path), filHdPathLen)
|
||||
}
|
||||
bb, err := json.Marshal(ki)
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("marshaling key info: %w", err)
|
||||
}
|
||||
|
||||
if err := lw.ds.Put(keyForAddr(ki.Address), bb); err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
return ki.Address, nil
|
||||
}
|
||||
|
||||
func (lw LedgerWallet) WalletList(ctx context.Context) ([]address.Address, error) {
|
||||
res, err := lw.ds.Query(query.Query{Prefix: dsLedgerPrefix})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Close() // nolint:errcheck
|
||||
|
||||
var out []address.Address
|
||||
for {
|
||||
res, ok := res.NextSync()
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
var ki LedgerKeyInfo
|
||||
if err := json.Unmarshal(res.Value, &ki); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out = append(out, ki.Address)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
const hdHard = 0x80000000
|
||||
|
||||
var filHDBasePath = []uint32{hdHard | 44, hdHard | 461, hdHard, 0}
|
||||
var filHdPathLen = 5
|
||||
|
||||
func (lw LedgerWallet) WalletNew(ctx context.Context, t types.KeyType) (address.Address, error) {
|
||||
if t != types.KTSecp256k1Ledger {
|
||||
return address.Undef, fmt.Errorf("unsupported key type: '%s', only '%s' supported",
|
||||
t, types.KTSecp256k1Ledger)
|
||||
}
|
||||
|
||||
res, err := lw.ds.Query(query.Query{Prefix: dsLedgerPrefix})
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
defer res.Close() // nolint:errcheck
|
||||
|
||||
var maxi int64 = -1
|
||||
for {
|
||||
res, ok := res.NextSync()
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
var ki LedgerKeyInfo
|
||||
if err := json.Unmarshal(res.Value, &ki); err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
if i := ki.Path[filHdPathLen-1]; maxi == -1 || maxi < int64(i) {
|
||||
maxi = int64(i)
|
||||
}
|
||||
}
|
||||
|
||||
fl, err := ledgerfil.FindLedgerFilecoinApp()
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("finding ledger: %w", err)
|
||||
}
|
||||
defer fl.Close() // nolint:errcheck
|
||||
|
||||
path := append(append([]uint32(nil), filHDBasePath...), uint32(maxi+1))
|
||||
_, _, addr, err := fl.GetAddressPubKeySECP256K1(path)
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("getting public key from ledger: %w", err)
|
||||
}
|
||||
|
||||
log.Warnf("creating key: %s, accept the key in ledger device", addr)
|
||||
_, _, addr, err = fl.ShowAddressPubKeySECP256K1(path)
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("verifying public key with ledger: %w", err)
|
||||
}
|
||||
|
||||
a, err := address.NewFromString(addr)
|
||||
if err != nil {
|
||||
return address.Undef, fmt.Errorf("parsing address: %w", err)
|
||||
}
|
||||
|
||||
var lki LedgerKeyInfo
|
||||
lki.Address = a
|
||||
lki.Path = path
|
||||
|
||||
return lw.importKey(lki)
|
||||
}
|
||||
|
||||
func (lw *LedgerWallet) Get() api.WalletAPI {
|
||||
if lw == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return lw
|
||||
}
|
||||
|
||||
var dsLedgerPrefix = "/ledgerkey/"
|
||||
|
||||
func keyForAddr(addr address.Address) datastore.Key {
|
||||
return datastore.NewKey(dsLedgerPrefix + addr.String())
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package wallet
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.uber.org/fx"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
ledgerwallet "github.com/filecoin-project/lotus/chain/wallet/ledger"
|
||||
"github.com/filecoin-project/lotus/chain/wallet/remotewallet"
|
||||
)
|
||||
|
||||
type MultiWallet struct {
|
||||
fx.In // "constructed" with fx.In instead of normal constructor
|
||||
|
||||
Local *LocalWallet `optional:"true"`
|
||||
Remote *remotewallet.RemoteWallet `optional:"true"`
|
||||
Ledger *ledgerwallet.LedgerWallet `optional:"true"`
|
||||
}
|
||||
|
||||
type getif interface {
|
||||
api.WalletAPI
|
||||
|
||||
// workaround for the fact that iface(*struct(nil)) != nil
|
||||
Get() api.WalletAPI
|
||||
}
|
||||
|
||||
func firstNonNil(wallets ...getif) api.WalletAPI {
|
||||
for _, w := range wallets {
|
||||
if w.Get() != nil {
|
||||
return w
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func nonNil(wallets ...getif) []api.WalletAPI {
|
||||
var out []api.WalletAPI
|
||||
for _, w := range wallets {
|
||||
if w.Get() == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
out = append(out, w)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func (m MultiWallet) find(ctx context.Context, address address.Address, wallets ...getif) (api.WalletAPI, error) {
|
||||
ws := nonNil(wallets...)
|
||||
|
||||
for _, w := range ws {
|
||||
have, err := w.WalletHas(ctx, address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if have {
|
||||
return w, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m MultiWallet) WalletNew(ctx context.Context, keyType types.KeyType) (address.Address, error) {
|
||||
var local getif = m.Local
|
||||
if keyType == types.KTSecp256k1Ledger {
|
||||
local = m.Ledger
|
||||
}
|
||||
|
||||
w := firstNonNil(m.Remote, local)
|
||||
if w == nil {
|
||||
return address.Undef, xerrors.Errorf("no wallet backends supporting key type: %s", keyType)
|
||||
}
|
||||
|
||||
return w.WalletNew(ctx, keyType)
|
||||
}
|
||||
|
||||
func (m MultiWallet) WalletHas(ctx context.Context, address address.Address) (bool, error) {
|
||||
w, err := m.find(ctx, address, m.Remote, m.Ledger, m.Local)
|
||||
return w != nil, err
|
||||
}
|
||||
|
||||
func (m MultiWallet) WalletList(ctx context.Context) ([]address.Address, error) {
|
||||
var out []address.Address
|
||||
seen := map[address.Address]struct{}{}
|
||||
|
||||
ws := nonNil(m.Remote, m.Ledger, m.Local)
|
||||
for _, w := range ws {
|
||||
l, err := w.WalletList(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, a := range l {
|
||||
if _, ok := seen[a]; ok {
|
||||
continue
|
||||
}
|
||||
seen[a] = struct{}{}
|
||||
|
||||
out = append(out, a)
|
||||
}
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (m MultiWallet) WalletSign(ctx context.Context, signer address.Address, toSign []byte, meta api.MsgMeta) (*crypto.Signature, error) {
|
||||
w, err := m.find(ctx, signer, m.Remote, m.Ledger, m.Local)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if w == nil {
|
||||
return nil, xerrors.Errorf("key not found")
|
||||
}
|
||||
|
||||
return w.WalletSign(ctx, signer, toSign, meta)
|
||||
}
|
||||
|
||||
func (m MultiWallet) WalletExport(ctx context.Context, address address.Address) (*types.KeyInfo, error) {
|
||||
w, err := m.find(ctx, address, m.Remote, m.Local)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if w == nil {
|
||||
return nil, xerrors.Errorf("key not found")
|
||||
}
|
||||
|
||||
return w.WalletExport(ctx, address)
|
||||
}
|
||||
|
||||
func (m MultiWallet) WalletImport(ctx context.Context, info *types.KeyInfo) (address.Address, error) {
|
||||
var local getif = m.Local
|
||||
if info.Type == types.KTSecp256k1Ledger {
|
||||
local = m.Ledger
|
||||
}
|
||||
|
||||
w := firstNonNil(m.Remote, local)
|
||||
if w == nil {
|
||||
return address.Undef, xerrors.Errorf("no wallet backends configured")
|
||||
}
|
||||
|
||||
return w.WalletImport(ctx, info)
|
||||
}
|
||||
|
||||
func (m MultiWallet) WalletDelete(ctx context.Context, address address.Address) error {
|
||||
for {
|
||||
w, err := m.find(ctx, address, m.Remote, m.Ledger, m.Local)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if w == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := w.WalletDelete(ctx, address); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var _ api.WalletAPI = MultiWallet{}
|
||||
@@ -0,0 +1,50 @@
|
||||
package remotewallet
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.uber.org/fx"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/api/client"
|
||||
cliutil "github.com/filecoin-project/lotus/cli/util"
|
||||
"github.com/filecoin-project/lotus/node/modules/helpers"
|
||||
)
|
||||
|
||||
type RemoteWallet struct {
|
||||
api.WalletAPI
|
||||
}
|
||||
|
||||
func SetupRemoteWallet(info string) func(mctx helpers.MetricsCtx, lc fx.Lifecycle) (*RemoteWallet, error) {
|
||||
return func(mctx helpers.MetricsCtx, lc fx.Lifecycle) (*RemoteWallet, error) {
|
||||
ai := cliutil.ParseApiInfo(info)
|
||||
|
||||
url, err := ai.DialArgs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wapi, closer, err := client.NewWalletRPC(mctx, url, ai.AuthHeader())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("creating jsonrpc client: %w", err)
|
||||
}
|
||||
|
||||
lc.Append(fx.Hook{
|
||||
OnStop: func(ctx context.Context) error {
|
||||
closer()
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
return &RemoteWallet{wapi}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (w *RemoteWallet) Get() api.WalletAPI {
|
||||
if w == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return w
|
||||
}
|
||||
+63
-83
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls" // enable bls signatures
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp" // enable secp signatures
|
||||
|
||||
@@ -25,19 +26,22 @@ const (
|
||||
KNamePrefix = "wallet-"
|
||||
KTrashPrefix = "trash-"
|
||||
KDefault = "default"
|
||||
KTBLS = "bls"
|
||||
KTSecp256k1 = "secp256k1"
|
||||
)
|
||||
|
||||
type Wallet struct {
|
||||
type LocalWallet struct {
|
||||
keys map[address.Address]*Key
|
||||
keystore types.KeyStore
|
||||
|
||||
lk sync.Mutex
|
||||
}
|
||||
|
||||
func NewWallet(keystore types.KeyStore) (*Wallet, error) {
|
||||
w := &Wallet{
|
||||
type Default interface {
|
||||
GetDefault() (address.Address, error)
|
||||
SetDefault(a address.Address) error
|
||||
}
|
||||
|
||||
func NewWallet(keystore types.KeyStore) (*LocalWallet, error) {
|
||||
w := &LocalWallet{
|
||||
keys: make(map[address.Address]*Key),
|
||||
keystore: keystore,
|
||||
}
|
||||
@@ -45,18 +49,18 @@ func NewWallet(keystore types.KeyStore) (*Wallet, error) {
|
||||
return w, nil
|
||||
}
|
||||
|
||||
func KeyWallet(keys ...*Key) *Wallet {
|
||||
func KeyWallet(keys ...*Key) *LocalWallet {
|
||||
m := make(map[address.Address]*Key)
|
||||
for _, key := range keys {
|
||||
m[key.Address] = key
|
||||
}
|
||||
|
||||
return &Wallet{
|
||||
return &LocalWallet{
|
||||
keys: m,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Wallet) Sign(ctx context.Context, addr address.Address, msg []byte) (*crypto.Signature, error) {
|
||||
func (w *LocalWallet) WalletSign(ctx context.Context, addr address.Address, msg []byte, meta api.MsgMeta) (*crypto.Signature, error) {
|
||||
ki, err := w.findKey(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -68,7 +72,7 @@ func (w *Wallet) Sign(ctx context.Context, addr address.Address, msg []byte) (*c
|
||||
return sigs.Sign(ActSigType(ki.Type), ki.PrivateKey, msg)
|
||||
}
|
||||
|
||||
func (w *Wallet) findKey(addr address.Address) (*Key, error) {
|
||||
func (w *LocalWallet) findKey(addr address.Address) (*Key, error) {
|
||||
w.lk.Lock()
|
||||
defer w.lk.Unlock()
|
||||
|
||||
@@ -96,7 +100,7 @@ func (w *Wallet) findKey(addr address.Address) (*Key, error) {
|
||||
return k, nil
|
||||
}
|
||||
|
||||
func (w *Wallet) tryFind(addr address.Address) (types.KeyInfo, error) {
|
||||
func (w *LocalWallet) tryFind(addr address.Address) (types.KeyInfo, error) {
|
||||
|
||||
ki, err := w.keystore.Get(KNamePrefix + addr.String())
|
||||
if err == nil {
|
||||
@@ -110,14 +114,12 @@ func (w *Wallet) tryFind(addr address.Address) (types.KeyInfo, error) {
|
||||
// We got an ErrKeyInfoNotFound error
|
||||
// Try again, this time with the testnet prefix
|
||||
|
||||
aChars := []rune(addr.String())
|
||||
prefixRunes := []rune(address.TestnetPrefix)
|
||||
if len(prefixRunes) != 1 {
|
||||
return types.KeyInfo{}, xerrors.Errorf("unexpected prefix length: %d", len(prefixRunes))
|
||||
tAddress, err := swapMainnetForTestnetPrefix(addr.String())
|
||||
if err != nil {
|
||||
return types.KeyInfo{}, err
|
||||
}
|
||||
|
||||
aChars[0] = prefixRunes[0]
|
||||
ki, err = w.keystore.Get(KNamePrefix + string(aChars))
|
||||
ki, err = w.keystore.Get(KNamePrefix + tAddress)
|
||||
if err != nil {
|
||||
return types.KeyInfo{}, err
|
||||
}
|
||||
@@ -132,16 +134,19 @@ func (w *Wallet) tryFind(addr address.Address) (types.KeyInfo, error) {
|
||||
return ki, nil
|
||||
}
|
||||
|
||||
func (w *Wallet) Export(addr address.Address) (*types.KeyInfo, error) {
|
||||
func (w *LocalWallet) WalletExport(ctx context.Context, addr address.Address) (*types.KeyInfo, error) {
|
||||
k, err := w.findKey(addr)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to find key to export: %w", err)
|
||||
}
|
||||
if k == nil {
|
||||
return nil, xerrors.Errorf("key not found")
|
||||
}
|
||||
|
||||
return &k.KeyInfo, nil
|
||||
}
|
||||
|
||||
func (w *Wallet) Import(ki *types.KeyInfo) (address.Address, error) {
|
||||
func (w *LocalWallet) WalletImport(ctx context.Context, ki *types.KeyInfo) (address.Address, error) {
|
||||
w.lk.Lock()
|
||||
defer w.lk.Unlock()
|
||||
|
||||
@@ -157,7 +162,7 @@ func (w *Wallet) Import(ki *types.KeyInfo) (address.Address, error) {
|
||||
return k.Address, nil
|
||||
}
|
||||
|
||||
func (w *Wallet) ListAddrs() ([]address.Address, error) {
|
||||
func (w *LocalWallet) WalletList(ctx context.Context) ([]address.Address, error) {
|
||||
all, err := w.keystore.List()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("listing keystore: %w", err)
|
||||
@@ -190,7 +195,7 @@ func (w *Wallet) ListAddrs() ([]address.Address, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (w *Wallet) GetDefault() (address.Address, error) {
|
||||
func (w *LocalWallet) GetDefault() (address.Address, error) {
|
||||
w.lk.Lock()
|
||||
defer w.lk.Unlock()
|
||||
|
||||
@@ -207,7 +212,7 @@ func (w *Wallet) GetDefault() (address.Address, error) {
|
||||
return k.Address, nil
|
||||
}
|
||||
|
||||
func (w *Wallet) SetDefault(a address.Address) error {
|
||||
func (w *LocalWallet) SetDefault(a address.Address) error {
|
||||
w.lk.Lock()
|
||||
defer w.lk.Unlock()
|
||||
|
||||
@@ -229,19 +234,7 @@ func (w *Wallet) SetDefault(a address.Address) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GenerateKey(typ crypto.SigType) (*Key, error) {
|
||||
pk, err := sigs.Generate(typ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ki := types.KeyInfo{
|
||||
Type: kstoreSigType(typ),
|
||||
PrivateKey: pk,
|
||||
}
|
||||
return NewKey(ki)
|
||||
}
|
||||
|
||||
func (w *Wallet) GenerateKey(typ crypto.SigType) (address.Address, error) {
|
||||
func (w *LocalWallet) WalletNew(ctx context.Context, typ types.KeyType) (address.Address, error) {
|
||||
w.lk.Lock()
|
||||
defer w.lk.Unlock()
|
||||
|
||||
@@ -269,7 +262,7 @@ func (w *Wallet) GenerateKey(typ crypto.SigType) (address.Address, error) {
|
||||
return k.Address, nil
|
||||
}
|
||||
|
||||
func (w *Wallet) HasKey(addr address.Address) (bool, error) {
|
||||
func (w *LocalWallet) WalletHas(ctx context.Context, addr address.Address) (bool, error) {
|
||||
k, err := w.findKey(addr)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -277,11 +270,14 @@ func (w *Wallet) HasKey(addr address.Address) (bool, error) {
|
||||
return k != nil, nil
|
||||
}
|
||||
|
||||
func (w *Wallet) DeleteKey(addr address.Address) error {
|
||||
func (w *LocalWallet) WalletDelete(ctx context.Context, addr address.Address) error {
|
||||
k, err := w.findKey(addr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to delete key %s : %w", addr, err)
|
||||
}
|
||||
if k == nil {
|
||||
return nil // already not there
|
||||
}
|
||||
|
||||
if err := w.keystore.Put(KTrashPrefix+k.Address.String(), k.KeyInfo); err != nil {
|
||||
return xerrors.Errorf("failed to mark key %s as trashed: %w", addr, err)
|
||||
@@ -291,63 +287,47 @@ func (w *Wallet) DeleteKey(addr address.Address) error {
|
||||
return xerrors.Errorf("failed to delete key %s: %w", addr, err)
|
||||
}
|
||||
|
||||
tAddr, err := swapMainnetForTestnetPrefix(addr.String())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to swap prefixes: %w", err)
|
||||
}
|
||||
|
||||
// TODO: Does this always error in the not-found case? Just ignoring an error return for now.
|
||||
_ = w.keystore.Delete(KNamePrefix + tAddr)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type Key struct {
|
||||
types.KeyInfo
|
||||
func (w *LocalWallet) Get() api.WalletAPI {
|
||||
if w == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
PublicKey []byte
|
||||
Address address.Address
|
||||
return w
|
||||
}
|
||||
|
||||
func NewKey(keyinfo types.KeyInfo) (*Key, error) {
|
||||
k := &Key{
|
||||
KeyInfo: keyinfo,
|
||||
var _ api.WalletAPI = &LocalWallet{}
|
||||
|
||||
func swapMainnetForTestnetPrefix(addr string) (string, error) {
|
||||
aChars := []rune(addr)
|
||||
prefixRunes := []rune(address.TestnetPrefix)
|
||||
if len(prefixRunes) != 1 {
|
||||
return "", xerrors.Errorf("unexpected prefix length: %d", len(prefixRunes))
|
||||
}
|
||||
|
||||
var err error
|
||||
k.PublicKey, err = sigs.ToPublic(ActSigType(k.Type), k.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch k.Type {
|
||||
case KTSecp256k1:
|
||||
k.Address, err = address.NewSecp256k1Address(k.PublicKey)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("converting Secp256k1 to address: %w", err)
|
||||
}
|
||||
case KTBLS:
|
||||
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")
|
||||
}
|
||||
return k, nil
|
||||
|
||||
aChars[0] = prefixRunes[0]
|
||||
return string(aChars), nil
|
||||
}
|
||||
|
||||
func kstoreSigType(typ crypto.SigType) string {
|
||||
switch typ {
|
||||
case crypto.SigTypeBLS:
|
||||
return KTBLS
|
||||
case crypto.SigTypeSecp256k1:
|
||||
return KTSecp256k1
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
type nilDefault struct{}
|
||||
|
||||
func (n nilDefault) GetDefault() (address.Address, error) {
|
||||
return address.Undef, nil
|
||||
}
|
||||
|
||||
func ActSigType(typ string) crypto.SigType {
|
||||
switch typ {
|
||||
case KTBLS:
|
||||
return crypto.SigTypeBLS
|
||||
case KTSecp256k1:
|
||||
return crypto.SigTypeSecp256k1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
func (n nilDefault) SetDefault(a address.Address) error {
|
||||
return xerrors.Errorf("not supported; local wallet disabled")
|
||||
}
|
||||
|
||||
var NilDefault nilDefault
|
||||
var _ Default = NilDefault
|
||||
|
||||
+79
-6
@@ -3,6 +3,7 @@ package cli
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -53,6 +54,7 @@ var chainCmd = &cli.Command{
|
||||
slashConsensusFault,
|
||||
chainGasPriceCmd,
|
||||
chainInspectUsage,
|
||||
chainDecodeCmd,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -449,11 +451,16 @@ var chainInspectUsage = &cli.Command{
|
||||
bySender := make(map[string]int64)
|
||||
byDest := make(map[string]int64)
|
||||
byMethod := make(map[string]int64)
|
||||
bySenderC := make(map[string]int64)
|
||||
byDestC := make(map[string]int64)
|
||||
byMethodC := make(map[string]int64)
|
||||
|
||||
var sum int64
|
||||
for _, m := range msgs {
|
||||
bySender[m.Message.From.String()] += m.Message.GasLimit
|
||||
bySenderC[m.Message.From.String()]++
|
||||
byDest[m.Message.To.String()] += m.Message.GasLimit
|
||||
byDestC[m.Message.To.String()]++
|
||||
sum += m.Message.GasLimit
|
||||
|
||||
code, err := lookupActorCode(m.Message.To)
|
||||
@@ -464,7 +471,7 @@ var chainInspectUsage = &cli.Command{
|
||||
mm := stmgr.MethodsMap[code][m.Message.Method]
|
||||
|
||||
byMethod[mm.Name] += m.Message.GasLimit
|
||||
|
||||
byMethodC[mm.Name]++
|
||||
}
|
||||
|
||||
type keyGasPair struct {
|
||||
@@ -496,19 +503,19 @@ var chainInspectUsage = &cli.Command{
|
||||
fmt.Printf("By Sender:\n")
|
||||
for i := 0; i < numRes && i < len(senderVals); i++ {
|
||||
sv := senderVals[i]
|
||||
fmt.Printf("%s\t%0.2f%%\t(%d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas)
|
||||
fmt.Printf("%s\t%0.2f%%\t(total: %d, count: %d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas, bySenderC[sv.Key])
|
||||
}
|
||||
fmt.Println()
|
||||
fmt.Printf("By Receiver:\n")
|
||||
for i := 0; i < numRes && i < len(destVals); i++ {
|
||||
sv := destVals[i]
|
||||
fmt.Printf("%s\t%0.2f%%\t(%d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas)
|
||||
fmt.Printf("%s\t%0.2f%%\t(total: %d, count: %d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas, byDestC[sv.Key])
|
||||
}
|
||||
fmt.Println()
|
||||
fmt.Printf("By Method:\n")
|
||||
for i := 0; i < numRes && i < len(methodVals); i++ {
|
||||
sv := methodVals[i]
|
||||
fmt.Printf("%s\t%0.2f%%\t(%d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas)
|
||||
fmt.Printf("%s\t%0.2f%%\t(total: %d, count: %d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas, byMethodC[sv.Key])
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -516,8 +523,9 @@ var chainInspectUsage = &cli.Command{
|
||||
}
|
||||
|
||||
var chainListCmd = &cli.Command{
|
||||
Name: "list",
|
||||
Usage: "View a segment of the chain",
|
||||
Name: "list",
|
||||
Aliases: []string{"love"},
|
||||
Usage: "View a segment of the chain",
|
||||
Flags: []cli.Flag{
|
||||
&cli.Uint64Flag{Name: "height"},
|
||||
&cli.IntFlag{Name: "count", Value: 30},
|
||||
@@ -1228,3 +1236,68 @@ var chainGasPriceCmd = &cli.Command{
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var chainDecodeCmd = &cli.Command{
|
||||
Name: "decode",
|
||||
Usage: "decode various types",
|
||||
Subcommands: []*cli.Command{
|
||||
chainDecodeParamsCmd,
|
||||
},
|
||||
}
|
||||
|
||||
var chainDecodeParamsCmd = &cli.Command{
|
||||
Name: "params",
|
||||
Usage: "Decode message params",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "tipset",
|
||||
},
|
||||
},
|
||||
ArgsUsage: "[toAddr method hexParams]",
|
||||
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 ShowHelp(cctx, fmt.Errorf("incorrect number of arguments"))
|
||||
}
|
||||
|
||||
to, err := address.NewFromString(cctx.Args().First())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing toAddr: %w", err)
|
||||
}
|
||||
|
||||
method, err := strconv.ParseInt(cctx.Args().Get(1), 10, 64)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing method id: %w", err)
|
||||
}
|
||||
|
||||
params, err := hex.DecodeString(cctx.Args().Get(2))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing hex params: %w", err)
|
||||
}
|
||||
|
||||
ts, err := LoadTipSet(ctx, cctx, api)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
act, err := api.StateGetActor(ctx, to, ts.Key())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting actor: %w", err)
|
||||
}
|
||||
|
||||
pstr, err := jsonParams(act.Code, abi.MethodNum(method), params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(pstr)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
+78
-7
@@ -3,6 +3,7 @@ package cli
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -82,6 +83,7 @@ var clientCmd = &cli.Command{
|
||||
WithCategory("util", clientCarGenCmd),
|
||||
WithCategory("util", clientInfoCmd),
|
||||
WithCategory("util", clientListTransfers),
|
||||
WithCategory("util", clientRestartTransfer),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -536,7 +538,7 @@ func interactiveDeal(cctx *cli.Context) error {
|
||||
|
||||
state = "miner"
|
||||
case "miner":
|
||||
fmt.Print("Miner Address (t0..): ")
|
||||
fmt.Print("Miner Address (f0..): ")
|
||||
var maddrStr string
|
||||
|
||||
_, err := fmt.Scan(&maddrStr)
|
||||
@@ -1039,6 +1041,10 @@ var clientListDeals = &cli.Command{
|
||||
Usage: "use color in display output",
|
||||
Value: true,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "show-failed",
|
||||
Usage: "show failed/failing deals",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "watch",
|
||||
Usage: "watch deal updates in real-time, rather than a one time list",
|
||||
@@ -1055,6 +1061,7 @@ var clientListDeals = &cli.Command{
|
||||
verbose := cctx.Bool("verbose")
|
||||
color := cctx.Bool("color")
|
||||
watch := cctx.Bool("watch")
|
||||
showFailed := cctx.Bool("show-failed")
|
||||
|
||||
localDeals, err := api.ClientListDeals(ctx)
|
||||
if err != nil {
|
||||
@@ -1071,7 +1078,7 @@ var clientListDeals = &cli.Command{
|
||||
tm.Clear()
|
||||
tm.MoveCursor(1, 1)
|
||||
|
||||
err = outputStorageDeals(ctx, tm.Screen, api, localDeals, verbose, color)
|
||||
err = outputStorageDeals(ctx, tm.Screen, api, localDeals, verbose, color, showFailed)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1097,7 +1104,7 @@ var clientListDeals = &cli.Command{
|
||||
}
|
||||
}
|
||||
|
||||
return outputStorageDeals(ctx, os.Stdout, api, localDeals, cctx.Bool("verbose"), cctx.Bool("color"))
|
||||
return outputStorageDeals(ctx, os.Stdout, api, localDeals, cctx.Bool("verbose"), cctx.Bool("color"), showFailed)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1120,7 +1127,7 @@ func dealFromDealInfo(ctx context.Context, full api.FullNode, head *types.TipSet
|
||||
}
|
||||
}
|
||||
|
||||
func outputStorageDeals(ctx context.Context, out io.Writer, full api.FullNode, localDeals []api.DealInfo, verbose bool, color bool) error {
|
||||
func outputStorageDeals(ctx context.Context, out io.Writer, full lapi.FullNode, localDeals []lapi.DealInfo, verbose bool, color bool, showFailed bool) error {
|
||||
sort.Slice(localDeals, func(i, j int) bool {
|
||||
return localDeals[i].CreationTime.Before(localDeals[j].CreationTime)
|
||||
})
|
||||
@@ -1132,12 +1139,14 @@ func outputStorageDeals(ctx context.Context, out io.Writer, full api.FullNode, l
|
||||
|
||||
var deals []deal
|
||||
for _, localDeal := range localDeals {
|
||||
deals = append(deals, dealFromDealInfo(ctx, full, head, localDeal))
|
||||
if showFailed || localDeal.State != storagemarket.StorageDealError {
|
||||
deals = append(deals, dealFromDealInfo(ctx, full, head, localDeal))
|
||||
}
|
||||
}
|
||||
|
||||
if verbose {
|
||||
w := tabwriter.NewWriter(out, 2, 4, 2, ' ', 0)
|
||||
fmt.Fprintf(w, "Created\tDealCid\tDealId\tProvider\tState\tOn Chain?\tSlashed?\tPieceCID\tSize\tPrice\tDuration\tMessage\n")
|
||||
fmt.Fprintf(w, "Created\tDealCid\tDealId\tProvider\tState\tOn Chain?\tSlashed?\tPieceCID\tSize\tPrice\tDuration\tVerified\tMessage\n")
|
||||
for _, d := range deals {
|
||||
onChain := "N"
|
||||
if d.OnChainDealState.SectorStartEpoch != -1 {
|
||||
@@ -1150,7 +1159,7 @@ func outputStorageDeals(ctx context.Context, out io.Writer, full api.FullNode, l
|
||||
}
|
||||
|
||||
price := types.FIL(types.BigMul(d.LocalDeal.PricePerEpoch, types.NewInt(d.LocalDeal.Duration)))
|
||||
fmt.Fprintf(w, "%s\t%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%d\t%s\n", d.LocalDeal.CreationTime.Format(time.Stamp), d.LocalDeal.ProposalCid, d.LocalDeal.DealID, d.LocalDeal.Provider, dealStateString(color, d.LocalDeal.State), onChain, slashed, d.LocalDeal.PieceCID, types.SizeStr(types.NewInt(d.LocalDeal.Size)), price, d.LocalDeal.Duration, d.LocalDeal.Message)
|
||||
fmt.Fprintf(w, "%s\t%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%d\t%v\t%s\n", d.LocalDeal.CreationTime.Format(time.Stamp), d.LocalDeal.ProposalCid, d.LocalDeal.DealID, d.LocalDeal.Provider, dealStateString(color, d.LocalDeal.State), onChain, slashed, d.LocalDeal.PieceCID, types.SizeStr(types.NewInt(d.LocalDeal.Size)), price, d.LocalDeal.Duration, d.LocalDeal.Verified, d.LocalDeal.Message)
|
||||
}
|
||||
return w.Flush()
|
||||
}
|
||||
@@ -1165,6 +1174,7 @@ func outputStorageDeals(ctx context.Context, out io.Writer, full api.FullNode, l
|
||||
tablewriter.Col("Size"),
|
||||
tablewriter.Col("Price"),
|
||||
tablewriter.Col("Duration"),
|
||||
tablewriter.Col("Verified"),
|
||||
tablewriter.NewLineCol("Message"))
|
||||
|
||||
for _, d := range deals {
|
||||
@@ -1194,6 +1204,7 @@ func outputStorageDeals(ctx context.Context, out io.Writer, full api.FullNode, l
|
||||
"PieceCID": piece,
|
||||
"Size": types.SizeStr(types.NewInt(d.LocalDeal.Size)),
|
||||
"Price": price,
|
||||
"Verified": d.LocalDeal.Verified,
|
||||
"Duration": d.LocalDeal.Duration,
|
||||
"Message": d.LocalDeal.Message,
|
||||
})
|
||||
@@ -1317,6 +1328,66 @@ var clientInfoCmd = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var clientRestartTransfer = &cli.Command{
|
||||
Name: "restart-transfer",
|
||||
Usage: "Force restart a stalled data transfer",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "peerid",
|
||||
Usage: "narrow to transfer with specific peer",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "initiator",
|
||||
Usage: "specify only transfers where peer is/is not initiator",
|
||||
Value: true,
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
return cli.ShowCommandHelp(cctx, cctx.Command.Name)
|
||||
}
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
transferUint, err := strconv.ParseUint(cctx.Args().First(), 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error reading transfer ID: %w", err)
|
||||
}
|
||||
transferID := datatransfer.TransferID(transferUint)
|
||||
initiator := cctx.Bool("initiator")
|
||||
var other peer.ID
|
||||
if pidstr := cctx.String("peerid"); pidstr != "" {
|
||||
p, err := peer.Decode(pidstr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
other = p
|
||||
} else {
|
||||
channels, err := api.ClientListDataTransfers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
found := false
|
||||
for _, channel := range channels {
|
||||
if channel.IsInitiator == initiator && channel.TransferID == transferID {
|
||||
other = channel.OtherPeer
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return errors.New("unable to find matching data transfer")
|
||||
}
|
||||
}
|
||||
|
||||
return api.ClientRestartDataTransfer(ctx, transferID, other, initiator)
|
||||
},
|
||||
}
|
||||
|
||||
var clientListTransfers = &cli.Command{
|
||||
Name: "list-transfers",
|
||||
Usage: "List ongoing data transfers for deals",
|
||||
|
||||
+21
-50
@@ -11,8 +11,6 @@ import (
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
manet "github.com/multiformats/go-multiaddr/net"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@@ -20,6 +18,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/api/client"
|
||||
cliutil "github.com/filecoin-project/lotus/cli/util"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
)
|
||||
|
||||
@@ -46,37 +45,16 @@ func NewCliError(s string) error {
|
||||
// ApiConnector returns API instance
|
||||
type ApiConnector func() api.FullNode
|
||||
|
||||
type APIInfo struct {
|
||||
Addr multiaddr.Multiaddr
|
||||
Token []byte
|
||||
}
|
||||
|
||||
func (a APIInfo) DialArgs() (string, error) {
|
||||
_, addr, err := manet.DialArgs(a.Addr)
|
||||
|
||||
return "ws://" + addr + "/rpc/v0", err
|
||||
}
|
||||
|
||||
func (a APIInfo) AuthHeader() http.Header {
|
||||
if len(a.Token) != 0 {
|
||||
headers := http.Header{}
|
||||
headers.Add("Authorization", "Bearer "+string(a.Token))
|
||||
return headers
|
||||
}
|
||||
log.Warn("API Token not set and requested, capabilities might be limited.")
|
||||
return nil
|
||||
}
|
||||
|
||||
// The flag passed on the command line with the listen address of the API
|
||||
// server (only used by the tests)
|
||||
func flagForAPI(t repo.RepoType) string {
|
||||
switch t {
|
||||
case repo.FullNode:
|
||||
return "api"
|
||||
return "api-url"
|
||||
case repo.StorageMiner:
|
||||
return "miner-api"
|
||||
return "miner-api-url"
|
||||
case repo.Worker:
|
||||
return "worker-api"
|
||||
return "worker-api-url"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown repo type: %v", t))
|
||||
}
|
||||
@@ -122,7 +100,7 @@ func envForRepoDeprecation(t repo.RepoType) string {
|
||||
}
|
||||
}
|
||||
|
||||
func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
|
||||
func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (cliutil.APIInfo, error) {
|
||||
// Check if there was a flag passed with the listen address of the API
|
||||
// server (only used by the tests)
|
||||
apiFlag := flagForAPI(t)
|
||||
@@ -130,11 +108,7 @@ func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
|
||||
strma := ctx.String(apiFlag)
|
||||
strma = strings.TrimSpace(strma)
|
||||
|
||||
apima, err := multiaddr.NewMultiaddr(strma)
|
||||
if err != nil {
|
||||
return APIInfo{}, err
|
||||
}
|
||||
return APIInfo{Addr: apima}, nil
|
||||
return cliutil.APIInfo{Addr: strma}, nil
|
||||
}
|
||||
|
||||
envKey := envForRepo(t)
|
||||
@@ -148,36 +122,24 @@ func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
|
||||
}
|
||||
}
|
||||
if ok {
|
||||
sp := strings.SplitN(env, ":", 2)
|
||||
if len(sp) != 2 {
|
||||
log.Warnf("invalid env(%s) value, missing token or address", envKey)
|
||||
} else {
|
||||
ma, err := multiaddr.NewMultiaddr(sp[1])
|
||||
if err != nil {
|
||||
return APIInfo{}, xerrors.Errorf("could not parse multiaddr from env(%s): %w", envKey, err)
|
||||
}
|
||||
return APIInfo{
|
||||
Addr: ma,
|
||||
Token: []byte(sp[0]),
|
||||
}, nil
|
||||
}
|
||||
return cliutil.ParseApiInfo(env), nil
|
||||
}
|
||||
|
||||
repoFlag := flagForRepo(t)
|
||||
|
||||
p, err := homedir.Expand(ctx.String(repoFlag))
|
||||
if err != nil {
|
||||
return APIInfo{}, xerrors.Errorf("could not expand home dir (%s): %w", repoFlag, err)
|
||||
return cliutil.APIInfo{}, xerrors.Errorf("could not expand home dir (%s): %w", repoFlag, err)
|
||||
}
|
||||
|
||||
r, err := repo.NewFS(p)
|
||||
if err != nil {
|
||||
return APIInfo{}, xerrors.Errorf("could not open repo at path: %s; %w", p, err)
|
||||
return cliutil.APIInfo{}, xerrors.Errorf("could not open repo at path: %s; %w", p, err)
|
||||
}
|
||||
|
||||
ma, err := r.APIEndpoint()
|
||||
if err != nil {
|
||||
return APIInfo{}, xerrors.Errorf("could not get api endpoint: %w", err)
|
||||
return cliutil.APIInfo{}, xerrors.Errorf("could not get api endpoint: %w", err)
|
||||
}
|
||||
|
||||
token, err := r.APIToken()
|
||||
@@ -185,8 +147,8 @@ func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
|
||||
log.Warnf("Couldn't load CLI token, capabilities may be limited: %v", err)
|
||||
}
|
||||
|
||||
return APIInfo{
|
||||
Addr: ma,
|
||||
return cliutil.APIInfo{
|
||||
Addr: ma.String(),
|
||||
Token: token,
|
||||
}, nil
|
||||
}
|
||||
@@ -266,6 +228,15 @@ func GetWorkerAPI(ctx *cli.Context) (api.WorkerAPI, jsonrpc.ClientCloser, error)
|
||||
return client.NewWorkerRPC(ctx.Context, addr, headers)
|
||||
}
|
||||
|
||||
func GetGatewayAPI(ctx *cli.Context) (api.GatewayAPI, jsonrpc.ClientCloser, error) {
|
||||
addr, headers, err := GetRawAPI(ctx, repo.FullNode)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return client.NewGatewayRPC(ctx.Context, addr, headers)
|
||||
}
|
||||
|
||||
func DaemonContext(cctx *cli.Context) context.Context {
|
||||
if mtCtx, ok := cctx.App.Metadata[metadataTraceContext]; ok {
|
||||
return mtCtx.(context.Context)
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ func RunApp(app *cli.App) {
|
||||
if os.Getenv("LOTUS_DEV") != "" {
|
||||
log.Warnf("%+v", err)
|
||||
} else {
|
||||
fmt.Printf("ERROR: %s\n\n", err)
|
||||
fmt.Fprintf(os.Stderr, "ERROR: %s\n\n", err) // nolint:errcheck
|
||||
}
|
||||
var phe *PrintHelpErr
|
||||
if xerrors.As(err, &phe) {
|
||||
|
||||
+123
-5
@@ -3,8 +3,10 @@ package cli
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"text/tabwriter"
|
||||
@@ -14,6 +16,8 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
|
||||
@@ -41,6 +45,7 @@ var multisigCmd = &cli.Command{
|
||||
msigCreateCmd,
|
||||
msigInspectCmd,
|
||||
msigProposeCmd,
|
||||
msigRemoveProposeCmd,
|
||||
msigApproveCmd,
|
||||
msigAddProposeCmd,
|
||||
msigAddApproveCmd,
|
||||
@@ -174,6 +179,10 @@ var msigInspectCmd = &cli.Command{
|
||||
Name: "vesting",
|
||||
Usage: "Include vesting details",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "decode-params",
|
||||
Usage: "Decode parameters of transaction proposals",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
@@ -204,6 +213,11 @@ var msigInspectCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
ownId, err := api.StateLookupID(ctx, maddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mstate, err := multisig.Load(store, act)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -256,6 +270,7 @@ var msigInspectCmd = &cli.Command{
|
||||
return xerrors.Errorf("reading pending transactions: %w", err)
|
||||
}
|
||||
|
||||
decParams := cctx.Bool("decode-params")
|
||||
fmt.Println("Transactions: ", len(pending))
|
||||
if len(pending) > 0 {
|
||||
var txids []int64
|
||||
@@ -266,11 +281,36 @@ var msigInspectCmd = &cli.Command{
|
||||
return txids[i] < txids[j]
|
||||
})
|
||||
|
||||
w := tabwriter.NewWriter(os.Stdout, 8, 4, 0, ' ', 0)
|
||||
w := tabwriter.NewWriter(os.Stdout, 8, 4, 2, ' ', 0)
|
||||
fmt.Fprintf(w, "ID\tState\tApprovals\tTo\tValue\tMethod\tParams\n")
|
||||
for _, txid := range txids {
|
||||
tx := pending[txid]
|
||||
fmt.Fprintf(w, "%d\t%s\t%d\t%s\t%s\t%d\t%x\n", txid, "pending", len(tx.Approved), tx.To, types.FIL(tx.Value), tx.Method, tx.Params)
|
||||
target := tx.To.String()
|
||||
if tx.To == ownId {
|
||||
target += " (self)"
|
||||
}
|
||||
targAct, err := api.StateGetActor(ctx, tx.To, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to resolve 'To' address of multisig transaction %d: %w", txid, err)
|
||||
}
|
||||
method := stmgr.MethodsMap[targAct.Code][tx.Method]
|
||||
|
||||
paramStr := fmt.Sprintf("%x", tx.Params)
|
||||
if decParams && tx.Method != 0 {
|
||||
ptyp := reflect.New(method.Params.Elem()).Interface().(cbg.CBORUnmarshaler)
|
||||
if err := ptyp.UnmarshalCBOR(bytes.NewReader(tx.Params)); err != nil {
|
||||
return xerrors.Errorf("failed to decode parameters of transaction %d: %w", txid, err)
|
||||
}
|
||||
|
||||
b, err := json.Marshal(ptyp)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("could not json marshal parameter type: %w", err)
|
||||
}
|
||||
|
||||
paramStr = string(b)
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "%d\t%s\t%d\t%s\t%s\t%s(%d)\t%s\n", txid, "pending", len(tx.Approved), target, types.FIL(tx.Value), method.Name, tx.Method, paramStr)
|
||||
}
|
||||
if err := w.Flush(); err != nil {
|
||||
return xerrors.Errorf("flushing output: %+v", err)
|
||||
@@ -398,7 +438,7 @@ var msigProposeCmd = &cli.Command{
|
||||
var msigApproveCmd = &cli.Command{
|
||||
Name: "approve",
|
||||
Usage: "Approve a multisig message",
|
||||
ArgsUsage: "[multisigAddress messageId proposerAddress destination value <methodId methodParams> (optional)]",
|
||||
ArgsUsage: "<multisigAddress messageId> [proposerAddress destination value [methodId methodParams]]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "from",
|
||||
@@ -484,7 +524,7 @@ var msigApproveCmd = &cli.Command{
|
||||
from = defaddr
|
||||
}
|
||||
|
||||
msgCid, err := api.MsigApprove(ctx, msig, txid, proposer, dest, types.BigInt(value), from, method, params)
|
||||
msgCid, err := api.MsigApproveTxnHash(ctx, msig, txid, proposer, dest, types.BigInt(value), from, method, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -504,6 +544,84 @@ var msigApproveCmd = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var msigRemoveProposeCmd = &cli.Command{
|
||||
Name: "propose-remove",
|
||||
Usage: "Propose to remove a signer",
|
||||
ArgsUsage: "[multisigAddress signer]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "decrease-threshold",
|
||||
Usage: "whether the number of required signers should be decreased",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "from",
|
||||
Usage: "account to send the propose message from",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.Args().Len() != 2 {
|
||||
return ShowHelp(cctx, fmt.Errorf("must pass multisig address and signer address"))
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
msig, err := address.NewFromString(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addr, err := address.NewFromString(cctx.Args().Get(1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var from address.Address
|
||||
if cctx.IsSet("from") {
|
||||
f, err := address.NewFromString(cctx.String("from"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
from = f
|
||||
} else {
|
||||
defaddr, err := api.WalletDefaultAddress(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
from = defaddr
|
||||
}
|
||||
|
||||
msgCid, err := api.MsigRemoveSigner(ctx, msig, from, addr, cctx.Bool("decrease-threshold"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("sent remove proposal in message: ", msgCid)
|
||||
|
||||
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if wait.Receipt.ExitCode != 0 {
|
||||
return fmt.Errorf("add proposal returned exit %d", wait.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
var ret multisig.ProposeReturn
|
||||
err = ret.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("decoding proposal return: %w", err)
|
||||
}
|
||||
fmt.Printf("TxnID: %d", ret.TxnID)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var msigAddProposeCmd = &cli.Command{
|
||||
Name: "add-propose",
|
||||
Usage: "Propose to add a signer",
|
||||
@@ -1129,7 +1247,7 @@ var msigLockApproveCmd = &cli.Command{
|
||||
return actErr
|
||||
}
|
||||
|
||||
msgCid, err := api.MsigApprove(ctx, msig, txid, prop, msig, big.Zero(), from, uint64(builtin2.MethodsMultisig.LockBalance), params)
|
||||
msgCid, err := api.MsigApproveTxnHash(ctx, msig, txid, prop, msig, big.Zero(), from, uint64(builtin2.MethodsMultisig.LockBalance), params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+9
-10
@@ -29,7 +29,6 @@ import (
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/events"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
builder "github.com/filecoin-project/lotus/node/test"
|
||||
)
|
||||
|
||||
@@ -121,13 +120,13 @@ func TestPaymentChannelStatus(t *testing.T) {
|
||||
create := make(chan string)
|
||||
go func() {
|
||||
// creator: paych add-funds <creator> <receiver> <amount>
|
||||
cmd = []string{creatorAddr.String(), receiverAddr.String(), fmt.Sprintf("%d", channelAmt)}
|
||||
cmd := []string{creatorAddr.String(), receiverAddr.String(), fmt.Sprintf("%d", channelAmt)}
|
||||
create <- creatorCLI.runCmd(paychAddFundsCmd, cmd)
|
||||
}()
|
||||
|
||||
// Wait for the output to stop being "Channel does not exist"
|
||||
for regexp.MustCompile(noChannelState).MatchString(out) {
|
||||
cmd = []string{creatorAddr.String(), receiverAddr.String()}
|
||||
cmd := []string{creatorAddr.String(), receiverAddr.String()}
|
||||
out = creatorCLI.runCmd(paychStatusByFromToCmd, cmd)
|
||||
}
|
||||
fmt.Println(out)
|
||||
@@ -390,7 +389,7 @@ func checkVoucherOutput(t *testing.T, list string, vouchers []voucherSpec) {
|
||||
}
|
||||
|
||||
func startTwoNodesOneMiner(ctx context.Context, t *testing.T, blocktime time.Duration) ([]test.TestNode, []address.Address) {
|
||||
n, sn := builder.RPCMockSbBuilder(t, 2, test.OneMiner)
|
||||
n, sn := builder.RPCMockSbBuilder(t, test.TwoFull, test.OneMiner)
|
||||
|
||||
paymentCreator := n[0]
|
||||
paymentReceiver := n[1]
|
||||
@@ -415,7 +414,7 @@ func startTwoNodesOneMiner(ctx context.Context, t *testing.T, blocktime time.Dur
|
||||
bm.MineBlocks()
|
||||
|
||||
// Send some funds to register the receiver
|
||||
receiverAddr, err := paymentReceiver.WalletNew(ctx, wallet.ActSigType("secp256k1"))
|
||||
receiverAddr, err := paymentReceiver.WalletNew(ctx, types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -439,12 +438,12 @@ type mockCLI struct {
|
||||
}
|
||||
|
||||
func newMockCLI(t *testing.T) *mockCLI {
|
||||
// Create a CLI App with an --api flag so that we can specify which node
|
||||
// Create a CLI App with an --api-url flag so that we can specify which node
|
||||
// the command should be executed against
|
||||
app := cli.NewApp()
|
||||
app.Flags = []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "api",
|
||||
Name: "api-url",
|
||||
Hidden: true,
|
||||
},
|
||||
}
|
||||
@@ -476,8 +475,8 @@ func (c *mockCLIClient) runCmd(cmd *cli.Command, input []string) string {
|
||||
}
|
||||
|
||||
func (c *mockCLIClient) runCmdRaw(cmd *cli.Command, input []string) (string, error) {
|
||||
// prepend --api=<node api listener address>
|
||||
apiFlag := "--api=" + c.addr.String()
|
||||
// prepend --api-url=<node api listener address>
|
||||
apiFlag := "--api-url=" + c.addr.String()
|
||||
input = append([]string{apiFlag}, input...)
|
||||
|
||||
fs := c.flagSet(cmd)
|
||||
@@ -493,7 +492,7 @@ func (c *mockCLIClient) runCmdRaw(cmd *cli.Command, input []string) (string, err
|
||||
}
|
||||
|
||||
func (c *mockCLIClient) flagSet(cmd *cli.Command) *flag.FlagSet {
|
||||
// Apply app level flags (so we can process --api flag)
|
||||
// Apply app level flags (so we can process --api-url flag)
|
||||
fs := &flag.FlagSet{}
|
||||
for _, f := range c.cctx.App.Flags {
|
||||
err := f.Apply(fs)
|
||||
|
||||
+1
-2
@@ -9,7 +9,6 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
manet "github.com/multiformats/go-multiaddr/net"
|
||||
)
|
||||
|
||||
var pprofCmd = &cli.Command{
|
||||
@@ -37,7 +36,7 @@ var PprofGoroutines = &cli.Command{
|
||||
if err != nil {
|
||||
return xerrors.Errorf("could not get API info: %w", err)
|
||||
}
|
||||
_, addr, err := manet.DialArgs(ainfo.Addr)
|
||||
addr, err := ainfo.Host()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+27
-10
@@ -1688,7 +1688,14 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er
|
||||
|
||||
var stateCircSupplyCmd = &cli.Command{
|
||||
Name: "circulating-supply",
|
||||
Usage: "Get the current circulating supply of filecoin",
|
||||
Usage: "Get the exact current circulating supply of Filecoin",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "vm-supply",
|
||||
Usage: "calculates the approximation of the circulating supply used internally by the VM (instead of the exact amount)",
|
||||
Value: false,
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
@@ -1703,16 +1710,26 @@ var stateCircSupplyCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
circ, err := api.StateCirculatingSupply(ctx, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cctx.IsSet("vm-supply") {
|
||||
circ, err := api.StateVMCirculatingSupplyInternal(ctx, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Circulating supply: ", types.FIL(circ.FilCirculating))
|
||||
fmt.Println("Mined: ", types.FIL(circ.FilMined))
|
||||
fmt.Println("Vested: ", types.FIL(circ.FilVested))
|
||||
fmt.Println("Burnt: ", types.FIL(circ.FilBurnt))
|
||||
fmt.Println("Locked: ", types.FIL(circ.FilLocked))
|
||||
fmt.Println("Circulating supply: ", types.FIL(circ.FilCirculating))
|
||||
fmt.Println("Mined: ", types.FIL(circ.FilMined))
|
||||
fmt.Println("Vested: ", types.FIL(circ.FilVested))
|
||||
fmt.Println("Burnt: ", types.FIL(circ.FilBurnt))
|
||||
fmt.Println("Locked: ", types.FIL(circ.FilLocked))
|
||||
} else {
|
||||
circ, err := api.StateCirculatingSupply(ctx, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Exact circulating supply: ", types.FIL(circ))
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
|
||||
+30
-8
@@ -84,6 +84,12 @@ var syncStatusCmd = &cli.Command{
|
||||
var syncWaitCmd = &cli.Command{
|
||||
Name: "wait",
|
||||
Usage: "Wait for sync to be complete",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "watch",
|
||||
Usage: "don't exit after node is synced",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
napi, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
@@ -92,7 +98,7 @@ var syncWaitCmd = &cli.Command{
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
return SyncWait(ctx, napi)
|
||||
return SyncWait(ctx, napi, cctx.Bool("watch"))
|
||||
},
|
||||
}
|
||||
|
||||
@@ -122,8 +128,14 @@ var syncMarkBadCmd = &cli.Command{
|
||||
}
|
||||
|
||||
var syncUnmarkBadCmd = &cli.Command{
|
||||
Name: "unmark-bad",
|
||||
Usage: "Unmark the given block as bad, makes it possible to sync to a chain containing it",
|
||||
Name: "unmark-bad",
|
||||
Usage: "Unmark the given block as bad, makes it possible to sync to a chain containing it",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "all",
|
||||
Usage: "drop the entire bad block cache",
|
||||
},
|
||||
},
|
||||
ArgsUsage: "[blockCid]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
napi, closer, err := GetFullNodeAPI(cctx)
|
||||
@@ -133,6 +145,10 @@ var syncUnmarkBadCmd = &cli.Command{
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if cctx.Bool("all") {
|
||||
return napi.SyncUnmarkAllBad(ctx)
|
||||
}
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must specify block cid to unmark")
|
||||
}
|
||||
@@ -224,7 +240,7 @@ var syncCheckpointCmd = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
func SyncWait(ctx context.Context, napi api.FullNode) error {
|
||||
func SyncWait(ctx context.Context, napi api.FullNode, watch bool) error {
|
||||
tick := time.Second / 4
|
||||
|
||||
lastLines := 0
|
||||
@@ -233,7 +249,13 @@ func SyncWait(ctx context.Context, napi api.FullNode) error {
|
||||
|
||||
samples := 8
|
||||
i := 0
|
||||
var app, lastApp uint64
|
||||
var firstApp, app, lastApp uint64
|
||||
|
||||
state, err := napi.SyncState(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
firstApp = state.VMApplied
|
||||
|
||||
for {
|
||||
state, err := napi.SyncState(ctx)
|
||||
@@ -286,16 +308,16 @@ func SyncWait(ctx context.Context, napi api.FullNode) error {
|
||||
|
||||
if i%samples == 0 {
|
||||
lastApp = app
|
||||
app = state.VMApplied
|
||||
app = state.VMApplied - firstApp
|
||||
}
|
||||
if i > 0 {
|
||||
fmt.Printf("Validated %d messages (%d per second)\n", state.VMApplied, (app-lastApp)*uint64(time.Second/tick)/uint64(samples))
|
||||
fmt.Printf("Validated %d messages (%d per second)\n", state.VMApplied-firstApp, (app-lastApp)*uint64(time.Second/tick)/uint64(samples))
|
||||
lastLines++
|
||||
}
|
||||
|
||||
_ = target // todo: maybe print? (creates a bunch of line wrapping issues with most tipsets)
|
||||
|
||||
if time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs) {
|
||||
if !watch && time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs) {
|
||||
fmt.Println("\nDone!")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
package cliutil
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
manet "github.com/multiformats/go-multiaddr/net"
|
||||
)
|
||||
|
||||
var log = logging.Logger("cliutil")
|
||||
|
||||
var (
|
||||
infoWithToken = regexp.MustCompile("^[a-zA-Z0-9\\-_]+?\\.[a-zA-Z0-9\\-_]+?\\.([a-zA-Z0-9\\-_]+)?:.+$")
|
||||
)
|
||||
|
||||
type APIInfo struct {
|
||||
Addr string
|
||||
Token []byte
|
||||
}
|
||||
|
||||
func ParseApiInfo(s string) APIInfo {
|
||||
var tok []byte
|
||||
if infoWithToken.Match([]byte(s)) {
|
||||
sp := strings.SplitN(s, ":", 2)
|
||||
tok = []byte(sp[0])
|
||||
s = sp[1]
|
||||
}
|
||||
|
||||
return APIInfo{
|
||||
Addr: s,
|
||||
Token: tok,
|
||||
}
|
||||
}
|
||||
|
||||
func (a APIInfo) DialArgs() (string, error) {
|
||||
ma, err := multiaddr.NewMultiaddr(a.Addr)
|
||||
if err == nil {
|
||||
_, addr, err := manet.DialArgs(ma)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return "ws://" + addr + "/rpc/v0", nil
|
||||
}
|
||||
|
||||
_, err = url.Parse(a.Addr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return a.Addr + "/rpc/v0", nil
|
||||
}
|
||||
|
||||
func (a APIInfo) Host() (string, error) {
|
||||
ma, err := multiaddr.NewMultiaddr(a.Addr)
|
||||
if err == nil {
|
||||
_, addr, err := manet.DialArgs(ma)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
spec, err := url.Parse(a.Addr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return spec.Host, nil
|
||||
}
|
||||
|
||||
func (a APIInfo) AuthHeader() http.Header {
|
||||
if len(a.Token) != 0 {
|
||||
headers := http.Header{}
|
||||
headers.Add("Authorization", "Bearer "+string(a.Token))
|
||||
return headers
|
||||
}
|
||||
log.Warn("API Token not set and requested, capabilities might be limited.")
|
||||
return nil
|
||||
}
|
||||
+3
-4
@@ -17,7 +17,6 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
types "github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/filecoin-project/lotus/lib/tablewriter"
|
||||
)
|
||||
|
||||
@@ -55,7 +54,7 @@ var walletNew = &cli.Command{
|
||||
t = "secp256k1"
|
||||
}
|
||||
|
||||
nk, err := api.WalletNew(ctx, wallet.ActSigType(t))
|
||||
nk, err := api.WalletNew(ctx, types.KeyType(t))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -329,9 +328,9 @@ var walletImport = &cli.Command{
|
||||
ki.PrivateKey = gk.PrivateKey
|
||||
switch gk.SigType {
|
||||
case 1:
|
||||
ki.Type = wallet.KTSecp256k1
|
||||
ki.Type = types.KTSecp256k1
|
||||
case 2:
|
||||
ki.Type = wallet.KTBLS
|
||||
ki.Type = types.KTBLS
|
||||
default:
|
||||
return fmt.Errorf("unrecognized key type: %d", gk.SigType)
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
@@ -61,7 +59,7 @@ var runCmd = &cli.Command{
|
||||
func sendSmallFundsTxs(ctx context.Context, api api.FullNode, from address.Address, rate int) error {
|
||||
var sendSet []address.Address
|
||||
for i := 0; i < 20; i++ {
|
||||
naddr, err := api.WalletNew(ctx, crypto.SigTypeSecp256k1)
|
||||
naddr, err := api.WalletNew(ctx, types.KTSecp256k1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ var importBenchCmd = &cli.Command{
|
||||
return nil
|
||||
}
|
||||
|
||||
cs := store.NewChainStore(bs, ds, vm.Syscalls(verifier))
|
||||
cs := store.NewChainStore(bs, ds, vm.Syscalls(verifier), nil)
|
||||
stm := stmgr.NewStateManager(cs)
|
||||
|
||||
if cctx.Bool("global-profile") {
|
||||
|
||||
@@ -316,7 +316,7 @@ limit 1
|
||||
}
|
||||
|
||||
func (s *Syncer) storeCirculatingSupply(ctx context.Context, tipset *types.TipSet) error {
|
||||
supply, err := s.node.StateCirculatingSupply(ctx, tipset.Key())
|
||||
supply, err := s.node.StateVMCirculatingSupplyInternal(ctx, tipset.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+131
-42
@@ -6,85 +6,174 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/impl/full"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
const LookbackCap = time.Hour
|
||||
const (
|
||||
LookbackCap = time.Hour
|
||||
stateWaitLookbackLimit = abi.ChainEpoch(20)
|
||||
)
|
||||
|
||||
var (
|
||||
ErrLookbackTooLong = fmt.Errorf("lookbacks of more than %s are disallowed", LookbackCap)
|
||||
)
|
||||
|
||||
type GatewayAPI struct {
|
||||
api api.FullNode
|
||||
// gatewayDepsAPI defines the API methods that the GatewayAPI depends on
|
||||
// (to make it easy to mock for tests)
|
||||
type gatewayDepsAPI interface {
|
||||
ChainHead(ctx context.Context) (*types.TipSet, error)
|
||||
ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error)
|
||||
ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error)
|
||||
GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error)
|
||||
MpoolPushUntrusted(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error)
|
||||
MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error)
|
||||
MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error)
|
||||
StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
|
||||
StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)
|
||||
StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
|
||||
StateWaitMsgLimited(ctx context.Context, msg cid.Cid, confidence uint64, h abi.ChainEpoch) (*api.MsgLookup, error)
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) getTipsetTimestamp(ctx context.Context, tsk types.TipSetKey) (time.Time, error) {
|
||||
type GatewayAPI struct {
|
||||
api gatewayDepsAPI
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) checkTipsetKey(ctx context.Context, tsk types.TipSetKey) error {
|
||||
if tsk.IsEmpty() {
|
||||
return time.Now(), nil
|
||||
return nil
|
||||
}
|
||||
|
||||
ts, err := a.api.ChainGetTipSet(ctx, tsk)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
return time.Unix(int64(ts.Blocks()[0].Timestamp), 0), nil
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) checkTipset(ctx context.Context, ts types.TipSetKey) error {
|
||||
when, err := a.getTipsetTimestamp(ctx, ts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if time.Since(when) > time.Hour {
|
||||
return a.checkTipset(ts)
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) checkTipset(ts *types.TipSet) error {
|
||||
at := time.Unix(int64(ts.Blocks()[0].Timestamp), 0)
|
||||
if err := a.checkTimestamp(at); err != nil {
|
||||
return fmt.Errorf("bad tipset: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) checkTipsetHeight(ts *types.TipSet, h abi.ChainEpoch) error {
|
||||
tsBlock := ts.Blocks()[0]
|
||||
heightDelta := time.Duration(uint64(tsBlock.Height-h)*build.BlockDelaySecs) * time.Second
|
||||
timeAtHeight := time.Unix(int64(tsBlock.Timestamp), 0).Add(-heightDelta)
|
||||
|
||||
if err := a.checkTimestamp(timeAtHeight); err != nil {
|
||||
return fmt.Errorf("bad tipset height: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) checkTimestamp(at time.Time) error {
|
||||
if time.Since(at) > LookbackCap {
|
||||
return ErrLookbackTooLong
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "StateGetActor")
|
||||
defer span.End()
|
||||
|
||||
if err := a.checkTipset(ctx, ts); err != nil {
|
||||
return nil, fmt.Errorf("bad tipset: %w", err)
|
||||
}
|
||||
|
||||
return a.api.StateGetActor(ctx, actor, ts)
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) ChainHead(ctx context.Context) (*types.TipSet, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "ChainHead")
|
||||
defer span.End()
|
||||
// TODO: cache and invalidate cache when timestamp is up (or have internal ChainNotify)
|
||||
|
||||
return a.api.ChainHead(ctx)
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "ChainGetTipSet")
|
||||
defer span.End()
|
||||
|
||||
if err := a.checkTipset(ctx, tsk); err != nil {
|
||||
return nil, fmt.Errorf("bad tipset: %w", err)
|
||||
}
|
||||
|
||||
// TODO: since we're limiting lookbacks, should just cache this (could really even cache the json response bytes)
|
||||
return a.api.ChainGetTipSet(ctx, tsk)
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
ts, err := a.api.ChainGetTipSet(ctx, tsk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check if the tipset key refers to a tipset that's too far in the past
|
||||
if err := a.checkTipset(ts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check if the height is too far in the past
|
||||
if err := a.checkTipsetHeight(ts, h); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return a.api.ChainGetTipSetByHeight(ctx, h, tsk)
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) {
|
||||
if err := a.checkTipsetKey(ctx, tsk); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return a.api.GasEstimateMessageGas(ctx, msg, spec, tsk)
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "MpoolPush")
|
||||
defer span.End()
|
||||
|
||||
// TODO: additional anti-spam checks
|
||||
|
||||
return a.api.MpoolPushUntrusted(ctx, sm)
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
if err := a.checkTipsetKey(ctx, tsk); err != nil {
|
||||
return types.NewInt(0), err
|
||||
}
|
||||
|
||||
return a.api.MsigGetAvailableBalance(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) {
|
||||
if err := a.checkTipsetKey(ctx, start); err != nil {
|
||||
return types.NewInt(0), err
|
||||
}
|
||||
if err := a.checkTipsetKey(ctx, end); err != nil {
|
||||
return types.NewInt(0), err
|
||||
}
|
||||
|
||||
return a.api.MsigGetVested(ctx, addr, start, end)
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
||||
if err := a.checkTipsetKey(ctx, tsk); err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
return a.api.StateAccountKey(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) {
|
||||
if err := a.checkTipsetKey(ctx, tsk); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return a.api.StateGetActor(ctx, actor, tsk)
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
||||
if err := a.checkTipsetKey(ctx, tsk); err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
return a.api.StateLookupID(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) {
|
||||
return a.api.StateWaitMsgLimited(ctx, msg, confidence, stateWaitLookbackLimit)
|
||||
}
|
||||
|
||||
var _ api.GatewayAPI = (*GatewayAPI)(nil)
|
||||
var _ full.ChainModuleAPI = (*GatewayAPI)(nil)
|
||||
var _ full.GasModuleAPI = (*GatewayAPI)(nil)
|
||||
var _ full.MpoolModuleAPI = (*GatewayAPI)(nil)
|
||||
var _ full.StateModuleAPI = (*GatewayAPI)(nil)
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
func TestGatewayAPIChainGetTipSetByHeight(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
lookbackTimestamp := uint64(time.Now().Unix()) - uint64(LookbackCap.Seconds())
|
||||
type args struct {
|
||||
h abi.ChainEpoch
|
||||
tskh abi.ChainEpoch
|
||||
genesisTS uint64
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expErr bool
|
||||
}{{
|
||||
name: "basic",
|
||||
args: args{
|
||||
h: abi.ChainEpoch(1),
|
||||
tskh: abi.ChainEpoch(5),
|
||||
},
|
||||
}, {
|
||||
name: "genesis",
|
||||
args: args{
|
||||
h: abi.ChainEpoch(0),
|
||||
tskh: abi.ChainEpoch(5),
|
||||
},
|
||||
}, {
|
||||
name: "same epoch as tipset",
|
||||
args: args{
|
||||
h: abi.ChainEpoch(5),
|
||||
tskh: abi.ChainEpoch(5),
|
||||
},
|
||||
}, {
|
||||
name: "tipset too old",
|
||||
args: args{
|
||||
// Tipset height is 5, genesis is at LookbackCap - 10 epochs.
|
||||
// So resulting tipset height will be 5 epochs earlier than LookbackCap.
|
||||
h: abi.ChainEpoch(1),
|
||||
tskh: abi.ChainEpoch(5),
|
||||
genesisTS: lookbackTimestamp - build.BlockDelaySecs*10,
|
||||
},
|
||||
expErr: true,
|
||||
}, {
|
||||
name: "lookup height too old",
|
||||
args: args{
|
||||
// Tipset height is 5, lookup height is 1, genesis is at LookbackCap - 3 epochs.
|
||||
// So
|
||||
// - lookup height will be 2 epochs earlier than LookbackCap.
|
||||
// - tipset height will be 2 epochs later than LookbackCap.
|
||||
h: abi.ChainEpoch(1),
|
||||
tskh: abi.ChainEpoch(5),
|
||||
genesisTS: lookbackTimestamp - build.BlockDelaySecs*3,
|
||||
},
|
||||
expErr: true,
|
||||
}, {
|
||||
name: "tipset and lookup height within acceptable range",
|
||||
args: args{
|
||||
// Tipset height is 5, lookup height is 1, genesis is at LookbackCap.
|
||||
// So
|
||||
// - lookup height will be 1 epoch later than LookbackCap.
|
||||
// - tipset height will be 5 epochs later than LookbackCap.
|
||||
h: abi.ChainEpoch(1),
|
||||
tskh: abi.ChainEpoch(5),
|
||||
genesisTS: lookbackTimestamp,
|
||||
},
|
||||
}}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mock := &mockGatewayDepsAPI{}
|
||||
a := &GatewayAPI{api: mock}
|
||||
|
||||
// Create tipsets from genesis up to tskh and return the highest
|
||||
ts := mock.createTipSets(tt.args.tskh, tt.args.genesisTS)
|
||||
|
||||
got, err := a.ChainGetTipSetByHeight(ctx, tt.args.h, ts.Key())
|
||||
if tt.expErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tt.args.h, got.Height())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type mockGatewayDepsAPI struct {
|
||||
lk sync.RWMutex
|
||||
tipsets []*types.TipSet
|
||||
}
|
||||
|
||||
func (m *mockGatewayDepsAPI) ChainHead(ctx context.Context) (*types.TipSet, error) {
|
||||
m.lk.RLock()
|
||||
defer m.lk.RUnlock()
|
||||
|
||||
return m.tipsets[len(m.tipsets)-1], nil
|
||||
}
|
||||
|
||||
func (m *mockGatewayDepsAPI) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
m.lk.RLock()
|
||||
defer m.lk.RUnlock()
|
||||
|
||||
for _, ts := range m.tipsets {
|
||||
if ts.Key() == tsk {
|
||||
return ts, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// createTipSets creates tipsets from genesis up to tskh and returns the highest
|
||||
func (m *mockGatewayDepsAPI) createTipSets(h abi.ChainEpoch, genesisTimestamp uint64) *types.TipSet {
|
||||
m.lk.Lock()
|
||||
defer m.lk.Unlock()
|
||||
|
||||
targeth := h + 1 // add one for genesis block
|
||||
if genesisTimestamp == 0 {
|
||||
genesisTimestamp = uint64(time.Now().Unix()) - build.BlockDelaySecs*uint64(targeth)
|
||||
}
|
||||
var currts *types.TipSet
|
||||
for currh := abi.ChainEpoch(0); currh < targeth; currh++ {
|
||||
blks := mock.MkBlock(currts, 1, 1)
|
||||
if currh == 0 {
|
||||
blks.Timestamp = genesisTimestamp
|
||||
}
|
||||
currts = mock.TipSet(blks)
|
||||
m.tipsets = append(m.tipsets, currts)
|
||||
}
|
||||
|
||||
return m.tipsets[len(m.tipsets)-1]
|
||||
}
|
||||
|
||||
func (m *mockGatewayDepsAPI) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
m.lk.Lock()
|
||||
defer m.lk.Unlock()
|
||||
|
||||
return m.tipsets[h], nil
|
||||
}
|
||||
|
||||
func (m *mockGatewayDepsAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockGatewayDepsAPI) MpoolPushUntrusted(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockGatewayDepsAPI) MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockGatewayDepsAPI) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockGatewayDepsAPI) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockGatewayDepsAPI) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockGatewayDepsAPI) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockGatewayDepsAPI) StateWaitMsgLimited(ctx context.Context, msg cid.Cid, confidence uint64, h abi.ChainEpoch) (*api.MsgLookup, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-jsonrpc"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/api/client"
|
||||
"github.com/filecoin-project/lotus/api/test"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node"
|
||||
builder "github.com/filecoin-project/lotus/node/test"
|
||||
)
|
||||
|
||||
func init() {
|
||||
policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1)
|
||||
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
|
||||
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
|
||||
}
|
||||
|
||||
// TestEndToEnd tests that API calls can be made on a lite node that is
|
||||
// connected through a gateway to a full API node
|
||||
func TestEndToEnd(t *testing.T) {
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
blocktime := 5 * time.Millisecond
|
||||
ctx := context.Background()
|
||||
full, lite, closer := startNodes(ctx, t, blocktime)
|
||||
defer closer()
|
||||
|
||||
// The full node starts with a wallet
|
||||
fullWalletAddr, err := full.WalletDefaultAddress(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check the full node's wallet balance from the lite node
|
||||
balance, err := lite.WalletBalance(ctx, fullWalletAddr)
|
||||
require.NoError(t, err)
|
||||
fmt.Println(balance)
|
||||
|
||||
// Create a wallet on the lite node
|
||||
liteWalletAddr, err := lite.WalletNew(ctx, types.KTSecp256k1)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Send some funds from the full node to the lite node
|
||||
err = sendFunds(ctx, t, full, fullWalletAddr, liteWalletAddr, types.NewInt(1e18))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Send some funds from the lite node back to the full node
|
||||
err = sendFunds(ctx, t, lite, liteWalletAddr, fullWalletAddr, types.NewInt(100))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Sign some data with the lite node wallet address
|
||||
data := []byte("hello")
|
||||
sig, err := lite.WalletSign(ctx, liteWalletAddr, data)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify the signature
|
||||
ok, err := lite.WalletVerify(ctx, liteWalletAddr, data, sig)
|
||||
require.NoError(t, err)
|
||||
require.True(t, ok)
|
||||
|
||||
// Create some wallets on the lite node to use for testing multisig
|
||||
var walletAddrs []address.Address
|
||||
for i := 0; i < 4; i++ {
|
||||
addr, err := lite.WalletNew(ctx, types.KTSecp256k1)
|
||||
require.NoError(t, err)
|
||||
|
||||
walletAddrs = append(walletAddrs, addr)
|
||||
|
||||
err = sendFunds(ctx, t, lite, liteWalletAddr, addr, types.NewInt(1e15))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Create an msig with three of the addresses and threshold of two sigs
|
||||
msigAddrs := walletAddrs[:3]
|
||||
amt := types.NewInt(1000)
|
||||
addProposal, err := lite.MsigCreate(ctx, 2, msigAddrs, abi.ChainEpoch(50), amt, liteWalletAddr, types.NewInt(0))
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := lite.StateWaitMsg(ctx, addProposal, 1)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 0, res.Receipt.ExitCode)
|
||||
|
||||
var execReturn init0.ExecReturn
|
||||
err = execReturn.UnmarshalCBOR(bytes.NewReader(res.Receipt.Return))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get available balance of msig: should be greater than zero and less
|
||||
// than initial amount
|
||||
msig := execReturn.IDAddress
|
||||
msigBalance, err := lite.MsigGetAvailableBalance(ctx, msig, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
require.Greater(t, msigBalance.Int64(), int64(0))
|
||||
require.Less(t, msigBalance.Int64(), amt.Int64())
|
||||
|
||||
// Propose to add a new address to the msig
|
||||
addProposal, err = lite.MsigAddPropose(ctx, msig, walletAddrs[0], walletAddrs[3], false)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err = lite.StateWaitMsg(ctx, addProposal, 1)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 0, res.Receipt.ExitCode)
|
||||
|
||||
var proposeReturn multisig.ProposeReturn
|
||||
err = proposeReturn.UnmarshalCBOR(bytes.NewReader(res.Receipt.Return))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Approve proposal (proposer is first (implicit) signer, approver is
|
||||
// second signer
|
||||
txnID := uint64(proposeReturn.TxnID)
|
||||
approval1, err := lite.MsigAddApprove(ctx, msig, walletAddrs[1], txnID, walletAddrs[0], walletAddrs[3], false)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err = lite.StateWaitMsg(ctx, approval1, 1)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 0, res.Receipt.ExitCode)
|
||||
|
||||
var approveReturn multisig.ApproveReturn
|
||||
err = approveReturn.UnmarshalCBOR(bytes.NewReader(res.Receipt.Return))
|
||||
require.NoError(t, err)
|
||||
require.True(t, approveReturn.Applied)
|
||||
}
|
||||
|
||||
func sendFunds(ctx context.Context, t *testing.T, fromNode test.TestNode, fromAddr address.Address, toAddr address.Address, amt types.BigInt) error {
|
||||
msg := &types.Message{
|
||||
From: fromAddr,
|
||||
To: toAddr,
|
||||
Value: amt,
|
||||
}
|
||||
|
||||
sm, err := fromNode.MpoolPushMessage(ctx, msg, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := fromNode.StateWaitMsg(ctx, sm.Cid(), 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if res.Receipt.ExitCode != 0 {
|
||||
return xerrors.Errorf("send funds failed with exit code %d", res.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func startNodes(ctx context.Context, t *testing.T, blocktime time.Duration) (test.TestNode, test.TestNode, jsonrpc.ClientCloser) {
|
||||
var closer jsonrpc.ClientCloser
|
||||
|
||||
// Create one miner and two full nodes.
|
||||
// - Put a gateway server in front of full node 1
|
||||
// - Start full node 2 in lite mode
|
||||
// - Connect lite node -> gateway server -> full node
|
||||
opts := append(
|
||||
// Full node
|
||||
test.OneFull,
|
||||
// Lite node
|
||||
test.FullNodeOpts{
|
||||
Lite: true,
|
||||
Opts: func(nodes []test.TestNode) node.Option {
|
||||
fullNode := nodes[0]
|
||||
|
||||
// Create a gateway server in front of the full node
|
||||
_, addr, err := builder.CreateRPCServer(&GatewayAPI{api: fullNode})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create a gateway client API that connects to the gateway server
|
||||
var gapi api.GatewayAPI
|
||||
gapi, closer, err = client.NewGatewayRPC(ctx, addr, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Provide the gateway API to dependency injection
|
||||
return node.Override(new(api.GatewayAPI), gapi)
|
||||
},
|
||||
},
|
||||
)
|
||||
n, sn := builder.RPCMockSbBuilder(t, opts, test.OneMiner)
|
||||
|
||||
full := n[0]
|
||||
lite := n[1]
|
||||
miner := sn[0]
|
||||
|
||||
// Get the listener address for the full node
|
||||
fullAddr, err := full.NetAddrsListen(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Connect the miner and the full node
|
||||
err = miner.NetConnect(ctx, fullAddr)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Start mining blocks
|
||||
bm := test.NewBlockMiner(ctx, t, miner, blocktime)
|
||||
bm.MineBlocks()
|
||||
|
||||
return full, lite, closer
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
@@ -30,22 +30,22 @@ func main() {
|
||||
return err
|
||||
}
|
||||
|
||||
var kt crypto.SigType
|
||||
var kt types.KeyType
|
||||
switch cctx.String("type") {
|
||||
case "bls":
|
||||
kt = crypto.SigTypeBLS
|
||||
kt = types.KTBLS
|
||||
case "secp256k1":
|
||||
kt = crypto.SigTypeSecp256k1
|
||||
kt = types.KTSecp256k1
|
||||
default:
|
||||
return fmt.Errorf("unrecognized key type: %q", cctx.String("type"))
|
||||
}
|
||||
|
||||
kaddr, err := w.GenerateKey(kt)
|
||||
kaddr, err := w.WalletNew(cctx.Context, kt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ki, err := w.Export(kaddr)
|
||||
ki, err := w.WalletExport(cctx.Context, kaddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -396,13 +396,13 @@ var runCmd = &cli.Command{
|
||||
Name: "pre-fee-cap-max",
|
||||
EnvVars: []string{"LOTUS_PCR_PRE_FEE_CAP_MAX"},
|
||||
Usage: "messages with a fee cap larger than this will be skipped when processing pre commit messages",
|
||||
Value: "0.0000000001",
|
||||
Value: "0.000000001",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "prove-fee-cap-max",
|
||||
EnvVars: []string{"LOTUS_PCR_PROVE_FEE_CAP_MAX"},
|
||||
Usage: "messages with a prove cap larger than this will be skipped when processing pre commit messages",
|
||||
Value: "0.0000000001",
|
||||
Value: "0.000000001",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
@@ -884,6 +884,8 @@ func (r *refunder) processTipsetStorageMarketActor(ctx context.Context, tipset *
|
||||
}
|
||||
|
||||
refundValue = types.BigMul(types.NewInt(uint64(recp.GasUsed)), tipset.Blocks()[0].ParentBaseFee)
|
||||
default:
|
||||
return false, messageMethod, types.NewInt(0), nil
|
||||
}
|
||||
|
||||
return true, messageMethod, refundValue, nil
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/zerocomm"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
|
||||
@@ -93,7 +92,7 @@ func PreSeal(maddr address.Address, spt abi.RegisteredSealProof, offset abi.Sect
|
||||
return nil, nil, err
|
||||
}
|
||||
} else {
|
||||
minerAddr, err = wallet.GenerateKey(crypto.SigTypeBLS)
|
||||
minerAddr, err = wallet.GenerateKey(types.KTBLS)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
+62
-28
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/docker/go-units"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
||||
|
||||
@@ -33,16 +34,19 @@ import (
|
||||
)
|
||||
|
||||
type accountInfo struct {
|
||||
Address address.Address
|
||||
Balance types.FIL
|
||||
Type string
|
||||
Power abi.StoragePower
|
||||
Worker address.Address
|
||||
Owner address.Address
|
||||
InitialPledge types.FIL
|
||||
PreCommits types.FIL
|
||||
LockedFunds types.FIL
|
||||
Sectors uint64
|
||||
Address address.Address
|
||||
Balance types.FIL
|
||||
Type string
|
||||
Power abi.StoragePower
|
||||
Worker address.Address
|
||||
Owner address.Address
|
||||
InitialPledge types.FIL
|
||||
PreCommits types.FIL
|
||||
LockedFunds types.FIL
|
||||
Sectors uint64
|
||||
VestingStart abi.ChainEpoch
|
||||
VestingDuration abi.ChainEpoch
|
||||
VestingAmount types.FIL
|
||||
}
|
||||
|
||||
var auditsCmd = &cli.Command{
|
||||
@@ -115,10 +119,8 @@ var chainBalanceCmd = &cli.Command{
|
||||
infos = append(infos, ai)
|
||||
}
|
||||
|
||||
fmt.Printf("Address,Balance,Type,Power,Worker,Owner\n")
|
||||
for _, acc := range infos {
|
||||
fmt.Printf("%s,%s,%s,%s,%s,%s\n", acc.Address, acc.Balance, acc.Type, acc.Power, acc.Worker, acc.Owner)
|
||||
}
|
||||
printAccountInfos(infos, false)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -171,7 +173,7 @@ var chainBalanceStateCmd = &cli.Command{
|
||||
|
||||
bs := blockstore.NewBlockstore(ds)
|
||||
|
||||
cs := store.NewChainStore(bs, mds, vm.Syscalls(ffiwrapper.ProofVerifier))
|
||||
cs := store.NewChainStore(bs, mds, vm.Syscalls(ffiwrapper.ProofVerifier), nil)
|
||||
|
||||
cst := cbor.NewCborStore(bs)
|
||||
store := adt.WrapStore(ctx, cst)
|
||||
@@ -196,6 +198,7 @@ var chainBalanceStateCmd = &cli.Command{
|
||||
LockedFunds: types.FIL(big.NewInt(0)),
|
||||
InitialPledge: types.FIL(big.NewInt(0)),
|
||||
PreCommits: types.FIL(big.NewInt(0)),
|
||||
VestingAmount: types.FIL(big.NewInt(0)),
|
||||
}
|
||||
|
||||
if minerInfo && builtin.IsStorageMinerActor(act.Code) {
|
||||
@@ -234,6 +237,32 @@ var chainBalanceStateCmd = &cli.Command{
|
||||
ai.Worker = minfo.Worker
|
||||
ai.Owner = minfo.Owner
|
||||
}
|
||||
|
||||
if builtin.IsMultisigActor(act.Code) {
|
||||
mst, err := multisig.Load(store, act)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ai.VestingStart, err = mst.StartEpoch()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ib, err := mst.InitialBalance()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ai.VestingAmount = types.FIL(ib)
|
||||
|
||||
ai.VestingDuration, err = mst.UnlockDuration()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
infos = append(infos, ai)
|
||||
return nil
|
||||
})
|
||||
@@ -241,22 +270,27 @@ var chainBalanceStateCmd = &cli.Command{
|
||||
return xerrors.Errorf("failed to loop over actors: %w", err)
|
||||
}
|
||||
|
||||
if minerInfo {
|
||||
fmt.Printf("Address,Balance,Type,Sectors,Worker,Owner,InitialPledge,Locked,PreCommits\n")
|
||||
for _, acc := range infos {
|
||||
fmt.Printf("%s,%s,%s,%d,%s,%s,%s,%s,%s\n", acc.Address, acc.Balance, acc.Type, acc.Sectors, acc.Worker, acc.Owner, acc.InitialPledge, acc.LockedFunds, acc.PreCommits)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("Address,Balance,Type\n")
|
||||
for _, acc := range infos {
|
||||
fmt.Printf("%s,%s,%s\n", acc.Address, acc.Balance, acc.Type)
|
||||
}
|
||||
}
|
||||
printAccountInfos(infos, minerInfo)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func printAccountInfos(infos []accountInfo, minerInfo bool) {
|
||||
if minerInfo {
|
||||
fmt.Printf("Address,Balance,Type,Sectors,Worker,Owner,InitialPledge,Locked,PreCommits,VestingStart,VestingDuration,VestingAmount\n")
|
||||
for _, acc := range infos {
|
||||
fmt.Printf("%s,%s,%s,%d,%s,%s,%s,%s,%s,%d,%d,%s\n", acc.Address, acc.Balance.Unitless(), acc.Type, acc.Sectors, acc.Worker, acc.Owner, acc.InitialPledge.Unitless(), acc.LockedFunds.Unitless(), acc.PreCommits.Unitless(), acc.VestingStart, acc.VestingDuration, acc.VestingAmount.Unitless())
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("Address,Balance,Type\n")
|
||||
for _, acc := range infos {
|
||||
fmt.Printf("%s,%s,%s\n", acc.Address, acc.Balance.Unitless(), acc.Type)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var chainPledgeCmd = &cli.Command{
|
||||
Name: "stateroot-pledge",
|
||||
Description: "Calculate sector pledge numbers",
|
||||
@@ -309,7 +343,7 @@ var chainPledgeCmd = &cli.Command{
|
||||
|
||||
bs := blockstore.NewBlockstore(ds)
|
||||
|
||||
cs := store.NewChainStore(bs, mds, vm.Syscalls(ffiwrapper.ProofVerifier))
|
||||
cs := store.NewChainStore(bs, mds, vm.Syscalls(ffiwrapper.ProofVerifier), nil)
|
||||
|
||||
cst := cbor.NewCborStore(bs)
|
||||
store := adt.WrapStore(ctx, cst)
|
||||
@@ -338,7 +372,7 @@ var chainPledgeCmd = &cli.Command{
|
||||
pledgeCollateral = c
|
||||
}
|
||||
|
||||
circ, err := sm.GetCirculatingSupplyDetailed(ctx, abi.ChainEpoch(epoch), state)
|
||||
circ, err := sm.GetVMCirculatingSupplyDetailed(ctx, abi.ChainEpoch(epoch), state)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
cliutil "github.com/filecoin-project/lotus/cli/util"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
"github.com/urfave/cli/v2"
|
||||
@@ -111,7 +112,7 @@ var consensusCheckCmd = &cli.Command{
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ainfo := lcli.APIInfo{Addr: apima}
|
||||
ainfo := cliutil.APIInfo{Addr: apima.String()}
|
||||
addr, err := ainfo.DialArgs()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -83,7 +83,7 @@ var exportChainCmd = &cli.Command{
|
||||
|
||||
bs := blockstore.NewBlockstore(ds)
|
||||
|
||||
cs := store.NewChainStore(bs, mds, nil)
|
||||
cs := store.NewChainStore(bs, mds, nil, nil)
|
||||
if err := cs.Load(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user