Merge branch 'master' into ntwk-calibration
This commit is contained in:
commit
de1038ecc3
1
.gitignore
vendored
1
.gitignore
vendored
@ -12,6 +12,7 @@
|
|||||||
/lotus-bench
|
/lotus-bench
|
||||||
/lotus-gateway
|
/lotus-gateway
|
||||||
/lotus-pcr
|
/lotus-pcr
|
||||||
|
/lotus-wallet
|
||||||
/bench.json
|
/bench.json
|
||||||
/lotuspond/front/node_modules
|
/lotuspond/front/node_modules
|
||||||
/lotuspond/front/build
|
/lotuspond/front/build
|
||||||
|
115
CHANGELOG.md
115
CHANGELOG.md
@ -1,5 +1,118 @@
|
|||||||
# Lotus changelog
|
# Lotus changelog
|
||||||
|
|
||||||
|
# 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:
|
||||||
|
|
||||||
|
- Introducing v2 actors and its migration (https://github.com/filecoin-project/lotus/pull/3936)
|
||||||
|
- Runtime's Receiver() should only return ID addresses (https://github.com/filecoin-project/lotus/pull/3589)
|
||||||
|
- Update miner eligibility checks for v2 actors (https://github.com/filecoin-project/lotus/pull/4188)
|
||||||
|
- Add funds that have left FilReserve to circ supply (https://github.com/filecoin-project/lotus/pull/4160)
|
||||||
|
- Set WinningPoStSectorSetLookback to finality post-v2 actors (https://github.com/filecoin-project/lotus/pull/4190)
|
||||||
|
- fix: error when actor panics directly (https://github.com/filecoin-project/lotus/pull/3697)
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
#### Dependencies
|
||||||
|
|
||||||
|
- Update go-bitfield (https://github.com/filecoin-project/lotus/pull/4171)
|
||||||
|
- update the AMT implementation (https://github.com/filecoin-project/lotus/pull/4194)
|
||||||
|
- Update to actors v0.2.1 (https://github.com/filecoin-project/lotus/pull/4199)
|
||||||
|
|
||||||
|
#### Core Lotus
|
||||||
|
|
||||||
|
- Paych: fix voucher amount verification (https://github.com/filecoin-project/lotus/pull/3821)
|
||||||
|
- Cap market provider messages (https://github.com/filecoin-project/lotus/pull/4141)
|
||||||
|
- Run fork function after cron for null block safety (https://github.com/filecoin-project/lotus/pull/4114)
|
||||||
|
- use bitswap sessions when fetching messages, and cancel them (https://github.com/filecoin-project/lotus/pull/4142)
|
||||||
|
- relax pubsub IPColocationFactorThreshold to 5 (https://github.com/filecoin-project/lotus/pull/4183)
|
||||||
|
- Support addresses with mainnet prefixes (https://github.com/filecoin-project/lotus/pull/4186)
|
||||||
|
- fix: make message signer nonce generation transactional (https://github.com/filecoin-project/lotus/pull/4165)
|
||||||
|
- build: Env var to keep test address output (https://github.com/filecoin-project/lotus/pull/4213)
|
||||||
|
- make vm.EnableGasTracing public (https://github.com/filecoin-project/lotus/pull/4214)
|
||||||
|
- introduce separate state-tree versions (https://github.com/filecoin-project/lotus/pull/4197)
|
||||||
|
- reject explicit "calls" at the upgrade height (https://github.com/filecoin-project/lotus/pull/4231)
|
||||||
|
- return an illegal actor error when we see an unsupported actor version (https://github.com/filecoin-project/lotus/pull/4232)
|
||||||
|
- Set head should unmark blocks as valid (https://gist.github.com/travisperson/3c7cddd77a33979a519ccef4e6515f20)
|
||||||
|
|
||||||
|
#### Mining
|
||||||
|
|
||||||
|
- Increased ExpectedSealDuration and and WaitDealsDelay (https://github.com/filecoin-project/lotus/pull/3743)
|
||||||
|
- Miner backup/restore commands (https://github.com/filecoin-project/lotus/pull/4133)
|
||||||
|
- lotus-miner: add more help text to storage / attach (https://github.com/filecoin-project/lotus/pull/3961)
|
||||||
|
- Reject deals that are > 7 days in the future in the BasicDealFilter (https://github.com/filecoin-project/lotus/pull/4173)
|
||||||
|
- feat(miner): add miner deadline diffing logic (https://github.com/filecoin-project/lotus/pull/4178)
|
||||||
|
|
||||||
|
#### UX
|
||||||
|
|
||||||
|
- Improve the UX for replacing messages (https://github.com/filecoin-project/lotus/pull/4134)
|
||||||
|
- Add verified flag to interactive deal creation (https://github.com/filecoin-project/lotus/pull/4145)
|
||||||
|
- Add command to (slowly) prune lotus chain datastore (https://github.com/filecoin-project/lotus/pull/3876)
|
||||||
|
- Some helpers for verifreg work (https://github.com/filecoin-project/lotus/pull/4124)
|
||||||
|
- Always use default 720h for setask duration and hide the duration param option (https://github.com/filecoin-project/lotus/pull/4077)
|
||||||
|
- Convert ID addresses to key addresses before checking wallet (https://github.com/filecoin-project/lotus/pull/4122)
|
||||||
|
- add a command to view block space utilization (https://github.com/filecoin-project/lotus/pull/4176)
|
||||||
|
- allow usage inspection on a chain segment (https://github.com/filecoin-project/lotus/pull/4177)
|
||||||
|
- Add mpool stats for base fee (https://github.com/filecoin-project/lotus/pull/4170)
|
||||||
|
- Add verified status to api.DealInfo (https://github.com/filecoin-project/lotus/pull/4153)
|
||||||
|
- Add a CLI command to set a miner's owner address (https://github.com/filecoin-project/lotus/pull/4189)
|
||||||
|
|
||||||
|
#### Tooling and validation
|
||||||
|
|
||||||
|
- Lotus-pcr: add recover-miners command (https://github.com/filecoin-project/lotus/pull/3714)
|
||||||
|
- MpoolPushUntrusted API for gateway (https://github.com/filecoin-project/lotus/pull/3915)
|
||||||
|
- Test lotus-miner info all (https://github.com/filecoin-project/lotus/pull/4166)
|
||||||
|
- chain export: Error with unfinished exports (https://github.com/filecoin-project/lotus/pull/4179)
|
||||||
|
- add printf in TestWindowPost (https://github.com/filecoin-project/lotus/pull/4043)
|
||||||
|
- add trace wdpost (https://github.com/filecoin-project/lotus/pull/4020)
|
||||||
|
- Fix noncefix (https://github.com/filecoin-project/lotus/pull/4202)
|
||||||
|
- Lotus-pcr: Limit the fee cap of messages we will process, refund gas fees for windowed post and storage deals (https://github.com/filecoin-project/lotus/pull/4198)
|
||||||
|
- Fix pond (https://github.com/filecoin-project/lotus/pull/4203)
|
||||||
|
- allow manual setting of noncefix fee cap (https://github.com/filecoin-project/lotus/pull/4205)
|
||||||
|
- implement command to get execution traces of any message (https://github.com/filecoin-project/lotus/pull/4200)
|
||||||
|
- conformance: minor driver refactors (https://github.com/filecoin-project/lotus/pull/4211)
|
||||||
|
- lotus-pcr: ignore all other messages (https://github.com/filecoin-project/lotus/pull/4218)
|
||||||
|
- lotus-pcr: zero refund (https://github.com/filecoin-project/lotus/pull/4229)
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
The following contributors had 5 or more commits go into this release.
|
||||||
|
We are grateful for every contribution!
|
||||||
|
|
||||||
|
| Contributor | Commits | Lines ± |
|
||||||
|
|--------------------|---------|---------------|
|
||||||
|
| Stebalien | 84 | +3425/-2287 |
|
||||||
|
| magik6k | 41 | +2121/-506 |
|
||||||
|
| arajasek | 39 | +2467/-424 |
|
||||||
|
| Kubuxu | 25 | +2344/-775 |
|
||||||
|
| raulk | 21 | +287/-196 |
|
||||||
|
| whyrusleeping | 13 | +727/-71 |
|
||||||
|
| hsanjuan | 13 | +5886/-7956 |
|
||||||
|
| dirkmc | 11 | +2634/-576 |
|
||||||
|
| travisperson | 8 | +923/-202 |
|
||||||
|
| ribasushi | 6 | +188/-128 |
|
||||||
|
| zgfzgf | 5 | +21/-17 |
|
||||||
|
|
||||||
# 0.8.1 / 2020-09-30
|
# 0.8.1 / 2020-09-30
|
||||||
|
|
||||||
This optional release of Lotus introduces a new version of markets which switches to CBOR-map encodings, and allows datastore migrations. The release also introduces several improvements to the mining process, a few performance optimizations, and a battery of UX additions and enhancements.
|
This optional release of Lotus introduces a new version of markets which switches to CBOR-map encodings, and allows datastore migrations. The release also introduces several improvements to the mining process, a few performance optimizations, and a battery of UX additions and enhancements.
|
||||||
@ -117,7 +230,7 @@ We are grateful for every contribution!
|
|||||||
| vyzo | 22 | +287/-196 |
|
| vyzo | 22 | +287/-196 |
|
||||||
| alanshaw | 15 | +761/-146 |
|
| alanshaw | 15 | +761/-146 |
|
||||||
| whyrusleeping | 15 | +736/-52 |
|
| whyrusleeping | 15 | +736/-52 |
|
||||||
| hannahhoward | 14 | +1237/837- |
|
| hannahhoward | 14 | +1237/-837 |
|
||||||
| anton | 6 | +32/-8 |
|
| anton | 6 | +32/-8 |
|
||||||
| travisperson | 5 | +502/-6 |
|
| travisperson | 5 | +502/-6 |
|
||||||
| Frank | 5 | +78/-39 |
|
| Frank | 5 | +78/-39 |
|
||||||
|
6
Makefile
6
Makefile
@ -186,6 +186,12 @@ lotus-health:
|
|||||||
.PHONY: lotus-health
|
.PHONY: lotus-health
|
||||||
BINS+=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:
|
testground:
|
||||||
go build -tags testground -o /dev/null ./cmd/lotus
|
go build -tags testground -o /dev/null ./cmd/lotus
|
||||||
.PHONY: testground
|
.PHONY: testground
|
||||||
|
@ -172,6 +172,9 @@ type FullNode interface {
|
|||||||
// SyncUnmarkBad unmarks a blocks as bad, making it possible to be validated and synced again.
|
// SyncUnmarkBad unmarks a blocks as bad, making it possible to be validated and synced again.
|
||||||
SyncUnmarkBad(ctx context.Context, bcid cid.Cid) error
|
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
|
// SyncCheckBad checks if a block was marked as bad, and if it was, returns
|
||||||
// the reason.
|
// the reason.
|
||||||
SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error)
|
SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error)
|
||||||
@ -367,6 +370,10 @@ type FullNode interface {
|
|||||||
// StateWaitMsg looks back in the chain for a message. If not found, it blocks until the
|
// 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.
|
// message arrives on chain, and gets to the indicated confidence depth.
|
||||||
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*MsgLookup, error)
|
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 returns the addresses of every miner that has claimed power in the Power Actor
|
||||||
StateListMiners(context.Context, types.TipSetKey) ([]address.Address, error)
|
StateListMiners(context.Context, types.TipSetKey) ([]address.Address, error)
|
||||||
// StateListActors returns the addresses of every actor in the state
|
// StateListActors returns the addresses of every actor in the state
|
||||||
@ -418,6 +425,8 @@ type FullNode interface {
|
|||||||
|
|
||||||
// MsigGetAvailableBalance returns the portion of a multisig's balance that can be withdrawn or spent
|
// MsigGetAvailableBalance returns the portion of a multisig's balance that can be withdrawn or spent
|
||||||
MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
|
MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
|
||||||
|
// 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.
|
// 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>
|
// It takes the following params: <multisig address>, <start epoch>, <end epoch>
|
||||||
MsigGetVested(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error)
|
MsigGetVested(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error)
|
||||||
@ -429,12 +438,21 @@ type FullNode interface {
|
|||||||
// It takes the following params: <multisig address>, <recipient address>, <value to transfer>,
|
// 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>
|
// <sender address of the propose msg>, <method to call in the proposed message>, <params to include in the proposed message>
|
||||||
MsigPropose(context.Context, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
|
MsigPropose(context.Context, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
|
||||||
// MsigApprove approves a previously-proposed multisig message
|
|
||||||
|
// 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>,
|
// 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>
|
// <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
|
// 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>
|
// <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)
|
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
|
// MsigAddPropose proposes adding a signer in the multisig
|
||||||
@ -462,6 +480,13 @@ type FullNode interface {
|
|||||||
// <old signer>, <new signer>
|
// <old signer>, <new signer>
|
||||||
MsigSwapCancel(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error)
|
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)
|
MarketEnsureAvailable(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error)
|
||||||
// MarketFreeBalance
|
// MarketFreeBalance
|
||||||
|
|
||||||
@ -871,3 +896,15 @@ type Fault struct {
|
|||||||
Miner address.Address
|
Miner address.Address
|
||||||
Epoch abi.ChainEpoch
|
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
|
||||||
|
}
|
||||||
|
24
api/api_gateway.go
Normal file
24
api/api_gateway.go
Normal file
@ -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)
|
||||||
|
}
|
47
api/api_wallet.go
Normal file
47
api/api_wallet.go
Normal file
@ -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, crypto.SigType) (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)
|
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal)
|
||||||
return &out
|
return &out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PermissionedWalletAPI(a api.WalletAPI) api.WalletAPI {
|
||||||
|
var out WalletStruct
|
||||||
|
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal)
|
||||||
|
return &out
|
||||||
|
}
|
||||||
|
@ -111,6 +111,7 @@ type FullNodeStruct struct {
|
|||||||
SyncCheckpoint func(ctx context.Context, key types.TipSetKey) error `perm:"admin"`
|
SyncCheckpoint func(ctx context.Context, key types.TipSetKey) error `perm:"admin"`
|
||||||
SyncMarkBad func(ctx context.Context, bcid cid.Cid) 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"`
|
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"`
|
SyncCheckBad func(ctx context.Context, bcid cid.Cid) (string, error) `perm:"read"`
|
||||||
SyncValidateTipset func(ctx context.Context, tsk types.TipSetKey) (bool, error) `perm:"read"`
|
SyncValidateTipset func(ctx context.Context, tsk types.TipSetKey) (bool, error) `perm:"read"`
|
||||||
|
|
||||||
@ -190,6 +191,7 @@ type FullNodeStruct struct {
|
|||||||
StateReadState func(context.Context, address.Address, types.TipSetKey) (*api.ActorState, error) `perm:"read"`
|
StateReadState func(context.Context, address.Address, types.TipSetKey) (*api.ActorState, error) `perm:"read"`
|
||||||
StateMsgGasCost func(context.Context, cid.Cid, types.TipSetKey) (*api.MsgGasCost, error) `perm:"read"`
|
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"`
|
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"`
|
StateSearchMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"`
|
||||||
StateListMiners func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
|
StateListMiners func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
|
||||||
StateListActors func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
|
StateListActors func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
|
||||||
@ -212,10 +214,12 @@ type FullNodeStruct struct {
|
|||||||
StateNetworkVersion func(context.Context, types.TipSetKey) (stnetwork.Version, 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"`
|
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"`
|
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"`
|
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"`
|
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"`
|
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"`
|
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"`
|
MsigAddApprove func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, bool) (cid.Cid, error) `perm:"sign"`
|
||||||
@ -223,6 +227,7 @@ type FullNodeStruct struct {
|
|||||||
MsigSwapPropose func(context.Context, address.Address, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
MsigSwapPropose func(context.Context, address.Address, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||||
MsigSwapApprove func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
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"`
|
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"`
|
MarketEnsureAvailable func(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"`
|
||||||
|
|
||||||
@ -360,6 +365,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, crypto.SigType) (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
|
// CommonStruct
|
||||||
|
|
||||||
func (c *CommonStruct) AuthVerify(ctx context.Context, token string) ([]auth.Permission, error) {
|
func (c *CommonStruct) AuthVerify(ctx context.Context, token string) ([]auth.Permission, error) {
|
||||||
@ -749,6 +783,10 @@ func (c *FullNodeStruct) SyncUnmarkBad(ctx context.Context, bcid cid.Cid) error
|
|||||||
return c.Internal.SyncUnmarkBad(ctx, bcid)
|
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) {
|
func (c *FullNodeStruct) SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error) {
|
||||||
return c.Internal.SyncCheckBad(ctx, bcid)
|
return c.Internal.SyncCheckBad(ctx, bcid)
|
||||||
}
|
}
|
||||||
@ -853,6 +891,10 @@ func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid, confide
|
|||||||
return c.Internal.StateWaitMsg(ctx, msgc, confidence)
|
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) {
|
func (c *FullNodeStruct) StateSearchMsg(ctx context.Context, msgc cid.Cid) (*api.MsgLookup, error) {
|
||||||
return c.Internal.StateSearchMsg(ctx, msgc)
|
return c.Internal.StateSearchMsg(ctx, msgc)
|
||||||
}
|
}
|
||||||
@ -933,6 +975,10 @@ func (c *FullNodeStruct) MsigGetAvailableBalance(ctx context.Context, a address.
|
|||||||
return c.Internal.MsigGetAvailableBalance(ctx, a, tsk)
|
return c.Internal.MsigGetAvailableBalance(ctx, a, tsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *FullNodeStruct) 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) {
|
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)
|
return c.Internal.MsigGetVested(ctx, a, sTsk, eTsk)
|
||||||
}
|
}
|
||||||
@ -945,8 +991,12 @@ func (c *FullNodeStruct) MsigPropose(ctx context.Context, msig address.Address,
|
|||||||
return c.Internal.MsigPropose(ctx, msig, to, amt, src, method, params)
|
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) {
|
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, proposer, to, amt, src, method, params)
|
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) {
|
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 +1027,10 @@ func (c *FullNodeStruct) MsigSwapCancel(ctx context.Context, msig address.Addres
|
|||||||
return c.Internal.MsigSwapCancel(ctx, msig, src, txID, oldAdd, newAdd)
|
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) {
|
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)
|
return c.Internal.MarketEnsureAvailable(ctx, addr, wallet, amt)
|
||||||
}
|
}
|
||||||
@ -1367,7 +1421,81 @@ func (w *WorkerStruct) Closing(ctx context.Context) (<-chan struct{}, error) {
|
|||||||
return w.Internal.Closing(ctx)
|
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 crypto.SigType) (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.Common = &CommonStruct{}
|
||||||
var _ api.FullNode = &FullNodeStruct{}
|
var _ api.FullNode = &FullNodeStruct{}
|
||||||
var _ api.StorageMiner = &StorageMinerStruct{}
|
var _ api.StorageMiner = &StorageMinerStruct{}
|
||||||
var _ api.WorkerAPI = &WorkerStruct{}
|
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
|
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
|
||||||
|
}
|
||||||
|
@ -12,10 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"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/chain/types"
|
||||||
"github.com/filecoin-project/lotus/node"
|
|
||||||
"github.com/filecoin-project/lotus/node/impl"
|
"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) {
|
func testCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration, upgradeHeight abi.ChainEpoch) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
n, sn := b(t, 1, OneMiner, node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{
|
n, sn := b(t, []FullNodeOpts{FullNodeWithUpgradeAt(upgradeHeight)}, OneMiner)
|
||||||
Network: build.ActorUpgradeNetworkVersion,
|
|
||||||
Height: upgradeHeight,
|
|
||||||
Migration: stmgr.UpgradeActorsV2,
|
|
||||||
}}))
|
|
||||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||||
miner := sn[0]
|
miner := sn[0]
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport
|
|||||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
n, sn := b(t, 1, OneMiner)
|
n, sn := b(t, OneFull, OneMiner)
|
||||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||||
miner := sn[0]
|
miner := sn[0]
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
|||||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
n, sn := b(t, 1, OneMiner)
|
n, sn := b(t, OneFull, OneMiner)
|
||||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||||
miner := sn[0]
|
miner := sn[0]
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ func TestFastRetrievalDealFlow(t *testing.T, b APIBuilder, blocktime time.Durati
|
|||||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
n, sn := b(t, 1, OneMiner)
|
n, sn := b(t, OneFull, OneMiner)
|
||||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||||
miner := sn[0]
|
miner := sn[0]
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ func TestSenondDealRetrieval(t *testing.T, b APIBuilder, blocktime time.Duration
|
|||||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
n, sn := b(t, 1, OneMiner)
|
n, sn := b(t, OneFull, OneMiner)
|
||||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||||
miner := sn[0]
|
miner := sn[0]
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ var log = logging.Logger("apitest")
|
|||||||
|
|
||||||
func (ts *testSuite) testMining(t *testing.T) {
|
func (ts *testSuite) testMining(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
apis, sn := ts.makeNodes(t, 1, OneMiner)
|
apis, sn := ts.makeNodes(t, OneFull, OneMiner)
|
||||||
api := apis[0]
|
api := apis[0]
|
||||||
|
|
||||||
newHeads, err := api.ChainNotify(ctx)
|
newHeads, err := api.ChainNotify(ctx)
|
||||||
@ -54,7 +54,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
apis, sn := ts.makeNodes(t, 1, OneMiner)
|
apis, sn := ts.makeNodes(t, OneFull, OneMiner)
|
||||||
api := apis[0]
|
api := apis[0]
|
||||||
|
|
||||||
newHeads, err := api.ChainNotify(ctx)
|
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
|
// test making a deal with a fresh miner, and see if it starts to mine
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
n, sn := b(t, 1, []StorageMiner{
|
n, sn := b(t, OneFull, []StorageMiner{
|
||||||
{Full: 0, Preseal: PresealGenesis},
|
{Full: 0, Preseal: PresealGenesis},
|
||||||
{Full: 0, Preseal: 0}, // TODO: Add support for miners on non-first full node
|
{Full: 0, Preseal: 0}, // TODO: Add support for miners on non-first full node
|
||||||
})
|
})
|
||||||
|
@ -33,7 +33,7 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
|||||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
n, sn := b(t, 2, OneMiner)
|
n, sn := b(t, TwoFull, OneMiner)
|
||||||
|
|
||||||
paymentCreator := n[0]
|
paymentCreator := n[0]
|
||||||
paymentReceiver := n[1]
|
paymentReceiver := n[1]
|
||||||
|
@ -4,11 +4,14 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
|
|
||||||
"github.com/multiformats/go-multiaddr"
|
"github.com/multiformats/go-multiaddr"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/miner"
|
"github.com/filecoin-project/lotus/miner"
|
||||||
@ -35,17 +38,27 @@ var PresealGenesis = -1
|
|||||||
|
|
||||||
const GenesisPreseals = 2
|
const GenesisPreseals = 2
|
||||||
|
|
||||||
|
// Options for setting up a mock storage miner
|
||||||
type StorageMiner struct {
|
type StorageMiner struct {
|
||||||
Full int
|
Full int
|
||||||
Preseal 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
|
// APIBuilder is a function which is invoked in test suite to provide
|
||||||
// test nodes and networks
|
// test nodes and networks
|
||||||
//
|
//
|
||||||
|
// fullOpts array defines options for each full node
|
||||||
// storage array defines storage nodes, numbers in the array specify full node
|
// storage array defines storage nodes, numbers in the array specify full node
|
||||||
// index the storage node 'belongs' to
|
// 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 {
|
type testSuite struct {
|
||||||
makeNodes APIBuilder
|
makeNodes APIBuilder
|
||||||
}
|
}
|
||||||
@ -63,13 +76,39 @@ func TestApis(t *testing.T, b APIBuilder) {
|
|||||||
t.Run("testMiningReal", ts.testMiningReal)
|
t.Run("testMiningReal", ts.testMiningReal)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 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{{
|
||||||
|
Network: build.ActorUpgradeNetworkVersion,
|
||||||
|
Height: upgradeHeight,
|
||||||
|
Migration: stmgr.UpgradeActorsV2,
|
||||||
|
}})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (ts *testSuite) testVersion(t *testing.T) {
|
func (ts *testSuite) testVersion(t *testing.T) {
|
||||||
build.RunningNodeType = build.NodeFull
|
build.RunningNodeType = build.NodeFull
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
apis, _ := ts.makeNodes(t, 1, OneMiner)
|
apis, _ := ts.makeNodes(t, OneFull, OneMiner)
|
||||||
api := apis[0]
|
api := apis[0]
|
||||||
|
|
||||||
v, err := api.Version(ctx)
|
v, err := api.Version(ctx)
|
||||||
@ -81,7 +120,7 @@ func (ts *testSuite) testVersion(t *testing.T) {
|
|||||||
|
|
||||||
func (ts *testSuite) testID(t *testing.T) {
|
func (ts *testSuite) testID(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
apis, _ := ts.makeNodes(t, 1, OneMiner)
|
apis, _ := ts.makeNodes(t, OneFull, OneMiner)
|
||||||
api := apis[0]
|
api := apis[0]
|
||||||
|
|
||||||
id, err := api.ID(ctx)
|
id, err := api.ID(ctx)
|
||||||
@ -93,7 +132,7 @@ func (ts *testSuite) testID(t *testing.T) {
|
|||||||
|
|
||||||
func (ts *testSuite) testConnectTwo(t *testing.T) {
|
func (ts *testSuite) testConnectTwo(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
apis, _ := ts.makeNodes(t, 2, OneMiner)
|
apis, _ := ts.makeNodes(t, TwoFull, OneMiner)
|
||||||
|
|
||||||
p, err := apis[0].NetPeers(ctx)
|
p, err := apis[0].NetPeers(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -3,6 +3,7 @@ package test
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
@ -15,11 +16,9 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/lotus/extern/sector-storage/mock"
|
"github.com/filecoin-project/lotus/extern/sector-storage/mock"
|
||||||
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
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/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
bminer "github.com/filecoin-project/lotus/miner"
|
bminer "github.com/filecoin-project/lotus/miner"
|
||||||
"github.com/filecoin-project/lotus/node/impl"
|
"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) {
|
func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) {
|
||||||
ctx := context.Background()
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
n, sn := b(t, 1, OneMiner)
|
defer cancel()
|
||||||
|
|
||||||
|
n, sn := b(t, OneFull, OneMiner)
|
||||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||||
miner := sn[0]
|
miner := sn[0]
|
||||||
|
|
||||||
@ -48,11 +49,11 @@ func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSect
|
|||||||
}
|
}
|
||||||
build.Clock.Sleep(time.Second)
|
build.Clock.Sleep(time.Second)
|
||||||
|
|
||||||
mine := true
|
mine := int64(1)
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
defer close(done)
|
defer close(done)
|
||||||
for mine {
|
for atomic.LoadInt64(&mine) != 0 {
|
||||||
build.Clock.Sleep(blocktime)
|
build.Clock.Sleep(blocktime)
|
||||||
if err := sn[0].MineOne(ctx, bminer.MineReq{Done: func(bool, abi.ChainEpoch, error) {
|
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)
|
pledgeSectors(t, ctx, miner, nSectors, 0, nil)
|
||||||
|
|
||||||
mine = false
|
atomic.StoreInt64(&mine, 0)
|
||||||
<-done
|
<-done
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,11 +134,7 @@ func testWindowPostUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration,
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
n, sn := b(t, 1, OneMiner, node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{
|
n, sn := b(t, []FullNodeOpts{FullNodeWithUpgradeAt(upgradeHeight)}, OneMiner)
|
||||||
Network: build.ActorUpgradeNetworkVersion,
|
|
||||||
Height: upgradeHeight,
|
|
||||||
Migration: stmgr.UpgradeActorsV2,
|
|
||||||
}}))
|
|
||||||
|
|
||||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||||
miner := sn[0]
|
miner := sn[0]
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
package build
|
package build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||||
@ -13,8 +16,10 @@ const BreezeGasTampingDuration = 0
|
|||||||
|
|
||||||
const UpgradeSmokeHeight = -1
|
const UpgradeSmokeHeight = -1
|
||||||
const UpgradeIgnitionHeight = -2
|
const UpgradeIgnitionHeight = -2
|
||||||
const UpgradeLiftoffHeight = -3
|
const UpgradeRefuelHeight = -3
|
||||||
const UpgradeActorsV2Height = 10
|
|
||||||
|
var UpgradeActorsV2Height = abi.ChainEpoch(10)
|
||||||
|
var UpgradeLiftoffHeight = abi.ChainEpoch(-4)
|
||||||
|
|
||||||
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||||
0: DrandMainnet,
|
0: DrandMainnet,
|
||||||
@ -25,6 +30,11 @@ func init() {
|
|||||||
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
|
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
|
||||||
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
|
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
|
||||||
|
|
||||||
|
if os.Getenv("LOTUS_DISABLE_V2_ACTOR_MIGRATION") == "1" {
|
||||||
|
UpgradeActorsV2Height = math.MaxInt64
|
||||||
|
UpgradeLiftoffHeight = 11
|
||||||
|
}
|
||||||
|
|
||||||
BuildType |= Build2k
|
BuildType |= Build2k
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,8 +82,9 @@ var (
|
|||||||
|
|
||||||
UpgradeSmokeHeight abi.ChainEpoch = -1
|
UpgradeSmokeHeight abi.ChainEpoch = -1
|
||||||
UpgradeIgnitionHeight abi.ChainEpoch = -2
|
UpgradeIgnitionHeight abi.ChainEpoch = -2
|
||||||
UpgradeLiftoffHeight abi.ChainEpoch = -3
|
UpgradeRefuelHeight abi.ChainEpoch = -3
|
||||||
UpgradeActorsV2Height abi.ChainEpoch = 10
|
UpgradeActorsV2Height abi.ChainEpoch = 10
|
||||||
|
UpgradeLiftoffHeight abi.ChainEpoch = -4
|
||||||
|
|
||||||
DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||||
0: DrandMainnet,
|
0: DrandMainnet,
|
||||||
|
@ -29,7 +29,7 @@ func buildType() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BuildVersion is the local build version, set by build system
|
// BuildVersion is the local build version, set by build system
|
||||||
const BuildVersion = "0.8.1"
|
const BuildVersion = "0.9.1"
|
||||||
|
|
||||||
func UserVersion() string {
|
func UserVersion() string {
|
||||||
return BuildVersion + buildType() + CurrentCommit
|
return BuildVersion + buildType() + CurrentCommit
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
var SystemActorAddr = builtin0.SystemActorAddr
|
var SystemActorAddr = builtin0.SystemActorAddr
|
||||||
var BurntFundsActorAddr = builtin0.BurntFundsActorAddr
|
var BurntFundsActorAddr = builtin0.BurntFundsActorAddr
|
||||||
var ReserveAddress = makeAddress("t090")
|
var ReserveAddress = makeAddress("t090")
|
||||||
|
var RootVerifierAddress = makeAddress("t080")
|
||||||
|
|
||||||
// TODO: Why does actors have 2 different versions of this?
|
// TODO: Why does actors have 2 different versions of this?
|
||||||
type SectorInfo = proof0.SectorInfo
|
type SectorInfo = proof0.SectorInfo
|
||||||
|
180
chain/actors/builtin/miner/diff_deadlines.go
Normal file
180
chain/actors/builtin/miner/diff_deadlines.go
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
package miner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-bitfield"
|
||||||
|
"github.com/filecoin-project/go-state-types/exitcode"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeadlinesDiff map[uint64]*DeadlineDiff
|
||||||
|
|
||||||
|
func DiffDeadlines(pre, cur State) (*DeadlinesDiff, error) {
|
||||||
|
changed, err := pre.DeadlinesChanged(cur)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !changed {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
numDl, err := pre.NumDeadlines()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dlDiff := make(DeadlinesDiff, numDl)
|
||||||
|
if err := pre.ForEachDeadline(func(idx uint64, preDl Deadline) error {
|
||||||
|
curDl, err := cur.LoadDeadline(idx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
diff, err := DiffDeadline(preDl, curDl)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
dlDiff[idx] = diff
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &dlDiff, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeadlineDiff map[uint64]*PartitionDiff
|
||||||
|
|
||||||
|
func DiffDeadline(pre, cur Deadline) (*DeadlineDiff, error) {
|
||||||
|
changed, err := pre.PartitionsChanged(cur)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !changed {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
partDiff := make(DeadlineDiff)
|
||||||
|
if err := pre.ForEachPartition(func(idx uint64, prePart Partition) error {
|
||||||
|
// try loading current partition at this index
|
||||||
|
curPart, err := cur.LoadPartition(idx)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, exitcode.ErrNotFound) {
|
||||||
|
// TODO correctness?
|
||||||
|
return nil // the partition was removed.
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// compare it with the previous partition
|
||||||
|
diff, err := DiffPartition(prePart, curPart)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
partDiff[idx] = diff
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// all previous partitions have been walked.
|
||||||
|
// all partitions in cur and not in prev are new... can they be faulty already?
|
||||||
|
// TODO is this correct?
|
||||||
|
if err := cur.ForEachPartition(func(idx uint64, curPart Partition) error {
|
||||||
|
if _, found := partDiff[idx]; found {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
faults, err := curPart.FaultySectors()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
recovering, err := curPart.RecoveringSectors()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
partDiff[idx] = &PartitionDiff{
|
||||||
|
Removed: bitfield.New(),
|
||||||
|
Recovered: bitfield.New(),
|
||||||
|
Faulted: faults,
|
||||||
|
Recovering: recovering,
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &partDiff, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type PartitionDiff struct {
|
||||||
|
Removed bitfield.BitField
|
||||||
|
Recovered bitfield.BitField
|
||||||
|
Faulted bitfield.BitField
|
||||||
|
Recovering bitfield.BitField
|
||||||
|
}
|
||||||
|
|
||||||
|
func DiffPartition(pre, cur Partition) (*PartitionDiff, error) {
|
||||||
|
prevLiveSectors, err := pre.LiveSectors()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
curLiveSectors, err := cur.LiveSectors()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
removed, err := bitfield.SubtractBitField(prevLiveSectors, curLiveSectors)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
prevRecoveries, err := pre.RecoveringSectors()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
curRecoveries, err := cur.RecoveringSectors()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
recovering, err := bitfield.SubtractBitField(curRecoveries, prevRecoveries)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
prevFaults, err := pre.FaultySectors()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
curFaults, err := cur.FaultySectors()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
faulted, err := bitfield.SubtractBitField(curFaults, prevFaults)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// all current good sectors
|
||||||
|
curActiveSectors, err := cur.ActiveSectors()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// sectors that were previously fault and are now currently active are considered recovered.
|
||||||
|
recovered, err := bitfield.IntersectBitField(prevFaults, curActiveSectors)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &PartitionDiff{
|
||||||
|
Removed: removed,
|
||||||
|
Recovered: recovered,
|
||||||
|
Faulted: faulted,
|
||||||
|
Recovering: recovering,
|
||||||
|
}, nil
|
||||||
|
}
|
@ -51,6 +51,7 @@ type State interface {
|
|||||||
MinerPower(address.Address) (Claim, bool, error)
|
MinerPower(address.Address) (Claim, bool, error)
|
||||||
MinerNominalPowerMeetsConsensusMinimum(address.Address) (bool, error)
|
MinerNominalPowerMeetsConsensusMinimum(address.Address) (bool, error)
|
||||||
ListAllMiners() ([]address.Address, error)
|
ListAllMiners() ([]address.Address, error)
|
||||||
|
ForEachClaim(func(miner address.Address, claim Claim) error) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Claim struct {
|
type Claim struct {
|
||||||
|
@ -96,3 +96,22 @@ func (s *state0) ListAllMiners() ([]address.Address, error) {
|
|||||||
|
|
||||||
return miners, nil
|
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
|
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) {
|
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) {
|
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) {
|
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) {
|
func (s *state2) InitialPledgeForPower(qaPower abi.StoragePower, networkTotalPledge abi.TokenAmount, networkQAPower *builtin.FilterEstimate, circSupply abi.TokenAmount) (abi.TokenAmount, error) {
|
||||||
|
@ -9,8 +9,8 @@ import (
|
|||||||
type Version int
|
type Version int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version0 = 0
|
Version0 Version = 0
|
||||||
Version2 = 2
|
Version2 Version = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
// Converts a network version into an actors adt version.
|
// Converts a network version into an actors adt version.
|
||||||
|
@ -60,6 +60,10 @@ func (bts *BadBlockCache) Remove(c cid.Cid) {
|
|||||||
bts.badBlocks.Remove(c)
|
bts.badBlocks.Remove(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (bts *BadBlockCache) Purge() {
|
||||||
|
bts.badBlocks.Purge()
|
||||||
|
}
|
||||||
|
|
||||||
func (bts *BadBlockCache) Has(c cid.Cid) (BadBlockReason, bool) {
|
func (bts *BadBlockCache) Has(c cid.Cid) (BadBlockReason, bool) {
|
||||||
rval, ok := bts.badBlocks.Get(c)
|
rval, ok := bts.badBlocks.Get(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -2,6 +2,7 @@ package events
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
@ -17,6 +18,8 @@ type tsCacheAPI interface {
|
|||||||
// tipSetCache implements a simple ring-buffer cache to keep track of recent
|
// tipSetCache implements a simple ring-buffer cache to keep track of recent
|
||||||
// tipsets
|
// tipsets
|
||||||
type tipSetCache struct {
|
type tipSetCache struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
|
||||||
cache []*types.TipSet
|
cache []*types.TipSet
|
||||||
start int
|
start int
|
||||||
len int
|
len int
|
||||||
@ -35,6 +38,9 @@ func newTSCache(cap abi.ChainEpoch, storage tsCacheAPI) *tipSetCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tsc *tipSetCache) add(ts *types.TipSet) error {
|
func (tsc *tipSetCache) add(ts *types.TipSet) error {
|
||||||
|
tsc.mu.Lock()
|
||||||
|
defer tsc.mu.Unlock()
|
||||||
|
|
||||||
if tsc.len > 0 {
|
if tsc.len > 0 {
|
||||||
if tsc.cache[tsc.start].Height() >= ts.Height() {
|
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())
|
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 {
|
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 {
|
if tsc.len == 0 {
|
||||||
return nil // this can happen, and it's fine
|
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.start = normalModulo(tsc.start-1, len(tsc.cache))
|
||||||
tsc.len--
|
tsc.len--
|
||||||
|
|
||||||
_ = tsc.revert(nil) // revert null block gap
|
_ = tsc.revertUnlocked(nil) // revert null block gap
|
||||||
return nil
|
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) {
|
func (tsc *tipSetCache) get(height abi.ChainEpoch) (*types.TipSet, error) {
|
||||||
|
tsc.mu.RLock()
|
||||||
|
|
||||||
if tsc.len == 0 {
|
if tsc.len == 0 {
|
||||||
|
tsc.mu.RUnlock()
|
||||||
log.Warnf("tipSetCache.get: cache is empty, requesting from storage (h=%d)", height)
|
log.Warnf("tipSetCache.get: cache is empty, requesting from storage (h=%d)", height)
|
||||||
return tsc.storage.ChainGetTipSetByHeight(context.TODO(), height, types.EmptyTSK)
|
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()
|
headH := tsc.cache[tsc.start].Height()
|
||||||
|
|
||||||
if height > headH {
|
if height > headH {
|
||||||
|
tsc.mu.RUnlock()
|
||||||
return nil, xerrors.Errorf("tipSetCache.get: requested tipset not in cache (req: %d, cache head: %d)", height, headH)
|
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() {
|
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())
|
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.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) {
|
func (tsc *tipSetCache) best() (*types.TipSet, error) {
|
||||||
|
tsc.mu.RLock()
|
||||||
best := tsc.cache[tsc.start]
|
best := tsc.cache[tsc.start]
|
||||||
|
tsc.mu.RUnlock()
|
||||||
if best == nil {
|
if best == nil {
|
||||||
return tsc.storage.ChainHead(context.TODO())
|
return tsc.storage.ChainHead(context.TODO())
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/cmd/lotus-seed/seed"
|
"github.com/filecoin-project/lotus/cmd/lotus-seed/seed"
|
||||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||||
"github.com/filecoin-project/lotus/genesis"
|
"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/blockstore"
|
||||||
"github.com/filecoin-project/lotus/lib/sigs"
|
"github.com/filecoin-project/lotus/lib/sigs"
|
||||||
"github.com/filecoin-project/lotus/node/repo"
|
"github.com/filecoin-project/lotus/node/repo"
|
||||||
@ -71,7 +72,7 @@ type ChainGen struct {
|
|||||||
|
|
||||||
GetMessages func(*ChainGen) ([]*types.SignedMessage, error)
|
GetMessages func(*ChainGen) ([]*types.SignedMessage, error)
|
||||||
|
|
||||||
w *wallet.Wallet
|
w *wallet.LocalWallet
|
||||||
|
|
||||||
eppProvs map[address.Address]WinningPoStProver
|
eppProvs map[address.Address]WinningPoStProver
|
||||||
Miners []address.Address
|
Miners []address.Address
|
||||||
@ -122,6 +123,7 @@ var DefaultRemainderAccountActor = genesis.Actor{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||||
|
j := journal.NilJournal()
|
||||||
// TODO: we really shouldn't modify a global variable here.
|
// TODO: we really shouldn't modify a global variable here.
|
||||||
policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1)
|
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)
|
return nil, xerrors.Errorf("creating memrepo wallet failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
banker, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
banker, err := w.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to generate banker key: %w", err)
|
return nil, xerrors.Errorf("failed to generate banker key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
receievers := make([]address.Address, msgsPerBlock)
|
receievers := make([]address.Address, msgsPerBlock)
|
||||||
for r := range receievers {
|
for r := range receievers {
|
||||||
receievers[r], err = w.GenerateKey(crypto.SigTypeBLS)
|
receievers[r], err = w.WalletNew(context.Background(), crypto.SigTypeBLS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to generate receiver key: %w", err)
|
return nil, xerrors.Errorf("failed to generate receiver key: %w", err)
|
||||||
}
|
}
|
||||||
@ -190,11 +192,11 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mk1, err := w.Import(k1)
|
mk1, err := w.WalletImport(context.Background(), k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
mk2, err := w.Import(k2)
|
mk2, err := w.WalletImport(context.Background(), k2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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()),
|
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 {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("make genesis block failed: %w", err)
|
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}
|
genfb := &types.FullBlock{Header: genb.Genesis}
|
||||||
gents := store.NewFullTipSet([]*types.FullBlock{genfb})
|
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)
|
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 {
|
if err != nil {
|
||||||
return nil, nil, nil, xerrors.Errorf("compute VRF: %w", err)
|
return nil, nil, nil, xerrors.Errorf("compute VRF: %w", err)
|
||||||
}
|
}
|
||||||
@ -506,7 +514,7 @@ func (cg *ChainGen) Banker() address.Address {
|
|||||||
return cg.banker
|
return cg.banker
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cg *ChainGen) Wallet() *wallet.Wallet {
|
func (cg *ChainGen) Wallet() *wallet.LocalWallet {
|
||||||
return cg.w
|
return cg.w
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -528,7 +536,9 @@ func getRandomMessages(cg *ChainGen) ([]*types.SignedMessage, error) {
|
|||||||
GasPremium: types.NewInt(0),
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -559,7 +569,7 @@ type MiningCheckAPI interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type mca struct {
|
type mca struct {
|
||||||
w *wallet.Wallet
|
w *wallet.LocalWallet
|
||||||
sm *stmgr.StateManager
|
sm *stmgr.StateManager
|
||||||
pv ffiwrapper.Verifier
|
pv ffiwrapper.Verifier
|
||||||
bcn beacon.Schedule
|
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) {
|
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 {
|
type WinningPoStProver interface {
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
"github.com/filecoin-project/lotus/journal"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/ipfs/go-datastore"
|
"github.com/ipfs/go-datastore"
|
||||||
@ -26,7 +27,6 @@ import (
|
|||||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
|
||||||
"github.com/filecoin-project/lotus/chain/state"
|
"github.com/filecoin-project/lotus/chain/state"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
@ -117,7 +117,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
|||||||
return nil, nil, xerrors.Errorf("putting empty object: %w", err)
|
return nil, nil, xerrors.Errorf("putting empty object: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
state, err := state.NewStateTree(cst, actors.Version0)
|
state, err := state.NewStateTree(cst, types.StateTreeVersion0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, xerrors.Errorf("making new state tree: %w", err)
|
return nil, nil, xerrors.Errorf("making new state tree: %w", err)
|
||||||
}
|
}
|
||||||
@ -467,7 +467,10 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci
|
|||||||
return st, nil
|
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)
|
st, keyIDs, err := MakeInitialStateTree(ctx, bs, template)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("make initial state tree failed: %w", err)
|
return nil, xerrors.Errorf("make initial state tree failed: %w", err)
|
||||||
@ -479,7 +482,7 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys vm.SyscallB
|
|||||||
}
|
}
|
||||||
|
|
||||||
// temp chainstore
|
// temp chainstore
|
||||||
cs := store.NewChainStore(bs, datastore.NewMapDatastore(), sys)
|
cs := store.NewChainStore(bs, datastore.NewMapDatastore(), sys, j)
|
||||||
|
|
||||||
// Verify PreSealed Data
|
// Verify PreSealed Data
|
||||||
stateroot, err = VerifyPreSealedData(ctx, cs, stateroot, template, keyIDs)
|
stateroot, err = VerifyPreSealedData(ctx, cs, stateroot, template, keyIDs)
|
||||||
|
@ -15,11 +15,10 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
"github.com/filecoin-project/lotus/chain/wallet"
|
|
||||||
"github.com/filecoin-project/lotus/lib/sigs/bls"
|
"github.com/filecoin-project/lotus/lib/sigs/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)
|
pts, err := sm.ChainStore().LoadTipSet(bt.Parents)
|
||||||
if err != nil {
|
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)
|
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 {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to sign new block: %w", err)
|
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
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
fm.lk.Lock()
|
fm.lk.Lock()
|
||||||
|
defer fm.lk.Unlock()
|
||||||
|
|
||||||
bal, err := fm.api.StateMarketBalance(ctx, addr, types.EmptyTSK)
|
bal, err := fm.api.StateMarketBalance(ctx, addr, types.EmptyTSK)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fm.lk.Unlock()
|
|
||||||
return cid.Undef, err
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +139,6 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
|
|||||||
toAdd = types.NewInt(0)
|
toAdd = types.NewInt(0)
|
||||||
}
|
}
|
||||||
fm.available[idAddr] = big.Add(avail, toAdd)
|
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())
|
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)
|
params, err := actors.SerializeParams(&addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fm.available[idAddr] = avail
|
||||||
return cid.Undef, err
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,6 +160,7 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
|
|||||||
Params: params,
|
Params: params,
|
||||||
}, nil)
|
}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fm.available[idAddr] = avail
|
||||||
return cid.Undef, err
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,9 +57,10 @@ func addFundsMsg(toAdd abi.TokenAmount, addr address.Address, wallet address.Add
|
|||||||
}
|
}
|
||||||
|
|
||||||
type expectedResult struct {
|
type expectedResult struct {
|
||||||
addAmt abi.TokenAmount
|
addAmt abi.TokenAmount
|
||||||
shouldAdd bool
|
shouldAdd bool
|
||||||
err error
|
err error
|
||||||
|
cachedAvailable abi.TokenAmount
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddFunds(t *testing.T) {
|
func TestAddFunds(t *testing.T) {
|
||||||
@ -88,8 +89,9 @@ func TestAddFunds(t *testing.T) {
|
|||||||
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
|
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
|
||||||
expectedResults: []expectedResult{
|
expectedResults: []expectedResult{
|
||||||
{
|
{
|
||||||
shouldAdd: false,
|
shouldAdd: false,
|
||||||
err: nil,
|
err: nil,
|
||||||
|
cachedAvailable: abi.NewTokenAmount(100),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -102,18 +104,21 @@ func TestAddFunds(t *testing.T) {
|
|||||||
err: nil,
|
err: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
addAmt: abi.NewTokenAmount(100),
|
addAmt: abi.NewTokenAmount(100),
|
||||||
shouldAdd: true,
|
shouldAdd: true,
|
||||||
err: nil,
|
err: nil,
|
||||||
|
cachedAvailable: abi.NewTokenAmount(200),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
addAmt: abi.NewTokenAmount(50),
|
addAmt: abi.NewTokenAmount(50),
|
||||||
shouldAdd: true,
|
shouldAdd: true,
|
||||||
err: nil,
|
err: nil,
|
||||||
|
cachedAvailable: abi.NewTokenAmount(250),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
shouldAdd: false,
|
shouldAdd: false,
|
||||||
err: nil,
|
err: nil,
|
||||||
|
cachedAvailable: abi.NewTokenAmount(250),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -132,7 +137,8 @@ func TestAddFunds(t *testing.T) {
|
|||||||
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
|
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
|
||||||
expectedResults: []expectedResult{
|
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 {
|
} else {
|
||||||
require.EqualError(t, err, expected.err.Error())
|
require.EqualError(t, err, expected.err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !expected.cachedAvailable.Nil() {
|
||||||
|
require.Equal(t, expected.cachedAvailable, fundMgr.available[addr])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -159,6 +159,7 @@ type MessagePool struct {
|
|||||||
sigValCache *lru.TwoQueueCache
|
sigValCache *lru.TwoQueueCache
|
||||||
|
|
||||||
evtTypes [3]journal.EventType
|
evtTypes [3]journal.EventType
|
||||||
|
journal journal.Journal
|
||||||
}
|
}
|
||||||
|
|
||||||
type msgSet struct {
|
type msgSet struct {
|
||||||
@ -316,7 +317,7 @@ func (ms *msgSet) getRequiredFunds(nonce uint64) types.BigInt {
|
|||||||
return types.BigInt{Int: requiredFunds}
|
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)
|
cache, _ := lru.New2Q(build.BlsSignatureCacheSize)
|
||||||
verifcache, _ := lru.New2Q(build.VerifSigCacheSize)
|
verifcache, _ := lru.New2Q(build.VerifSigCacheSize)
|
||||||
|
|
||||||
@ -325,6 +326,10 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa
|
|||||||
return nil, xerrors.Errorf("error loading mpool config: %w", err)
|
return nil, xerrors.Errorf("error loading mpool config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if j == nil {
|
||||||
|
j = journal.NilJournal()
|
||||||
|
}
|
||||||
|
|
||||||
mp := &MessagePool{
|
mp := &MessagePool{
|
||||||
ds: ds,
|
ds: ds,
|
||||||
addSema: make(chan struct{}, 1),
|
addSema: make(chan struct{}, 1),
|
||||||
@ -344,10 +349,11 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa
|
|||||||
netName: netName,
|
netName: netName,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
evtTypes: [...]journal.EventType{
|
evtTypes: [...]journal.EventType{
|
||||||
evtTypeMpoolAdd: journal.J.RegisterEventType("mpool", "add"),
|
evtTypeMpoolAdd: j.RegisterEventType("mpool", "add"),
|
||||||
evtTypeMpoolRemove: journal.J.RegisterEventType("mpool", "remove"),
|
evtTypeMpoolRemove: j.RegisterEventType("mpool", "remove"),
|
||||||
evtTypeMpoolRepub: journal.J.RegisterEventType("mpool", "repub"),
|
evtTypeMpoolRepub: j.RegisterEventType("mpool", "repub"),
|
||||||
},
|
},
|
||||||
|
journal: j,
|
||||||
}
|
}
|
||||||
|
|
||||||
// enable initial prunes
|
// enable initial prunes
|
||||||
@ -744,7 +750,7 @@ func (mp *MessagePool) addLocked(m *types.SignedMessage, strict, untrusted bool)
|
|||||||
Message: m,
|
Message: m,
|
||||||
}, localUpdates)
|
}, localUpdates)
|
||||||
|
|
||||||
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolAdd], func() interface{} {
|
mp.journal.RecordEvent(mp.evtTypes[evtTypeMpoolAdd], func() interface{} {
|
||||||
return MessagePoolEvt{
|
return MessagePoolEvt{
|
||||||
Action: "add",
|
Action: "add",
|
||||||
Messages: []MessagePoolEvtMessage{{Message: m.Message, CID: m.Cid()}},
|
Messages: []MessagePoolEvtMessage{{Message: m.Message, CID: m.Cid()}},
|
||||||
@ -865,7 +871,7 @@ func (mp *MessagePool) remove(from address.Address, nonce uint64, applied bool)
|
|||||||
Message: m,
|
Message: m,
|
||||||
}, localUpdates)
|
}, localUpdates)
|
||||||
|
|
||||||
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolRemove], func() interface{} {
|
mp.journal.RecordEvent(mp.evtTypes[evtTypeMpoolRemove], func() interface{} {
|
||||||
return MessagePoolEvt{
|
return MessagePoolEvt{
|
||||||
Action: "remove",
|
Action: "remove",
|
||||||
Messages: []MessagePoolEvtMessage{{Message: m.Message, CID: m.Cid()}}}
|
Messages: []MessagePoolEvtMessage{{Message: m.Message, CID: m.Cid()}}}
|
||||||
|
@ -225,14 +225,14 @@ func TestMessagePool(t *testing.T) {
|
|||||||
|
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
mp, err := New(tma, ds, "mptest")
|
mp, err := New(tma, ds, "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a := tma.nextBlock()
|
a := tma.nextBlock()
|
||||||
|
|
||||||
sender, err := w.GenerateKey(crypto.SigTypeBLS)
|
sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -266,14 +266,14 @@ func TestMessagePoolMessagesInEachBlock(t *testing.T) {
|
|||||||
|
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
mp, err := New(tma, ds, "mptest")
|
mp, err := New(tma, ds, "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a := tma.nextBlock()
|
a := tma.nextBlock()
|
||||||
|
|
||||||
sender, err := w.GenerateKey(crypto.SigTypeBLS)
|
sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -315,7 +315,7 @@ func TestRevertMessages(t *testing.T) {
|
|||||||
|
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
mp, err := New(tma, ds, "mptest")
|
mp, err := New(tma, ds, "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -323,7 +323,7 @@ func TestRevertMessages(t *testing.T) {
|
|||||||
a := tma.nextBlock()
|
a := tma.nextBlock()
|
||||||
b := tma.nextBlock()
|
b := tma.nextBlock()
|
||||||
|
|
||||||
sender, err := w.GenerateKey(crypto.SigTypeBLS)
|
sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -378,7 +378,7 @@ func TestPruningSimple(t *testing.T) {
|
|||||||
|
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
mp, err := New(tma, ds, "mptest")
|
mp, err := New(tma, ds, "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -386,7 +386,7 @@ func TestPruningSimple(t *testing.T) {
|
|||||||
a := tma.nextBlock()
|
a := tma.nextBlock()
|
||||||
tma.applyBlock(t, a)
|
tma.applyBlock(t, a)
|
||||||
|
|
||||||
sender, err := w.GenerateKey(crypto.SigTypeBLS)
|
sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -422,7 +422,7 @@ func TestLoadLocal(t *testing.T) {
|
|||||||
tma := newTestMpoolAPI()
|
tma := newTestMpoolAPI()
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
mp, err := New(tma, ds, "mptest")
|
mp, err := New(tma, ds, "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -433,7 +433,7 @@ func TestLoadLocal(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -443,7 +443,7 @@ func TestLoadLocal(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -465,7 +465,7 @@ func TestLoadLocal(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
mp, err = New(tma, ds, "mptest")
|
mp, err = New(tma, ds, "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -494,7 +494,7 @@ func TestClearAll(t *testing.T) {
|
|||||||
tma := newTestMpoolAPI()
|
tma := newTestMpoolAPI()
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
mp, err := New(tma, ds, "mptest")
|
mp, err := New(tma, ds, "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -505,7 +505,7 @@ func TestClearAll(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -515,7 +515,7 @@ func TestClearAll(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -548,7 +548,7 @@ func TestClearNonLocal(t *testing.T) {
|
|||||||
tma := newTestMpoolAPI()
|
tma := newTestMpoolAPI()
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
mp, err := New(tma, ds, "mptest")
|
mp, err := New(tma, ds, "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -559,7 +559,7 @@ func TestClearNonLocal(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -569,7 +569,7 @@ func TestClearNonLocal(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -609,7 +609,7 @@ func TestUpdates(t *testing.T) {
|
|||||||
tma := newTestMpoolAPI()
|
tma := newTestMpoolAPI()
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
mp, err := New(tma, ds, "mptest")
|
mp, err := New(tma, ds, "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -620,7 +620,7 @@ func TestUpdates(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -630,7 +630,7 @@ func TestUpdates(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/journal"
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -148,14 +147,14 @@ loop:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(msgs) > 0 {
|
if len(msgs) > 0 {
|
||||||
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolRepub], func() interface{} {
|
mp.journal.RecordEvent(mp.evtTypes[evtTypeMpoolRepub], func() interface{} {
|
||||||
msgs := make([]MessagePoolEvtMessage, 0, len(msgs))
|
msgsEv := make([]MessagePoolEvtMessage, 0, len(msgs))
|
||||||
for _, m := range 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{
|
return MessagePoolEvt{
|
||||||
Action: "repub",
|
Action: "repub",
|
||||||
Messages: msgs,
|
Messages: msgsEv,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package messagepool
|
package messagepool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -21,7 +22,7 @@ func TestRepubMessages(t *testing.T) {
|
|||||||
tma := newTestMpoolAPI()
|
tma := newTestMpoolAPI()
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
mp, err := New(tma, ds, "mptest")
|
mp, err := New(tma, ds, "mptest", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -32,7 +33,7 @@ func TestRepubMessages(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -42,7 +43,7 @@ func TestRepubMessages(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,10 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"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-address"
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
@ -21,12 +25,10 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||||
"github.com/filecoin-project/lotus/chain/wallet"
|
"github.com/filecoin-project/lotus/chain/wallet"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
"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/bls"
|
||||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||||
logging "github.com/ipfs/go-log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -34,7 +36,7 @@ func init() {
|
|||||||
MaxActorPendingMessages = 1000000
|
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{
|
msg := &types.Message{
|
||||||
From: from,
|
From: from,
|
||||||
To: to,
|
To: to,
|
||||||
@ -45,7 +47,7 @@ func makeTestMessage(w *wallet.Wallet, from, to address.Address, nonce uint64, g
|
|||||||
GasFeeCap: types.NewInt(100 + gasPrice),
|
GasFeeCap: types.NewInt(100 + gasPrice),
|
||||||
GasPremium: types.NewInt(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 {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -58,7 +60,7 @@ func makeTestMessage(w *wallet.Wallet, from, to address.Address, nonce uint64, g
|
|||||||
func makeTestMpool() (*MessagePool, *testMpoolAPI) {
|
func makeTestMpool() (*MessagePool, *testMpoolAPI) {
|
||||||
tma := newTestMpoolAPI()
|
tma := newTestMpoolAPI()
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
mp, err := New(tma, ds, "test")
|
mp, err := New(tma, ds, "test", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -75,7 +77,7 @@ func TestMessageChains(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -85,7 +87,7 @@ func TestMessageChains(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -313,7 +315,7 @@ func TestMessageChainSkipping(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -323,7 +325,7 @@ func TestMessageChainSkipping(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -389,7 +391,7 @@ func TestBasicMessageSelection(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -399,7 +401,7 @@ func TestBasicMessageSelection(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -533,7 +535,7 @@ func TestMessageSelectionTrimming(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -543,7 +545,7 @@ func TestMessageSelectionTrimming(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -596,7 +598,7 @@ func TestPriorityMessageSelection(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -606,7 +608,7 @@ func TestPriorityMessageSelection(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -675,7 +677,7 @@ func TestPriorityMessageSelection2(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -685,7 +687,7 @@ func TestPriorityMessageSelection2(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -744,7 +746,7 @@ func TestPriorityMessageSelection3(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -754,7 +756,7 @@ func TestPriorityMessageSelection3(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -841,7 +843,7 @@ func TestOptimalMessageSelection1(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -851,7 +853,7 @@ func TestOptimalMessageSelection1(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -908,7 +910,7 @@ func TestOptimalMessageSelection2(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -918,7 +920,7 @@ func TestOptimalMessageSelection2(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -984,7 +986,7 @@ func TestOptimalMessageSelection3(t *testing.T) {
|
|||||||
nActors := 10
|
nActors := 10
|
||||||
// the actors
|
// the actors
|
||||||
var actors []address.Address
|
var actors []address.Address
|
||||||
var wallets []*wallet.Wallet
|
var wallets []*wallet.LocalWallet
|
||||||
|
|
||||||
for i := 0; i < nActors; i++ {
|
for i := 0; i < nActors; i++ {
|
||||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||||
@ -992,7 +994,7 @@ func TestOptimalMessageSelection3(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
a, err := w.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -1064,7 +1066,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu
|
|||||||
nActors := 300
|
nActors := 300
|
||||||
// the actors
|
// the actors
|
||||||
var actors []address.Address
|
var actors []address.Address
|
||||||
var wallets []*wallet.Wallet
|
var wallets []*wallet.LocalWallet
|
||||||
|
|
||||||
for i := 0; i < nActors; i++ {
|
for i := 0; i < nActors; i++ {
|
||||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||||
@ -1072,7 +1074,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
a, err := w.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -1330,7 +1332,7 @@ readLoop:
|
|||||||
}
|
}
|
||||||
|
|
||||||
actorMap := make(map[address.Address]address.Address)
|
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 {
|
for _, m := range msgs {
|
||||||
baseNonce := baseNonces[m.Message.From]
|
baseNonce := baseNonces[m.Message.From]
|
||||||
@ -1342,7 +1344,7 @@ readLoop:
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
a, err := w.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -1360,7 +1362,7 @@ readLoop:
|
|||||||
m.Message.From = localActor
|
m.Message.From = localActor
|
||||||
m.Message.Nonce -= baseNonce
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -5,40 +5,37 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"sync"
|
"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"
|
||||||
"github.com/ipfs/go-datastore/namespace"
|
"github.com/ipfs/go-datastore/namespace"
|
||||||
logging "github.com/ipfs/go-log/v2"
|
logging "github.com/ipfs/go-log/v2"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
"golang.org/x/xerrors"
|
"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"
|
const dsKeyActorNonce = "ActorNextNonce"
|
||||||
|
|
||||||
var log = logging.Logger("messagesigner")
|
var log = logging.Logger("messagesigner")
|
||||||
|
|
||||||
type mpoolAPI interface {
|
type MpoolNonceAPI interface {
|
||||||
GetNonce(address.Address) (uint64, error)
|
GetNonce(address.Address) (uint64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MessageSigner keeps track of nonces per address, and increments the nonce
|
// MessageSigner keeps track of nonces per address, and increments the nonce
|
||||||
// when signing a message
|
// when signing a message
|
||||||
type MessageSigner struct {
|
type MessageSigner struct {
|
||||||
wallet *wallet.Wallet
|
wallet api.WalletAPI
|
||||||
lk sync.Mutex
|
lk sync.Mutex
|
||||||
mpool mpoolAPI
|
mpool MpoolNonceAPI
|
||||||
ds datastore.Batching
|
ds datastore.Batching
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMessageSigner(wallet *wallet.Wallet, mpool *messagepool.MessagePool, ds dtypes.MetadataDS) *MessageSigner {
|
func NewMessageSigner(wallet api.WalletAPI, mpool MpoolNonceAPI, ds dtypes.MetadataDS) *MessageSigner {
|
||||||
return newMessageSigner(wallet, mpool, ds)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMessageSigner(wallet *wallet.Wallet, mpool mpoolAPI, ds dtypes.MetadataDS) *MessageSigner {
|
|
||||||
ds = namespace.Wrap(ds, datastore.NewKey("/message-signer/"))
|
ds = namespace.Wrap(ds, datastore.NewKey("/message-signer/"))
|
||||||
return &MessageSigner{
|
return &MessageSigner{
|
||||||
wallet: wallet,
|
wallet: wallet,
|
||||||
@ -61,7 +58,16 @@ func (ms *MessageSigner) SignMessage(ctx context.Context, msg *types.Message, cb
|
|||||||
|
|
||||||
// Sign the message with the nonce
|
// Sign the message with the nonce
|
||||||
msg.Nonce = 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 {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to sign message: %w", err)
|
return nil, xerrors.Errorf("failed to sign message: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -47,13 +47,13 @@ func TestMessageSignerSignMessage(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||||
from1, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
from1, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
from2, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
from2, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
to1, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
to1, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
to2, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
to2, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
type msgSpec struct {
|
type msgSpec struct {
|
||||||
@ -177,7 +177,7 @@ func TestMessageSignerSignMessage(t *testing.T) {
|
|||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
mpool := newMockMpool()
|
mpool := newMockMpool()
|
||||||
ds := ds_sync.MutexWrap(datastore.NewMapDatastore())
|
ds := ds_sync.MutexWrap(datastore.NewMapDatastore())
|
||||||
ms := newMessageSigner(w, mpool, ds)
|
ms := NewMessageSigner(w, mpool, ds)
|
||||||
|
|
||||||
for _, m := range tt.msgs {
|
for _, m := range tt.msgs {
|
||||||
if len(m.mpoolNonce) == 1 {
|
if len(m.mpoolNonce) == 1 {
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
@ -26,7 +27,7 @@ var log = logging.Logger("statetree")
|
|||||||
// StateTree stores actors state by their ID.
|
// StateTree stores actors state by their ID.
|
||||||
type StateTree struct {
|
type StateTree struct {
|
||||||
root adt.Map
|
root adt.Map
|
||||||
version actors.Version // TODO
|
version types.StateTreeVersion
|
||||||
info cid.Cid
|
info cid.Cid
|
||||||
Store cbor.IpldStore
|
Store cbor.IpldStore
|
||||||
|
|
||||||
@ -120,21 +121,41 @@ func (ss *stateSnaps) deleteActor(addr address.Address) {
|
|||||||
ss.layers[len(ss.layers)-1].actors[addr] = streeOp{Delete: true}
|
ss.layers[len(ss.layers)-1].actors[addr] = streeOp{Delete: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStateTree(cst cbor.IpldStore, version actors.Version) (*StateTree, error) {
|
// VersionForNetwork returns the state tree version for the given network
|
||||||
|
// version.
|
||||||
|
func VersionForNetwork(ver network.Version) types.StateTreeVersion {
|
||||||
|
if actors.VersionForNetwork(ver) == actors.Version0 {
|
||||||
|
return types.StateTreeVersion0
|
||||||
|
}
|
||||||
|
return types.StateTreeVersion1
|
||||||
|
}
|
||||||
|
|
||||||
|
func adtForSTVersion(ver types.StateTreeVersion) actors.Version {
|
||||||
|
switch ver {
|
||||||
|
case types.StateTreeVersion0:
|
||||||
|
return actors.Version0
|
||||||
|
case types.StateTreeVersion1:
|
||||||
|
return actors.Version2
|
||||||
|
default:
|
||||||
|
panic("unhandled state tree version")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStateTree(cst cbor.IpldStore, ver types.StateTreeVersion) (*StateTree, error) {
|
||||||
var info cid.Cid
|
var info cid.Cid
|
||||||
switch version {
|
switch ver {
|
||||||
case actors.Version0:
|
case types.StateTreeVersion0:
|
||||||
// info is undefined
|
// info is undefined
|
||||||
case actors.Version2:
|
case types.StateTreeVersion1:
|
||||||
var err error
|
var err error
|
||||||
info, err = cst.Put(context.TODO(), new(types.StateInfo))
|
info, err = cst.Put(context.TODO(), new(types.StateInfo0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return nil, xerrors.Errorf("unsupported state tree version: %d", version)
|
return nil, xerrors.Errorf("unsupported state tree version: %d", ver)
|
||||||
}
|
}
|
||||||
root, err := adt.NewMap(adt.WrapStore(context.TODO(), cst), version)
|
root, err := adt.NewMap(adt.WrapStore(context.TODO(), cst), adtForSTVersion(ver))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -142,7 +163,7 @@ func NewStateTree(cst cbor.IpldStore, version actors.Version) (*StateTree, error
|
|||||||
return &StateTree{
|
return &StateTree{
|
||||||
root: root,
|
root: root,
|
||||||
info: info,
|
info: info,
|
||||||
version: version,
|
version: ver,
|
||||||
Store: cst,
|
Store: cst,
|
||||||
snaps: newStateSnaps(),
|
snaps: newStateSnaps(),
|
||||||
}, nil
|
}, nil
|
||||||
@ -154,13 +175,16 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) {
|
|||||||
if err := cst.Get(context.TODO(), c, &root); err != nil {
|
if err := cst.Get(context.TODO(), c, &root); err != nil {
|
||||||
// We failed to decode as the new version, must be an old version.
|
// We failed to decode as the new version, must be an old version.
|
||||||
root.Actors = c
|
root.Actors = c
|
||||||
root.Version = actors.Version0
|
root.Version = types.StateTreeVersion0
|
||||||
}
|
}
|
||||||
|
|
||||||
switch root.Version {
|
switch root.Version {
|
||||||
case actors.Version0, actors.Version2:
|
case types.StateTreeVersion0, types.StateTreeVersion1:
|
||||||
// Load the actual state-tree HAMT.
|
// Load the actual state-tree HAMT.
|
||||||
nd, err := adt.AsMap(adt.WrapStore(context.TODO(), cst), root.Actors, actors.Version(root.Version))
|
nd, err := adt.AsMap(
|
||||||
|
adt.WrapStore(context.TODO(), cst), root.Actors,
|
||||||
|
adtForSTVersion(root.Version),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("loading hamt node %s failed: %s", c, err)
|
log.Errorf("loading hamt node %s failed: %s", c, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -169,7 +193,7 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) {
|
|||||||
return &StateTree{
|
return &StateTree{
|
||||||
root: nd,
|
root: nd,
|
||||||
info: root.Info,
|
info: root.Info,
|
||||||
version: actors.Version(root.Version),
|
version: root.Version,
|
||||||
Store: cst,
|
Store: cst,
|
||||||
snaps: newStateSnaps(),
|
snaps: newStateSnaps(),
|
||||||
}, nil
|
}, nil
|
||||||
@ -309,11 +333,11 @@ func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) {
|
|||||||
return cid.Undef, xerrors.Errorf("failed to flush state-tree hamt: %w", err)
|
return cid.Undef, xerrors.Errorf("failed to flush state-tree hamt: %w", err)
|
||||||
}
|
}
|
||||||
// If we're version 0, return a raw tree.
|
// If we're version 0, return a raw tree.
|
||||||
if st.version == actors.Version0 {
|
if st.version == types.StateTreeVersion0 {
|
||||||
return root, nil
|
return root, nil
|
||||||
}
|
}
|
||||||
// Otherwise, return a versioned tree.
|
// Otherwise, return a versioned tree.
|
||||||
return st.Store.Put(ctx, &types.StateRoot{Version: uint64(st.version), Actors: root, Info: st.info})
|
return st.Store.Put(ctx, &types.StateRoot{Version: st.version, Actors: root, Info: st.info})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *StateTree) Snapshot(ctx context.Context) error {
|
func (st *StateTree) Snapshot(ctx context.Context) error {
|
||||||
@ -400,7 +424,7 @@ func (st *StateTree) ForEach(f func(address.Address, *types.Actor) error) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Version returns the version of the StateTree data structure in use.
|
// Version returns the version of the StateTree data structure in use.
|
||||||
func (st *StateTree) Version() actors.Version {
|
func (st *StateTree) Version() types.StateTreeVersion {
|
||||||
return st.version
|
return st.version
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,13 +13,12 @@ import (
|
|||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BenchmarkStateTreeSet(b *testing.B) {
|
func BenchmarkStateTreeSet(b *testing.B) {
|
||||||
cst := cbor.NewMemCborStore()
|
cst := cbor.NewMemCborStore()
|
||||||
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
|
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -46,7 +45,7 @@ func BenchmarkStateTreeSet(b *testing.B) {
|
|||||||
|
|
||||||
func BenchmarkStateTreeSetFlush(b *testing.B) {
|
func BenchmarkStateTreeSetFlush(b *testing.B) {
|
||||||
cst := cbor.NewMemCborStore()
|
cst := cbor.NewMemCborStore()
|
||||||
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
|
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -76,7 +75,7 @@ func BenchmarkStateTreeSetFlush(b *testing.B) {
|
|||||||
|
|
||||||
func BenchmarkStateTree10kGetActor(b *testing.B) {
|
func BenchmarkStateTree10kGetActor(b *testing.B) {
|
||||||
cst := cbor.NewMemCborStore()
|
cst := cbor.NewMemCborStore()
|
||||||
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
|
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -118,7 +117,7 @@ func BenchmarkStateTree10kGetActor(b *testing.B) {
|
|||||||
|
|
||||||
func TestSetCache(t *testing.T) {
|
func TestSetCache(t *testing.T) {
|
||||||
cst := cbor.NewMemCborStore()
|
cst := cbor.NewMemCborStore()
|
||||||
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
|
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -155,7 +154,7 @@ func TestSetCache(t *testing.T) {
|
|||||||
func TestSnapshots(t *testing.T) {
|
func TestSnapshots(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
cst := cbor.NewMemCborStore()
|
cst := cbor.NewMemCborStore()
|
||||||
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
|
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -239,7 +238,7 @@ func assertNotHas(t *testing.T, st *StateTree, addr address.Address) {
|
|||||||
func TestStateTreeConsistency(t *testing.T) {
|
func TestStateTreeConsistency(t *testing.T) {
|
||||||
cst := cbor.NewMemCborStore()
|
cst := cbor.NewMemCborStore()
|
||||||
// TODO: ActorUpgrade: this test tests pre actors v2
|
// TODO: ActorUpgrade: this test tests pre actors v2
|
||||||
st, err := NewStateTree(cst, actors.VersionForNetwork(network.Version3))
|
st, err := NewStateTree(cst, VersionForNetwork(network.Version3))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package stmgr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
@ -17,17 +18,38 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ErrExpensiveFork = errors.New("refusing explicit call due to state fork at epoch")
|
||||||
|
|
||||||
func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) {
|
func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) {
|
||||||
ctx, span := trace.StartSpan(ctx, "statemanager.Call")
|
ctx, span := trace.StartSpan(ctx, "statemanager.Call")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
|
// If no tipset is provided, try to find one without a fork.
|
||||||
if ts == nil {
|
if ts == nil {
|
||||||
ts = sm.cs.GetHeaviestTipSet()
|
ts = sm.cs.GetHeaviestTipSet()
|
||||||
|
|
||||||
|
// Search back till we find a height with no fork, or we reach the beginning.
|
||||||
|
for ts.Height() > 0 && sm.hasExpensiveFork(ctx, ts.Height()-1) {
|
||||||
|
var err error
|
||||||
|
ts, err = sm.cs.GetTipSetFromKey(ts.Parents())
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to find a non-forking epoch: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bstate := ts.ParentState()
|
bstate := ts.ParentState()
|
||||||
bheight := ts.Height()
|
bheight := ts.Height()
|
||||||
|
|
||||||
|
// If we have to run an expensive migration, and we're not at genesis,
|
||||||
|
// return an error because the migration will take too long.
|
||||||
|
//
|
||||||
|
// We allow this at height 0 for at-genesis migrations (for testing).
|
||||||
|
if bheight-1 > 0 && sm.hasExpensiveFork(ctx, bheight-1) {
|
||||||
|
return nil, ErrExpensiveFork
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the (not expensive) migration.
|
||||||
bstate, err := sm.handleStateForks(ctx, bstate, bheight-1, nil, ts)
|
bstate, err := sm.handleStateForks(ctx, bstate, bheight-1, nil, ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to handle fork: %w", err)
|
return nil, fmt.Errorf("failed to handle fork: %w", err)
|
||||||
@ -44,7 +66,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.
|
|||||||
BaseFee: types.NewInt(0),
|
BaseFee: types.NewInt(0),
|
||||||
}
|
}
|
||||||
|
|
||||||
vmi, err := vm.NewVM(ctx, vmopt)
|
vmi, err := sm.newVM(ctx, vmopt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to set up vm: %w", err)
|
return nil, xerrors.Errorf("failed to set up vm: %w", err)
|
||||||
}
|
}
|
||||||
@ -106,6 +128,24 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
|||||||
|
|
||||||
if ts == nil {
|
if ts == nil {
|
||||||
ts = sm.cs.GetHeaviestTipSet()
|
ts = sm.cs.GetHeaviestTipSet()
|
||||||
|
|
||||||
|
// Search back till we find a height with no fork, or we reach the beginning.
|
||||||
|
// We need the _previous_ height to have no fork, because we'll
|
||||||
|
// run the fork logic in `sm.TipSetState`. We need the _current_
|
||||||
|
// height to have no fork, because we'll run it inside this
|
||||||
|
// function before executing the given message.
|
||||||
|
for ts.Height() > 0 && (sm.hasExpensiveFork(ctx, ts.Height()) || sm.hasExpensiveFork(ctx, ts.Height()-1)) {
|
||||||
|
var err error
|
||||||
|
ts, err = sm.cs.GetTipSetFromKey(ts.Parents())
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to find a non-forking epoch: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When we're not at the genesis block, make sure we don't have an expensive migration.
|
||||||
|
if ts.Height() > 0 && (sm.hasExpensiveFork(ctx, ts.Height()) || sm.hasExpensiveFork(ctx, ts.Height()-1)) {
|
||||||
|
return nil, ErrExpensiveFork
|
||||||
}
|
}
|
||||||
|
|
||||||
state, _, err := sm.TipSetState(ctx, ts)
|
state, _, err := sm.TipSetState(ctx, ts)
|
||||||
@ -138,7 +178,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
|||||||
NtwkVersion: sm.GetNtwkVersion,
|
NtwkVersion: sm.GetNtwkVersion,
|
||||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||||
}
|
}
|
||||||
vmi, err := vm.NewVM(ctx, vmopt)
|
vmi, err := sm.newVM(ctx, vmopt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to set up vm: %w", err)
|
return nil, xerrors.Errorf("failed to set up vm: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
@ -22,23 +24,32 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/migration/nv3"
|
"github.com/filecoin-project/specs-actors/actors/migration/nv3"
|
||||||
m2 "github.com/filecoin-project/specs-actors/v2/actors/migration"
|
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/build"
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
|
||||||
"github.com/filecoin-project/lotus/chain/state"
|
"github.com/filecoin-project/lotus/chain/state"
|
||||||
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
|
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||||
|
"github.com/filecoin-project/lotus/lib/bufbstore"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UpgradeFunc func(context.Context, *StateManager, ExecCallback, cid.Cid, *types.TipSet) (cid.Cid, error)
|
// UpgradeFunc is a migration function run at every upgrade.
|
||||||
|
//
|
||||||
|
// - The oldState is the state produced by the upgrade epoch.
|
||||||
|
// - The returned newState is the new state that will be used by the next epoch.
|
||||||
|
// - The height is the upgrade epoch height (already executed).
|
||||||
|
// - The tipset is the tipset for the last non-null block before the upgrade. Do
|
||||||
|
// not assume that ts.Height() is the upgrade height.
|
||||||
|
type UpgradeFunc func(ctx context.Context, sm *StateManager, cb ExecCallback, oldState cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (newState cid.Cid, err error)
|
||||||
|
|
||||||
type Upgrade struct {
|
type Upgrade struct {
|
||||||
Height abi.ChainEpoch
|
Height abi.ChainEpoch
|
||||||
Network network.Version
|
Network network.Version
|
||||||
|
Expensive bool
|
||||||
Migration UpgradeFunc
|
Migration UpgradeFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +58,7 @@ type UpgradeSchedule []Upgrade
|
|||||||
func DefaultUpgradeSchedule() UpgradeSchedule {
|
func DefaultUpgradeSchedule() UpgradeSchedule {
|
||||||
var us UpgradeSchedule
|
var us UpgradeSchedule
|
||||||
|
|
||||||
for _, u := range []Upgrade{{
|
updates := []Upgrade{{
|
||||||
Height: build.UpgradeBreezeHeight,
|
Height: build.UpgradeBreezeHeight,
|
||||||
Network: network.Version1,
|
Network: network.Version1,
|
||||||
Migration: UpgradeFaucetBurnRecovery,
|
Migration: UpgradeFaucetBurnRecovery,
|
||||||
@ -59,15 +70,46 @@ func DefaultUpgradeSchedule() UpgradeSchedule {
|
|||||||
Height: build.UpgradeIgnitionHeight,
|
Height: build.UpgradeIgnitionHeight,
|
||||||
Network: network.Version3,
|
Network: network.Version3,
|
||||||
Migration: UpgradeIgnition,
|
Migration: UpgradeIgnition,
|
||||||
|
}, {
|
||||||
|
Height: build.UpgradeRefuelHeight,
|
||||||
|
Network: network.Version3,
|
||||||
|
Migration: UpgradeRefuel,
|
||||||
}, {
|
}, {
|
||||||
Height: build.UpgradeActorsV2Height,
|
Height: build.UpgradeActorsV2Height,
|
||||||
Network: network.Version4,
|
Network: network.Version4,
|
||||||
|
Expensive: true,
|
||||||
Migration: UpgradeActorsV2,
|
Migration: UpgradeActorsV2,
|
||||||
}, {
|
}, {
|
||||||
Height: build.UpgradeLiftoffHeight,
|
Height: build.UpgradeLiftoffHeight,
|
||||||
Network: network.Version4,
|
Network: network.Version4,
|
||||||
Migration: UpgradeLiftoff,
|
Migration: UpgradeLiftoff,
|
||||||
}} {
|
}}
|
||||||
|
|
||||||
|
if build.UpgradeActorsV2Height == math.MaxInt64 { // disable actors upgrade
|
||||||
|
updates = []Upgrade{{
|
||||||
|
Height: build.UpgradeBreezeHeight,
|
||||||
|
Network: network.Version1,
|
||||||
|
Migration: UpgradeFaucetBurnRecovery,
|
||||||
|
}, {
|
||||||
|
Height: build.UpgradeSmokeHeight,
|
||||||
|
Network: network.Version2,
|
||||||
|
Migration: nil,
|
||||||
|
}, {
|
||||||
|
Height: build.UpgradeIgnitionHeight,
|
||||||
|
Network: network.Version3,
|
||||||
|
Migration: UpgradeIgnition,
|
||||||
|
}, {
|
||||||
|
Height: build.UpgradeRefuelHeight,
|
||||||
|
Network: network.Version3,
|
||||||
|
Migration: UpgradeRefuel,
|
||||||
|
}, {
|
||||||
|
Height: build.UpgradeLiftoffHeight,
|
||||||
|
Network: network.Version3,
|
||||||
|
Migration: UpgradeLiftoff,
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, u := range updates {
|
||||||
if u.Height < 0 {
|
if u.Height < 0 {
|
||||||
// upgrade disabled
|
// upgrade disabled
|
||||||
continue
|
continue
|
||||||
@ -109,7 +151,7 @@ func (sm *StateManager) handleStateForks(ctx context.Context, root cid.Cid, heig
|
|||||||
var err error
|
var err error
|
||||||
f, ok := sm.stateMigrations[height]
|
f, ok := sm.stateMigrations[height]
|
||||||
if ok {
|
if ok {
|
||||||
retCid, err = f(ctx, sm, cb, root, ts)
|
retCid, err = f(ctx, sm, cb, root, height, ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, err
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
@ -118,6 +160,11 @@ func (sm *StateManager) handleStateForks(ctx context.Context, root cid.Cid, heig
|
|||||||
return retCid, nil
|
return retCid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sm *StateManager) hasExpensiveFork(ctx context.Context, height abi.ChainEpoch) bool {
|
||||||
|
_, ok := sm.expensiveUpgrades[height]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address, amt abi.TokenAmount) error {
|
func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address, amt abi.TokenAmount) error {
|
||||||
fromAct, err := tree.GetActor(from)
|
fromAct, err := tree.GetActor(from)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -180,7 +227,7 @@ func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
|
func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||||
// Some initial parameters
|
// Some initial parameters
|
||||||
FundsForMiners := types.FromFil(1_000_000)
|
FundsForMiners := types.FromFil(1_000_000)
|
||||||
LookbackEpoch := abi.ChainEpoch(32000)
|
LookbackEpoch := abi.ChainEpoch(32000)
|
||||||
@ -432,11 +479,9 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
|||||||
return tree.Flush(ctx)
|
return tree.Flush(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
|
func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||||
store := sm.cs.Store(ctx)
|
store := sm.cs.Store(ctx)
|
||||||
|
|
||||||
epoch := ts.Height() - 1
|
|
||||||
|
|
||||||
if build.UpgradeLiftoffHeight <= epoch {
|
if build.UpgradeLiftoffHeight <= epoch {
|
||||||
return cid.Undef, xerrors.Errorf("liftoff height must be beyond ignition height")
|
return cid.Undef, xerrors.Errorf("liftoff height must be beyond ignition height")
|
||||||
}
|
}
|
||||||
@ -489,12 +534,42 @@ func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, roo
|
|||||||
return tree.Flush(ctx)
|
return tree.Flush(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
|
func UpgradeRefuel(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||||
|
|
||||||
store := sm.cs.Store(ctx)
|
store := sm.cs.Store(ctx)
|
||||||
|
tree, err := sm.StateTree(root)
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
epoch := ts.Height() - 1
|
addr, err := address.NewFromString("t0122")
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, xerrors.Errorf("getting address: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
info, err := store.Put(ctx, new(types.StateInfo))
|
err = resetMultisigVesting(ctx, store, tree, addr, 0, 0, big.Zero())
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, xerrors.Errorf("tweaking msig vesting: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = resetMultisigVesting(ctx, store, tree, builtin.ReserveAddress, 0, 0, big.Zero())
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, xerrors.Errorf("tweaking msig vesting: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = resetMultisigVesting(ctx, store, tree, builtin.RootVerifierAddress, 0, 0, big.Zero())
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, xerrors.Errorf("tweaking msig vesting: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tree.Flush(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||||
|
buf := bufbstore.NewTieredBstore(sm.cs.Blockstore(), bstore.NewTemporarySync())
|
||||||
|
store := store.ActorStore(ctx, buf)
|
||||||
|
|
||||||
|
info, err := store.Put(ctx, new(types.StateInfo0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("failed to create new state info for actors v2: %w", err)
|
return cid.Undef, xerrors.Errorf("failed to create new state info for actors v2: %w", err)
|
||||||
}
|
}
|
||||||
@ -504,22 +579,8 @@ func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, roo
|
|||||||
return cid.Undef, xerrors.Errorf("upgrading to actors v2: %w", err)
|
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{
|
newRoot, err := store.Put(ctx, &types.StateRoot{
|
||||||
// TODO: ActorUpgrade: should be state-tree specific, not just the actors version.
|
Version: types.StateTreeVersion1,
|
||||||
Version: actors.Version2,
|
|
||||||
Actors: newHamtRoot,
|
Actors: newHamtRoot,
|
||||||
Info: info,
|
Info: info,
|
||||||
})
|
})
|
||||||
@ -538,10 +599,19 @@ func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, roo
|
|||||||
return cid.Undef, xerrors.Errorf("failed to load init actor after upgrade: %w", err)
|
return cid.Undef, xerrors.Errorf("failed to load init actor after upgrade: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
from := buf
|
||||||
|
to := buf.Read()
|
||||||
|
|
||||||
|
if err := vm.Copy(ctx, from, to, newRoot); err != nil {
|
||||||
|
return cid.Undef, xerrors.Errorf("copying migrated tree: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return newRoot, nil
|
return newRoot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpgradeLiftoff(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
|
func UpgradeLiftoff(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||||
tree, err := sm.StateTree(root)
|
tree, err := sm.StateTree(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||||
@ -699,6 +769,7 @@ func makeKeyAddr(splitAddr address.Address, count uint64) (address.Address, erro
|
|||||||
return addr, nil
|
return addr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: After the Liftoff epoch, refactor this to use resetMultisigVesting
|
||||||
func resetGenesisMsigs(ctx context.Context, sm *StateManager, store adt0.Store, tree *state.StateTree, startEpoch abi.ChainEpoch) error {
|
func resetGenesisMsigs(ctx context.Context, sm *StateManager, store adt0.Store, tree *state.StateTree, startEpoch abi.ChainEpoch) error {
|
||||||
gb, err := sm.cs.GetGenesis()
|
gb, err := sm.cs.GetGenesis()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -748,3 +819,34 @@ func resetGenesisMsigs(ctx context.Context, sm *StateManager, store adt0.Store,
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resetMultisigVesting(ctx context.Context, store adt0.Store, tree *state.StateTree, addr address.Address, startEpoch abi.ChainEpoch, duration abi.ChainEpoch, balance abi.TokenAmount) error {
|
||||||
|
act, err := tree.GetActor(addr)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getting actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !builtin.IsMultisigActor(act.Code) {
|
||||||
|
return xerrors.Errorf("actor wasn't msig: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var msigState multisig0.State
|
||||||
|
if err := store.Get(ctx, act.Head, &msigState); err != nil {
|
||||||
|
return xerrors.Errorf("reading multisig state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msigState.StartEpoch = startEpoch
|
||||||
|
msigState.UnlockDuration = duration
|
||||||
|
msigState.InitialBalance = balance
|
||||||
|
|
||||||
|
act.Head, err = store.Put(ctx, &msigState)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("writing new multisig state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tree.SetActor(addr, act); err != nil {
|
||||||
|
return xerrors.Errorf("setting multisig actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -6,14 +6,21 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"testing"
|
"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-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/cbor"
|
"github.com/filecoin-project/go-state-types/cbor"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||||
"golang.org/x/xerrors"
|
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||||
lotusinit "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
lotusinit "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||||
@ -24,11 +31,6 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
_ "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() {
|
func init() {
|
||||||
@ -76,7 +78,7 @@ func (ta testActor) Exports() []interface{} {
|
|||||||
func (ta *testActor) Constructor(rt runtime.Runtime, params *abi.EmptyValue) *abi.EmptyValue {
|
func (ta *testActor) Constructor(rt runtime.Runtime, params *abi.EmptyValue) *abi.EmptyValue {
|
||||||
rt.ValidateImmediateCallerAcceptAny()
|
rt.ValidateImmediateCallerAcceptAny()
|
||||||
rt.StateCreate(&testActorState{11})
|
rt.StateCreate(&testActorState{11})
|
||||||
fmt.Println("NEW ACTOR ADDRESS IS: ", rt.Receiver())
|
//fmt.Println("NEW ACTOR ADDRESS IS: ", rt.Receiver())
|
||||||
|
|
||||||
return abi.Empty
|
return abi.Empty
|
||||||
}
|
}
|
||||||
@ -120,7 +122,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
|||||||
Network: 1,
|
Network: 1,
|
||||||
Height: testForkHeight,
|
Height: testForkHeight,
|
||||||
Migration: func(ctx context.Context, sm *StateManager, cb ExecCallback,
|
Migration: func(ctx context.Context, sm *StateManager, cb ExecCallback,
|
||||||
root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
|
root cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||||
cst := ipldcbor.NewCborStore(sm.ChainStore().Blockstore())
|
cst := ipldcbor.NewCborStore(sm.ChainStore().Blockstore())
|
||||||
|
|
||||||
st, err := sm.StateTree(root)
|
st, err := sm.StateTree(root)
|
||||||
@ -173,7 +175,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
|||||||
|
|
||||||
var msgs []*types.SignedMessage
|
var msgs []*types.SignedMessage
|
||||||
|
|
||||||
enc, err := actors.SerializeParams(&init_.ExecParams{CodeCID: (testActor{}).Code()})
|
enc, err := actors.SerializeParams(&init0.ExecParams{CodeCID: (testActor{}).Code()})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -185,7 +187,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
|||||||
Params: enc,
|
Params: enc,
|
||||||
GasLimit: types.TestGasLimit,
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -213,7 +215,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
nonce++
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -233,3 +235,84 @@ func TestForkHeightTriggers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestForkRefuseCall(t *testing.T) {
|
||||||
|
logging.SetAllLoggers(logging.LevelInfo)
|
||||||
|
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
|
cg, err := gen.NewGenerator()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sm, err := NewStateManagerWithUpgradeSchedule(
|
||||||
|
cg.ChainStore(), UpgradeSchedule{{
|
||||||
|
Network: 1,
|
||||||
|
Expensive: true,
|
||||||
|
Height: testForkHeight,
|
||||||
|
Migration: func(ctx context.Context, sm *StateManager, cb ExecCallback,
|
||||||
|
root cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||||
|
return root, nil
|
||||||
|
}}})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
inv := vm.NewActorRegistry()
|
||||||
|
inv.Register(nil, testActor{})
|
||||||
|
|
||||||
|
sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) {
|
||||||
|
nvm, err := vm.NewVM(ctx, vmopt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nvm.SetInvoker(inv)
|
||||||
|
return nvm, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
cg.SetStateManager(sm)
|
||||||
|
|
||||||
|
enc, err := actors.SerializeParams(&init0.ExecParams{CodeCID: (testActor{}).Code()})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m := &types.Message{
|
||||||
|
From: cg.Banker(),
|
||||||
|
To: lotusinit.Address,
|
||||||
|
Method: builtin.MethodsInit.Exec,
|
||||||
|
Params: enc,
|
||||||
|
GasLimit: types.TestGasLimit,
|
||||||
|
Value: types.NewInt(0),
|
||||||
|
GasPremium: types.NewInt(0),
|
||||||
|
GasFeeCap: types.NewInt(0),
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 50; i++ {
|
||||||
|
ts, err := cg.NextTipSet()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret, err := sm.CallWithGas(ctx, m, nil, ts.TipSet.TipSet())
|
||||||
|
switch ts.TipSet.TipSet().Height() {
|
||||||
|
case testForkHeight, testForkHeight + 1:
|
||||||
|
// If I had a fork, or I _will_ have a fork, it should fail.
|
||||||
|
require.Equal(t, ErrExpensiveFork, err)
|
||||||
|
default:
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, ret.MsgRct.ExitCode.IsSuccess())
|
||||||
|
}
|
||||||
|
// Call just runs on the parent state for a tipset, so we only
|
||||||
|
// expect an error at the fork height.
|
||||||
|
ret, err = sm.Call(ctx, m, ts.TipSet.TipSet())
|
||||||
|
switch ts.TipSet.TipSet().Height() {
|
||||||
|
case testForkHeight + 1:
|
||||||
|
require.Equal(t, ErrExpensiveFork, err)
|
||||||
|
default:
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, ret.MsgRct.ExitCode.IsSuccess())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@ package stmgr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@ -37,8 +38,16 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const LookbackNoLimit = abi.ChainEpoch(-1)
|
||||||
|
|
||||||
var log = logging.Logger("statemgr")
|
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 {
|
type versionSpec struct {
|
||||||
networkVersion network.Version
|
networkVersion network.Version
|
||||||
atOrBelow abi.ChainEpoch
|
atOrBelow abi.ChainEpoch
|
||||||
@ -53,6 +62,10 @@ type StateManager struct {
|
|||||||
|
|
||||||
// Maps chain epochs to upgrade functions.
|
// Maps chain epochs to upgrade functions.
|
||||||
stateMigrations map[abi.ChainEpoch]UpgradeFunc
|
stateMigrations map[abi.ChainEpoch]UpgradeFunc
|
||||||
|
// A set of potentially expensive/time consuming upgrades. Explicit
|
||||||
|
// calls for, e.g., gas estimation fail against this epoch with
|
||||||
|
// ErrExpensiveFork.
|
||||||
|
expensiveUpgrades map[abi.ChainEpoch]struct{}
|
||||||
|
|
||||||
stCache map[string][]cid.Cid
|
stCache map[string][]cid.Cid
|
||||||
compWait map[string]chan struct{}
|
compWait map[string]chan struct{}
|
||||||
@ -78,6 +91,7 @@ func NewStateManagerWithUpgradeSchedule(cs *store.ChainStore, us UpgradeSchedule
|
|||||||
}
|
}
|
||||||
|
|
||||||
stateMigrations := make(map[abi.ChainEpoch]UpgradeFunc, len(us))
|
stateMigrations := make(map[abi.ChainEpoch]UpgradeFunc, len(us))
|
||||||
|
expensiveUpgrades := make(map[abi.ChainEpoch]struct{}, len(us))
|
||||||
var networkVersions []versionSpec
|
var networkVersions []versionSpec
|
||||||
lastVersion := network.Version0
|
lastVersion := network.Version0
|
||||||
if len(us) > 0 {
|
if len(us) > 0 {
|
||||||
@ -87,6 +101,9 @@ func NewStateManagerWithUpgradeSchedule(cs *store.ChainStore, us UpgradeSchedule
|
|||||||
if upgrade.Migration != nil {
|
if upgrade.Migration != nil {
|
||||||
stateMigrations[upgrade.Height] = upgrade.Migration
|
stateMigrations[upgrade.Height] = upgrade.Migration
|
||||||
}
|
}
|
||||||
|
if upgrade.Expensive {
|
||||||
|
expensiveUpgrades[upgrade.Height] = struct{}{}
|
||||||
|
}
|
||||||
networkVersions = append(networkVersions, versionSpec{
|
networkVersions = append(networkVersions, versionSpec{
|
||||||
networkVersion: lastVersion,
|
networkVersion: lastVersion,
|
||||||
atOrBelow: upgrade.Height,
|
atOrBelow: upgrade.Height,
|
||||||
@ -99,13 +116,14 @@ func NewStateManagerWithUpgradeSchedule(cs *store.ChainStore, us UpgradeSchedule
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &StateManager{
|
return &StateManager{
|
||||||
networkVersions: networkVersions,
|
networkVersions: networkVersions,
|
||||||
latestVersion: lastVersion,
|
latestVersion: lastVersion,
|
||||||
stateMigrations: stateMigrations,
|
stateMigrations: stateMigrations,
|
||||||
newVM: vm.NewVM,
|
expensiveUpgrades: expensiveUpgrades,
|
||||||
cs: cs,
|
newVM: vm.NewVM,
|
||||||
stCache: make(map[string][]cid.Cid),
|
cs: cs,
|
||||||
compWait: make(map[string]chan struct{}),
|
stCache: make(map[string][]cid.Cid),
|
||||||
|
compWait: make(map[string]chan struct{}),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,16 +516,7 @@ func (sm *StateManager) GetReceipt(ctx context.Context, msg cid.Cid, ts *types.T
|
|||||||
return nil, fmt.Errorf("failed to load message: %w", err)
|
return nil, fmt.Errorf("failed to load message: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
r, _, err := sm.tipsetExecutedMessage(ts, msg, m.VMMessage())
|
_, r, _, err := sm.searchBackForMsg(ctx, ts, m, LookbackNoLimit)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if r != nil {
|
|
||||||
return r, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_, r, _, err = sm.searchBackForMsg(ctx, ts, m)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to look back through chain for message: %w", err)
|
return nil, fmt.Errorf("failed to look back through chain for message: %w", err)
|
||||||
}
|
}
|
||||||
@ -516,9 +525,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
|
// 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
|
// happened, with an optional limit to how many epochs it will search. It guarantees that the message has been on
|
||||||
// before returning.
|
// 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) {
|
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)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
@ -556,7 +565,7 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confid
|
|||||||
var backFm cid.Cid
|
var backFm cid.Cid
|
||||||
backSearchWait := make(chan struct{})
|
backSearchWait := make(chan struct{})
|
||||||
go func() {
|
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 {
|
if err != nil {
|
||||||
log.Warnf("failed to look back through chain for message: %w", err)
|
log.Warnf("failed to look back through chain for message: %w", err)
|
||||||
return
|
return
|
||||||
@ -648,7 +657,7 @@ func (sm *StateManager) SearchForMessage(ctx context.Context, mcid cid.Cid) (*ty
|
|||||||
return head, r, foundMsg, nil
|
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 {
|
if err != nil {
|
||||||
log.Warnf("failed to look back through chain for message %s", mcid)
|
log.Warnf("failed to look back through chain for message %s", mcid)
|
||||||
@ -662,11 +671,33 @@ func (sm *StateManager) SearchForMessage(ctx context.Context, mcid cid.Cid) (*ty
|
|||||||
return fts, r, foundMsg, nil
|
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
|
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 {
|
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!
|
// it ain't here!
|
||||||
return nil, nil, cid.Undef, nil
|
return nil, nil, cid.Undef, nil
|
||||||
}
|
}
|
||||||
@ -677,32 +708,37 @@ func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet
|
|||||||
default:
|
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,
|
// 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
|
// 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
|
return nil, nil, cid.Undef, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ts, err := sm.cs.LoadTipSet(cur.Parents())
|
pts, err := sm.cs.LoadTipSet(cur.Parents())
|
||||||
if err != nil {
|
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())
|
act, err := sm.LoadActor(ctx, mFromId, pts)
|
||||||
if err != nil {
|
actorNoExist := errors.Is(err, types.ErrActorNotFound)
|
||||||
return nil, nil, cid.Undef, fmt.Errorf("checking for message execution during lookback: %w", err)
|
if err != nil && !actorNoExist {
|
||||||
|
return nil, nil, cid.Cid{}, xerrors.Errorf("failed to load the actor: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if r != nil {
|
// check that between cur and parent tipset the nonce fell into range of our message
|
||||||
return ts, r, foundMsg, nil
|
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 pts, r, foundMsg, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cur = ts
|
cur = pts
|
||||||
|
curActor = act
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1375,3 +1411,5 @@ func (sm *StateManager) GetMarketState(ctx context.Context, ts *types.TipSet) (m
|
|||||||
}
|
}
|
||||||
return actState, nil
|
return actState, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ StateManagerAPI = (*StateManager)(nil)
|
||||||
|
@ -387,7 +387,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
|||||||
NtwkVersion: sm.GetNtwkVersion,
|
NtwkVersion: sm.GetNtwkVersion,
|
||||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||||
}
|
}
|
||||||
vmi, err := vm.NewVM(ctx, vmopt)
|
vmi, err := sm.newVM(ctx, vmopt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, nil, err
|
return cid.Undef, nil, err
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ func TestIndexSeeks(t *testing.T) {
|
|||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
|
|
||||||
nbs := blockstore.NewTemporarySync()
|
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))
|
_, err = cs.Import(bytes.NewReader(gencar))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
@ -38,7 +39,9 @@ import (
|
|||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
block "github.com/ipfs/go-block-format"
|
block "github.com/ipfs/go-block-format"
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
|
"github.com/ipfs/go-datastore"
|
||||||
dstore "github.com/ipfs/go-datastore"
|
dstore "github.com/ipfs/go-datastore"
|
||||||
|
"github.com/ipfs/go-datastore/query"
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
logging "github.com/ipfs/go-log/v2"
|
logging "github.com/ipfs/go-log/v2"
|
||||||
car "github.com/ipld/go-car"
|
car "github.com/ipld/go-car"
|
||||||
@ -102,7 +105,7 @@ type HeadChangeEvt struct {
|
|||||||
// 2. a block => messages references cache.
|
// 2. a block => messages references cache.
|
||||||
type ChainStore struct {
|
type ChainStore struct {
|
||||||
bs bstore.Blockstore
|
bs bstore.Blockstore
|
||||||
ds dstore.Datastore
|
ds dstore.Batching
|
||||||
|
|
||||||
heaviestLk sync.Mutex
|
heaviestLk sync.Mutex
|
||||||
heaviest *types.TipSet
|
heaviest *types.TipSet
|
||||||
@ -124,11 +127,15 @@ type ChainStore struct {
|
|||||||
vmcalls vm.SyscallBuilder
|
vmcalls vm.SyscallBuilder
|
||||||
|
|
||||||
evtTypes [1]journal.EventType
|
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)
|
c, _ := lru.NewARC(DefaultMsgMetaCacheSize)
|
||||||
tsc, _ := lru.NewARC(DefaultTipSetCacheSize)
|
tsc, _ := lru.NewARC(DefaultTipSetCacheSize)
|
||||||
|
if j == nil {
|
||||||
|
j = journal.NilJournal()
|
||||||
|
}
|
||||||
cs := &ChainStore{
|
cs := &ChainStore{
|
||||||
bs: bs,
|
bs: bs,
|
||||||
ds: ds,
|
ds: ds,
|
||||||
@ -137,10 +144,11 @@ func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls vm.SyscallB
|
|||||||
mmCache: c,
|
mmCache: c,
|
||||||
tsCache: tsc,
|
tsCache: tsc,
|
||||||
vmcalls: vmcalls,
|
vmcalls: vmcalls,
|
||||||
|
journal: j,
|
||||||
}
|
}
|
||||||
|
|
||||||
cs.evtTypes = [1]journal.EventType{
|
cs.evtTypes = [1]journal.EventType{
|
||||||
evtTypeHeadChange: journal.J.RegisterEventType("sync", "head_change"),
|
evtTypeHeadChange: j.RegisterEventType("sync", "head_change"),
|
||||||
}
|
}
|
||||||
|
|
||||||
ci := NewChainIndex(cs.LoadTipSet)
|
ci := NewChainIndex(cs.LoadTipSet)
|
||||||
@ -379,7 +387,7 @@ func (cs *ChainStore) reorgWorker(ctx context.Context, initialNotifees []ReorgNo
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
journal.J.RecordEvent(cs.evtTypes[evtTypeHeadChange], func() interface{} {
|
cs.journal.RecordEvent(cs.evtTypes[evtTypeHeadChange], func() interface{} {
|
||||||
return HeadChangeEvt{
|
return HeadChangeEvt{
|
||||||
From: r.old.Key(),
|
From: r.old.Key(),
|
||||||
FromHeight: r.old.Height(),
|
FromHeight: r.old.Height(),
|
||||||
@ -441,6 +449,53 @@ func (cs *ChainStore) takeHeaviestTipSet(ctx context.Context, ts *types.TipSet)
|
|||||||
return nil
|
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.
|
// SetHead sets the chainstores current 'best' head node.
|
||||||
// This should only be called if something is broken and needs fixing
|
// This should only be called if something is broken and needs fixing
|
||||||
func (cs *ChainStore) SetHead(ts *types.TipSet) error {
|
func (cs *ChainStore) SetHead(ts *types.TipSet) error {
|
||||||
|
@ -62,7 +62,7 @@ func BenchmarkGetRandomness(b *testing.B) {
|
|||||||
|
|
||||||
bs := blockstore.NewBlockstore(bds)
|
bs := blockstore.NewBlockstore(bds)
|
||||||
|
|
||||||
cs := store.NewChainStore(bs, mds, nil)
|
cs := store.NewChainStore(bs, mds, nil, nil)
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ func TestChainExportImport(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nbs := blockstore.NewTemporary()
|
nbs := blockstore.NewTemporary()
|
||||||
cs := store.NewChainStore(nbs, datastore.NewMapDatastore(), nil)
|
cs := store.NewChainStore(nbs, datastore.NewMapDatastore(), nil, nil)
|
||||||
|
|
||||||
root, err := cs.Import(buf)
|
root, err := cs.Import(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -120,12 +120,6 @@ func FetchMessagesByCids(
|
|||||||
return err
|
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
|
out[i] = msg
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@ -149,10 +143,6 @@ func FetchSignedMessagesByCids(
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if out[i] != nil {
|
|
||||||
return fmt.Errorf("received duplicate message")
|
|
||||||
}
|
|
||||||
|
|
||||||
out[i] = smsg
|
out[i] = smsg
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@ -172,37 +162,41 @@ func fetchCids(
|
|||||||
cids []cid.Cid,
|
cids []cid.Cid,
|
||||||
cb func(int, blocks.Block) error,
|
cb func(int, blocks.Block) error,
|
||||||
) error {
|
) error {
|
||||||
fetchedBlocks := bserv.GetBlocks(ctx, cids)
|
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
cidIndex := make(map[cid.Cid]int)
|
cidIndex := make(map[cid.Cid]int)
|
||||||
for i, c := range cids {
|
for i, c := range cids {
|
||||||
cidIndex[c] = i
|
cidIndex[c] = i
|
||||||
}
|
}
|
||||||
|
if len(cids) != len(cidIndex) {
|
||||||
|
return fmt.Errorf("duplicate CIDs in fetchCids input")
|
||||||
|
}
|
||||||
|
|
||||||
for i := 0; i < len(cids); i++ {
|
for block := range bserv.GetBlocks(ctx, cids) {
|
||||||
select {
|
ix, ok := cidIndex[block.Cid()]
|
||||||
case block, ok := <-fetchedBlocks:
|
if !ok {
|
||||||
if !ok {
|
// Ignore duplicate/unexpected blocks. This shouldn't
|
||||||
// Closed channel, no more blocks fetched, check if we have all
|
// happen, but we can be safe.
|
||||||
// of the CIDs requested.
|
log.Errorw("received duplicate/unexpected block when syncing", "cid", block.Cid())
|
||||||
// FIXME: Review this check. We don't call the callback on the
|
continue
|
||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
return nil
|
||||||
|
63
chain/sub/incoming_test.go
Normal file
63
chain/sub/incoming_test.go
Normal file
@ -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])
|
||||||
|
}
|
||||||
|
}
|
@ -217,6 +217,12 @@ func (syncer *Syncer) Stop() {
|
|||||||
// This should be called when connecting to new peers, and additionally
|
// This should be called when connecting to new peers, and additionally
|
||||||
// when receiving new blocks from the network
|
// when receiving new blocks from the network
|
||||||
func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
|
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()
|
ctx := context.Background()
|
||||||
if fts == nil {
|
if fts == nil {
|
||||||
log.Errorf("got nil tipset in InformNewHead")
|
log.Errorf("got nil tipset in InformNewHead")
|
||||||
@ -731,7 +737,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock, use
|
|||||||
|
|
||||||
lbst, _, err := syncer.sm.TipSetState(ctx, lbts)
|
lbst, _, err := syncer.sm.TipSetState(ctx, lbts)
|
||||||
if err != nil {
|
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)
|
prevBeacon, err := syncer.store.GetLatestBeaconEntry(baseTs)
|
||||||
@ -1281,9 +1287,11 @@ func (syncer *Syncer) collectHeaders(ctx context.Context, incoming *types.TipSet
|
|||||||
|
|
||||||
blockSet := []*types.TipSet{incoming}
|
blockSet := []*types.TipSet{incoming}
|
||||||
|
|
||||||
|
// Parent of the new (possibly better) tipset that we need to fetch next.
|
||||||
at := incoming.Parents()
|
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
|
untilHeight := known.Height() + 1
|
||||||
|
|
||||||
ss.SetHeight(blockSet[len(blockSet)-1].Height())
|
ss.SetHeight(blockSet[len(blockSet)-1].Height())
|
||||||
@ -1377,13 +1385,17 @@ loop:
|
|||||||
}
|
}
|
||||||
|
|
||||||
base := blockSet[len(blockSet)-1]
|
base := blockSet[len(blockSet)-1]
|
||||||
if base.Parents() == known.Parents() {
|
if base.IsChildOf(known) {
|
||||||
// common case: receiving a block thats potentially part of the same tipset as our best block
|
// common case: receiving blocks that are building on top of our best tipset
|
||||||
return blockSet, nil
|
return blockSet, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if types.CidArrsEqual(base.Parents().Cids(), known.Cids()) {
|
knownParent, err := syncer.store.LoadTipSet(known.Parents())
|
||||||
// common case: receiving blocks that are building on top of our best tipset
|
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
|
return blockSet, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1514,7 +1526,7 @@ func (syncer *Syncer) iterFullTipsets(ctx context.Context, headers []*types.TipS
|
|||||||
ss.SetStage(api.StageMessages)
|
ss.SetStage(api.StageMessages)
|
||||||
|
|
||||||
if batchErr != nil {
|
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++ {
|
for bsi := 0; bsi < len(bstout); bsi++ {
|
||||||
@ -1714,7 +1726,7 @@ func VerifyElectionPoStVRF(ctx context.Context, worker address.Address, rand []b
|
|||||||
return gen.VerifyVRF(ctx, worker, rand, evrf)
|
return gen.VerifyVRF(ctx, worker, rand, evrf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (syncer *Syncer) State() []SyncerState {
|
func (syncer *Syncer) State() []SyncerStateSnapshot {
|
||||||
return syncer.syncmgr.State()
|
return syncer.syncmgr.State()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1728,6 +1740,10 @@ func (syncer *Syncer) UnmarkBad(blk cid.Cid) {
|
|||||||
syncer.bad.Remove(blk)
|
syncer.bad.Remove(blk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (syncer *Syncer) UnmarkAllBad() {
|
||||||
|
syncer.bad.Purge()
|
||||||
|
}
|
||||||
|
|
||||||
func (syncer *Syncer) CheckBadBlockCache(blk cid.Cid) (string, bool) {
|
func (syncer *Syncer) CheckBadBlockCache(blk cid.Cid) (string, bool) {
|
||||||
bbr, ok := syncer.bad.Has(blk)
|
bbr, ok := syncer.bad.Has(blk)
|
||||||
return bbr.String(), ok
|
return bbr.String(), ok
|
||||||
|
@ -38,7 +38,7 @@ type SyncManager interface {
|
|||||||
SetPeerHead(ctx context.Context, p peer.ID, ts *types.TipSet)
|
SetPeerHead(ctx context.Context, p peer.ID, ts *types.TipSet)
|
||||||
|
|
||||||
// State retrieves the state of the sync workers.
|
// State retrieves the state of the sync workers.
|
||||||
State() []SyncerState
|
State() []SyncerStateSnapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
type syncManager struct {
|
type syncManager struct {
|
||||||
@ -79,7 +79,7 @@ type syncResult struct {
|
|||||||
const syncWorkerCount = 3
|
const syncWorkerCount = 3
|
||||||
|
|
||||||
func NewSyncManager(sync SyncFunc) SyncManager {
|
func NewSyncManager(sync SyncFunc) SyncManager {
|
||||||
return &syncManager{
|
sm := &syncManager{
|
||||||
bspThresh: 1,
|
bspThresh: 1,
|
||||||
peerHeads: make(map[peer.ID]*types.TipSet),
|
peerHeads: make(map[peer.ID]*types.TipSet),
|
||||||
syncTargets: make(chan *types.TipSet),
|
syncTargets: make(chan *types.TipSet),
|
||||||
@ -90,6 +90,10 @@ func NewSyncManager(sync SyncFunc) SyncManager {
|
|||||||
doSync: sync,
|
doSync: sync,
|
||||||
stop: make(chan struct{}),
|
stop: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
for i := range sm.syncStates {
|
||||||
|
sm.syncStates[i] = new(SyncerState)
|
||||||
|
}
|
||||||
|
return sm
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *syncManager) Start() {
|
func (sm *syncManager) Start() {
|
||||||
@ -128,8 +132,8 @@ func (sm *syncManager) SetPeerHead(ctx context.Context, p peer.ID, ts *types.Tip
|
|||||||
sm.incomingTipSets <- ts
|
sm.incomingTipSets <- ts
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *syncManager) State() []SyncerState {
|
func (sm *syncManager) State() []SyncerStateSnapshot {
|
||||||
ret := make([]SyncerState, 0, len(sm.syncStates))
|
ret := make([]SyncerStateSnapshot, 0, len(sm.syncStates))
|
||||||
for _, s := range sm.syncStates {
|
for _, s := range sm.syncStates {
|
||||||
ret = append(ret, s.Snapshot())
|
ret = append(ret, s.Snapshot())
|
||||||
}
|
}
|
||||||
@ -405,8 +409,7 @@ func (sm *syncManager) scheduleWorkSent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sm *syncManager) syncWorker(id int) {
|
func (sm *syncManager) syncWorker(id int) {
|
||||||
ss := &SyncerState{}
|
ss := sm.syncStates[id]
|
||||||
sm.syncStates[id] = ss
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case ts, ok := <-sm.syncTargets:
|
case ts, ok := <-sm.syncTargets:
|
||||||
|
@ -221,8 +221,7 @@ func (tu *syncTestUtil) addSourceNode(gen int) {
|
|||||||
sourceRepo, genesis, blocks := tu.repoWithChain(tu.t, gen)
|
sourceRepo, genesis, blocks := tu.repoWithChain(tu.t, gen)
|
||||||
var out api.FullNode
|
var out api.FullNode
|
||||||
|
|
||||||
// TODO: Don't ignore stop
|
stop, err := node.New(tu.ctx,
|
||||||
_, err := node.New(tu.ctx,
|
|
||||||
node.FullAPI(&out),
|
node.FullAPI(&out),
|
||||||
node.Online(),
|
node.Online(),
|
||||||
node.Repo(sourceRepo),
|
node.Repo(sourceRepo),
|
||||||
@ -232,6 +231,7 @@ func (tu *syncTestUtil) addSourceNode(gen int) {
|
|||||||
node.Override(new(modules.Genesis), modules.LoadGenesis(genesis)),
|
node.Override(new(modules.Genesis), modules.LoadGenesis(genesis)),
|
||||||
)
|
)
|
||||||
require.NoError(tu.t, err)
|
require.NoError(tu.t, err)
|
||||||
|
tu.t.Cleanup(func() { _ = stop(context.Background()) })
|
||||||
|
|
||||||
lastTs := blocks[len(blocks)-1].Blocks
|
lastTs := blocks[len(blocks)-1].Blocks
|
||||||
for _, lastB := range lastTs {
|
for _, lastB := range lastTs {
|
||||||
@ -253,8 +253,7 @@ func (tu *syncTestUtil) addClientNode() int {
|
|||||||
|
|
||||||
var out api.FullNode
|
var out api.FullNode
|
||||||
|
|
||||||
// TODO: Don't ignore stop
|
stop, err := node.New(tu.ctx,
|
||||||
_, err := node.New(tu.ctx,
|
|
||||||
node.FullAPI(&out),
|
node.FullAPI(&out),
|
||||||
node.Online(),
|
node.Online(),
|
||||||
node.Repo(repo.NewMemory(nil)),
|
node.Repo(repo.NewMemory(nil)),
|
||||||
@ -264,6 +263,7 @@ func (tu *syncTestUtil) addClientNode() int {
|
|||||||
node.Override(new(modules.Genesis), modules.LoadGenesis(tu.genesis)),
|
node.Override(new(modules.Genesis), modules.LoadGenesis(tu.genesis)),
|
||||||
)
|
)
|
||||||
require.NoError(tu.t, err)
|
require.NoError(tu.t, err)
|
||||||
|
tu.t.Cleanup(func() { _ = stop(context.Background()) })
|
||||||
|
|
||||||
tu.nds = append(tu.nds, out)
|
tu.nds = append(tu.nds, out)
|
||||||
return len(tu.nds) - 1
|
return len(tu.nds) - 1
|
||||||
@ -593,7 +593,7 @@ func TestDuplicateNonce(t *testing.T) {
|
|||||||
GasPremium: types.NewInt(0),
|
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)
|
require.NoError(t, err)
|
||||||
|
|
||||||
return &types.SignedMessage{
|
return &types.SignedMessage{
|
||||||
@ -685,7 +685,7 @@ func TestBadNonce(t *testing.T) {
|
|||||||
GasPremium: types.NewInt(0),
|
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)
|
require.NoError(t, err)
|
||||||
|
|
||||||
return &types.SignedMessage{
|
return &types.SignedMessage{
|
||||||
|
@ -11,8 +11,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SyncerState struct {
|
type SyncerStateSnapshot struct {
|
||||||
lk sync.Mutex
|
|
||||||
Target *types.TipSet
|
Target *types.TipSet
|
||||||
Base *types.TipSet
|
Base *types.TipSet
|
||||||
Stage api.SyncStateStage
|
Stage api.SyncStateStage
|
||||||
@ -22,6 +21,11 @@ type SyncerState struct {
|
|||||||
End time.Time
|
End time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SyncerState struct {
|
||||||
|
lk sync.Mutex
|
||||||
|
data SyncerStateSnapshot
|
||||||
|
}
|
||||||
|
|
||||||
func (ss *SyncerState) SetStage(v api.SyncStateStage) {
|
func (ss *SyncerState) SetStage(v api.SyncStateStage) {
|
||||||
if ss == nil {
|
if ss == nil {
|
||||||
return
|
return
|
||||||
@ -29,9 +33,9 @@ func (ss *SyncerState) SetStage(v api.SyncStateStage) {
|
|||||||
|
|
||||||
ss.lk.Lock()
|
ss.lk.Lock()
|
||||||
defer ss.lk.Unlock()
|
defer ss.lk.Unlock()
|
||||||
ss.Stage = v
|
ss.data.Stage = v
|
||||||
if v == api.StageSyncComplete {
|
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()
|
ss.lk.Lock()
|
||||||
defer ss.lk.Unlock()
|
defer ss.lk.Unlock()
|
||||||
ss.Target = target
|
ss.data.Target = target
|
||||||
ss.Base = base
|
ss.data.Base = base
|
||||||
ss.Stage = api.StageHeaders
|
ss.data.Stage = api.StageHeaders
|
||||||
ss.Height = 0
|
ss.data.Height = 0
|
||||||
ss.Message = ""
|
ss.data.Message = ""
|
||||||
ss.Start = build.Clock.Now()
|
ss.data.Start = build.Clock.Now()
|
||||||
ss.End = time.Time{}
|
ss.data.End = time.Time{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *SyncerState) SetHeight(h abi.ChainEpoch) {
|
func (ss *SyncerState) SetHeight(h abi.ChainEpoch) {
|
||||||
@ -58,7 +62,7 @@ func (ss *SyncerState) SetHeight(h abi.ChainEpoch) {
|
|||||||
|
|
||||||
ss.lk.Lock()
|
ss.lk.Lock()
|
||||||
defer ss.lk.Unlock()
|
defer ss.lk.Unlock()
|
||||||
ss.Height = h
|
ss.data.Height = h
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *SyncerState) Error(err error) {
|
func (ss *SyncerState) Error(err error) {
|
||||||
@ -68,21 +72,13 @@ func (ss *SyncerState) Error(err error) {
|
|||||||
|
|
||||||
ss.lk.Lock()
|
ss.lk.Lock()
|
||||||
defer ss.lk.Unlock()
|
defer ss.lk.Unlock()
|
||||||
ss.Message = err.Error()
|
ss.data.Message = err.Error()
|
||||||
ss.Stage = api.StageSyncErrored
|
ss.data.Stage = api.StageSyncErrored
|
||||||
ss.End = build.Clock.Now()
|
ss.data.End = build.Clock.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *SyncerState) Snapshot() SyncerState {
|
func (ss *SyncerState) Snapshot() SyncerStateSnapshot {
|
||||||
ss.lk.Lock()
|
ss.lk.Lock()
|
||||||
defer ss.lk.Unlock()
|
defer ss.lk.Unlock()
|
||||||
return SyncerState{
|
return ss.data
|
||||||
Base: ss.Base,
|
|
||||||
Target: ss.Target,
|
|
||||||
Stage: ss.Stage,
|
|
||||||
Height: ss.Height,
|
|
||||||
Message: ss.Message,
|
|
||||||
Start: ss.Start,
|
|
||||||
End: ss.End,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1648,7 +1648,7 @@ func (t *StateRoot) MarshalCBOR(w io.Writer) error {
|
|||||||
|
|
||||||
scratch := make([]byte, 9)
|
scratch := make([]byte, 9)
|
||||||
|
|
||||||
// t.Version (uint64) (uint64)
|
// t.Version (types.StateTreeVersion) (uint64)
|
||||||
|
|
||||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Version)); err != nil {
|
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Version)); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -1687,7 +1687,7 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
|
|||||||
return fmt.Errorf("cbor input had wrong number of fields")
|
return fmt.Errorf("cbor input had wrong number of fields")
|
||||||
}
|
}
|
||||||
|
|
||||||
// t.Version (uint64) (uint64)
|
// t.Version (types.StateTreeVersion) (uint64)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -1698,7 +1698,7 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
|
|||||||
if maj != cbg.MajUnsignedInt {
|
if maj != cbg.MajUnsignedInt {
|
||||||
return fmt.Errorf("wrong type for uint64 field")
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
}
|
}
|
||||||
t.Version = uint64(extra)
|
t.Version = StateTreeVersion(extra)
|
||||||
|
|
||||||
}
|
}
|
||||||
// t.Actors (cid.Cid) (struct)
|
// t.Actors (cid.Cid) (struct)
|
||||||
@ -1728,22 +1728,22 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var lengthBufStateInfo = []byte{128}
|
var lengthBufStateInfo0 = []byte{128}
|
||||||
|
|
||||||
func (t *StateInfo) MarshalCBOR(w io.Writer) error {
|
func (t *StateInfo0) MarshalCBOR(w io.Writer) error {
|
||||||
if t == nil {
|
if t == nil {
|
||||||
_, err := w.Write(cbg.CborNull)
|
_, err := w.Write(cbg.CborNull)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := w.Write(lengthBufStateInfo); err != nil {
|
if _, err := w.Write(lengthBufStateInfo0); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *StateInfo) UnmarshalCBOR(r io.Reader) error {
|
func (t *StateInfo0) UnmarshalCBOR(r io.Reader) error {
|
||||||
*t = StateInfo{}
|
*t = StateInfo0{}
|
||||||
|
|
||||||
br := cbg.GetPeeker(r)
|
br := cbg.GetPeeker(r)
|
||||||
scratch := make([]byte, 8)
|
scratch := make([]byte, 8)
|
||||||
|
@ -12,11 +12,15 @@ import (
|
|||||||
type FIL BigInt
|
type FIL BigInt
|
||||||
|
|
||||||
func (f FIL) String() string {
|
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)))
|
r := new(big.Rat).SetFrac(f.Int, big.NewInt(int64(build.FilecoinPrecision)))
|
||||||
if r.Sign() == 0 {
|
if r.Sign() == 0 {
|
||||||
return "0 FIL"
|
return "0"
|
||||||
}
|
}
|
||||||
return strings.TrimRight(strings.TrimRight(r.FloatString(18), "0"), ".") + " FIL"
|
return strings.TrimRight(strings.TrimRight(r.FloatString(18), "0"), ".")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FIL) Format(s fmt.State, ch rune) {
|
func (f FIL) Format(s fmt.State, ch rune) {
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/wallet"
|
"github.com/filecoin-project/lotus/chain/wallet"
|
||||||
@ -22,7 +23,7 @@ func Address(i uint64) address.Address {
|
|||||||
return a
|
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{
|
msg := &types.Message{
|
||||||
To: to,
|
To: to,
|
||||||
From: from,
|
From: from,
|
||||||
@ -33,7 +34,7 @@ func MkMessage(from, to address.Address, nonce uint64, w *wallet.Wallet) *types.
|
|||||||
GasPremium: types.NewInt(1),
|
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 {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -59,9 +60,11 @@ func MkBlock(parents *types.TipSet, weightInc uint64, ticketNonce uint64) *types
|
|||||||
var pcids []cid.Cid
|
var pcids []cid.Cid
|
||||||
var height abi.ChainEpoch
|
var height abi.ChainEpoch
|
||||||
weight := types.NewInt(weightInc)
|
weight := types.NewInt(weightInc)
|
||||||
|
var timestamp uint64
|
||||||
if parents != nil {
|
if parents != nil {
|
||||||
pcids = parents.Cids()
|
pcids = parents.Cids()
|
||||||
height = parents.Height() + 1
|
height = parents.Height() + 1
|
||||||
|
timestamp = parents.MinTimestamp() + build.BlockDelaySecs
|
||||||
weight = types.BigAdd(parents.Blocks()[0].ParentWeight, weight)
|
weight = types.BigAdd(parents.Blocks()[0].ParentWeight, weight)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,6 +82,7 @@ func MkBlock(parents *types.TipSet, weightInc uint64, ticketNonce uint64) *types
|
|||||||
ParentWeight: weight,
|
ParentWeight: weight,
|
||||||
Messages: c,
|
Messages: c,
|
||||||
Height: height,
|
Height: height,
|
||||||
|
Timestamp: timestamp,
|
||||||
ParentStateRoot: pstateRoot,
|
ParentStateRoot: pstateRoot,
|
||||||
BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte("boo! im a signature")},
|
BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte("boo! im a signature")},
|
||||||
ParentBaseFee: types.NewInt(uint64(build.MinimumBaseFee)),
|
ParentBaseFee: types.NewInt(uint64(build.MinimumBaseFee)),
|
||||||
|
@ -2,9 +2,20 @@ package types
|
|||||||
|
|
||||||
import "github.com/ipfs/go-cid"
|
import "github.com/ipfs/go-cid"
|
||||||
|
|
||||||
|
// StateTreeVersion is the version of the state tree itself, independent of the
|
||||||
|
// network version or the actors version.
|
||||||
|
type StateTreeVersion uint64
|
||||||
|
|
||||||
|
const (
|
||||||
|
// StateTreeVersion0 corresponds to actors < v2.
|
||||||
|
StateTreeVersion0 StateTreeVersion = iota
|
||||||
|
// StateTreeVersion1 corresponds to actors >= v2.
|
||||||
|
StateTreeVersion1
|
||||||
|
)
|
||||||
|
|
||||||
type StateRoot struct {
|
type StateRoot struct {
|
||||||
// State root version. Versioned along with actors (for now).
|
// State tree version.
|
||||||
Version uint64
|
Version StateTreeVersion
|
||||||
// Actors tree. The structure depends on the state root version.
|
// Actors tree. The structure depends on the state root version.
|
||||||
Actors cid.Cid
|
Actors cid.Cid
|
||||||
// Info. The structure depends on the state root version.
|
// Info. The structure depends on the state root version.
|
||||||
@ -12,4 +23,4 @@ type StateRoot struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: version this.
|
// TODO: version this.
|
||||||
type StateInfo struct{}
|
type StateInfo0 struct{}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@ -61,11 +62,11 @@ func MakeMessageSigningVectors() []vectors.MessageSigningVector {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
blsk, err := w.GenerateKey(crypto.SigTypeBLS)
|
blsk, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
bki, err := w.Export(blsk)
|
bki, err := w.WalletExport(context.Background(), blsk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -85,11 +86,11 @@ func MakeMessageSigningVectors() []vectors.MessageSigningVector {
|
|||||||
Signature: &bmsg.Signature,
|
Signature: &bmsg.Signature,
|
||||||
}
|
}
|
||||||
|
|
||||||
secpk, err := w.GenerateKey(crypto.SigTypeBLS)
|
secpk, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
ski, err := w.Export(secpk)
|
ski, err := w.WalletExport(context.Background(), secpk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -70,12 +70,12 @@ func (ar *ActorRegistry) Invoke(codeCid cid.Cid, rt vmr.Runtime, method abi.Meth
|
|||||||
log.Errorf("no code for actor %s (Addr: %s)", codeCid, rt.Receiver())
|
log.Errorf("no code for actor %s (Addr: %s)", codeCid, rt.Receiver())
|
||||||
return nil, aerrors.Newf(exitcode.SysErrorIllegalActor, "no code for actor %s(%d)(%s)", codeCid, method, hex.EncodeToString(params))
|
return nil, aerrors.Newf(exitcode.SysErrorIllegalActor, "no code for actor %s(%d)(%s)", codeCid, method, hex.EncodeToString(params))
|
||||||
}
|
}
|
||||||
|
if err := act.predicate(rt, act.vmActor); err != nil {
|
||||||
|
return nil, aerrors.Newf(exitcode.SysErrorIllegalActor, "unsupported actor: %s", err)
|
||||||
|
}
|
||||||
if method >= abi.MethodNum(len(act.methods)) || act.methods[method] == nil {
|
if method >= abi.MethodNum(len(act.methods)) || act.methods[method] == nil {
|
||||||
return nil, aerrors.Newf(exitcode.SysErrInvalidMethod, "no method %d on actor", method)
|
return nil, aerrors.Newf(exitcode.SysErrInvalidMethod, "no method %d on actor", method)
|
||||||
}
|
}
|
||||||
if err := act.predicate(rt, act.vmActor); err != nil {
|
|
||||||
return nil, aerrors.Newf(exitcode.SysErrInvalidMethod, "unsupported actor: %s", err)
|
|
||||||
}
|
|
||||||
return act.methods[method](rt, params)
|
return act.methods[method](rt, params)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,9 @@ func (m *Message) ValueReceived() abi.TokenAmount {
|
|||||||
return m.msg.Value
|
return m.msg.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnableGasTracing, if true, outputs gas tracing in execution traces.
|
||||||
|
var EnableGasTracing = false
|
||||||
|
|
||||||
type Runtime struct {
|
type Runtime struct {
|
||||||
rt0.Message
|
rt0.Message
|
||||||
rt0.Syscalls
|
rt0.Syscalls
|
||||||
@ -477,7 +480,7 @@ func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (rt *Runtime) finilizeGasTracing() {
|
func (rt *Runtime) finilizeGasTracing() {
|
||||||
if enableTracing {
|
if EnableGasTracing {
|
||||||
if rt.lastGasCharge != nil {
|
if rt.lastGasCharge != nil {
|
||||||
rt.lastGasCharge.TimeTaken = time.Since(rt.lastGasChargeTime)
|
rt.lastGasCharge.TimeTaken = time.Since(rt.lastGasChargeTime)
|
||||||
}
|
}
|
||||||
@ -509,11 +512,9 @@ func (rt *Runtime) chargeGasFunc(skip int) func(GasCharge) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var enableTracing = false
|
|
||||||
|
|
||||||
func (rt *Runtime) chargeGasInternal(gas GasCharge, skip int) aerrors.ActorError {
|
func (rt *Runtime) chargeGasInternal(gas GasCharge, skip int) aerrors.ActorError {
|
||||||
toUse := gas.Total()
|
toUse := gas.Total()
|
||||||
if enableTracing {
|
if EnableGasTracing {
|
||||||
var callers [10]uintptr
|
var callers [10]uintptr
|
||||||
|
|
||||||
cout := 0 //gruntime.Callers(2+skip, callers[:])
|
cout := 0 //gruntime.Callers(2+skip, callers[:])
|
||||||
|
@ -45,3 +45,23 @@ func TestRuntimePutErrors(t *testing.T) {
|
|||||||
rt.StorePut(&NotAVeryGoodMarshaler{})
|
rt.StorePut(&NotAVeryGoodMarshaler{})
|
||||||
t.Error("expected panic")
|
t.Error("expected panic")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkRuntime_CreateRuntimeChargeGas_TracingDisabled(b *testing.B) {
|
||||||
|
var (
|
||||||
|
cst = cbor.NewCborStore(nil)
|
||||||
|
gch = newGasCharge("foo", 1000, 1000)
|
||||||
|
)
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
EnableGasTracing = false
|
||||||
|
noop := func() bool { return EnableGasTracing }
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
// flip the value and access it to make sure
|
||||||
|
// the compiler doesn't optimize away
|
||||||
|
EnableGasTracing = true
|
||||||
|
_ = noop()
|
||||||
|
EnableGasTracing = false
|
||||||
|
_ = (&Runtime{cst: cst}).chargeGasInternal(gch, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -236,7 +236,7 @@ func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
|
|||||||
}
|
}
|
||||||
|
|
||||||
rt := vm.makeRuntime(ctx, msg, origin, on, gasUsed, nac)
|
rt := vm.makeRuntime(ctx, msg, origin, on, gasUsed, nac)
|
||||||
if enableTracing {
|
if EnableGasTracing {
|
||||||
rt.lastGasChargeTime = start
|
rt.lastGasChargeTime = start
|
||||||
if parent != nil {
|
if parent != nil {
|
||||||
rt.lastGasChargeTime = parent.lastGasChargeTime
|
rt.lastGasChargeTime = parent.lastGasChargeTime
|
||||||
|
81
chain/wallet/key.go
Normal file
81
chain/wallet/key.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
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 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func kstoreSigType(typ crypto.SigType) string {
|
||||||
|
switch typ {
|
||||||
|
case crypto.SigTypeBLS:
|
||||||
|
return KTBLS
|
||||||
|
case crypto.SigTypeSecp256k1:
|
||||||
|
return KTSecp256k1
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ActSigType(typ string) crypto.SigType {
|
||||||
|
switch typ {
|
||||||
|
case KTBLS:
|
||||||
|
return crypto.SigTypeBLS
|
||||||
|
case KTSecp256k1:
|
||||||
|
return crypto.SigTypeSecp256k1
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
42
chain/wallet/remotewallet/remote.go
Normal file
42
chain/wallet/remotewallet/remote.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"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/bls" // enable bls signatures
|
||||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp" // enable secp signatures
|
_ "github.com/filecoin-project/lotus/lib/sigs/secp" // enable secp signatures
|
||||||
|
|
||||||
@ -29,15 +30,20 @@ const (
|
|||||||
KTSecp256k1 = "secp256k1"
|
KTSecp256k1 = "secp256k1"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Wallet struct {
|
type LocalWallet struct {
|
||||||
keys map[address.Address]*Key
|
keys map[address.Address]*Key
|
||||||
keystore types.KeyStore
|
keystore types.KeyStore
|
||||||
|
|
||||||
lk sync.Mutex
|
lk sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWallet(keystore types.KeyStore) (*Wallet, error) {
|
type Default interface {
|
||||||
w := &Wallet{
|
GetDefault() (address.Address, error)
|
||||||
|
SetDefault(a address.Address) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWallet(keystore types.KeyStore) (*LocalWallet, error) {
|
||||||
|
w := &LocalWallet{
|
||||||
keys: make(map[address.Address]*Key),
|
keys: make(map[address.Address]*Key),
|
||||||
keystore: keystore,
|
keystore: keystore,
|
||||||
}
|
}
|
||||||
@ -45,18 +51,18 @@ func NewWallet(keystore types.KeyStore) (*Wallet, error) {
|
|||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func KeyWallet(keys ...*Key) *Wallet {
|
func KeyWallet(keys ...*Key) *LocalWallet {
|
||||||
m := make(map[address.Address]*Key)
|
m := make(map[address.Address]*Key)
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
m[key.Address] = key
|
m[key.Address] = key
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Wallet{
|
return &LocalWallet{
|
||||||
keys: m,
|
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)
|
ki, err := w.findKey(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -68,7 +74,7 @@ func (w *Wallet) Sign(ctx context.Context, addr address.Address, msg []byte) (*c
|
|||||||
return sigs.Sign(ActSigType(ki.Type), ki.PrivateKey, msg)
|
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()
|
w.lk.Lock()
|
||||||
defer w.lk.Unlock()
|
defer w.lk.Unlock()
|
||||||
|
|
||||||
@ -96,7 +102,7 @@ func (w *Wallet) findKey(addr address.Address) (*Key, error) {
|
|||||||
return k, nil
|
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())
|
ki, err := w.keystore.Get(KNamePrefix + addr.String())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -110,14 +116,12 @@ func (w *Wallet) tryFind(addr address.Address) (types.KeyInfo, error) {
|
|||||||
// We got an ErrKeyInfoNotFound error
|
// We got an ErrKeyInfoNotFound error
|
||||||
// Try again, this time with the testnet prefix
|
// Try again, this time with the testnet prefix
|
||||||
|
|
||||||
aChars := []rune(addr.String())
|
tAddress, err := swapMainnetForTestnetPrefix(addr.String())
|
||||||
prefixRunes := []rune(address.TestnetPrefix)
|
if err != nil {
|
||||||
if len(prefixRunes) != 1 {
|
return types.KeyInfo{}, err
|
||||||
return types.KeyInfo{}, xerrors.Errorf("unexpected prefix length: %d", len(prefixRunes))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
aChars[0] = prefixRunes[0]
|
ki, err = w.keystore.Get(KNamePrefix + tAddress)
|
||||||
ki, err = w.keystore.Get(KNamePrefix + string(aChars))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.KeyInfo{}, err
|
return types.KeyInfo{}, err
|
||||||
}
|
}
|
||||||
@ -132,16 +136,19 @@ func (w *Wallet) tryFind(addr address.Address) (types.KeyInfo, error) {
|
|||||||
return ki, nil
|
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)
|
k, err := w.findKey(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to find key to export: %w", err)
|
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
|
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()
|
w.lk.Lock()
|
||||||
defer w.lk.Unlock()
|
defer w.lk.Unlock()
|
||||||
|
|
||||||
@ -157,7 +164,7 @@ func (w *Wallet) Import(ki *types.KeyInfo) (address.Address, error) {
|
|||||||
return k.Address, nil
|
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()
|
all, err := w.keystore.List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("listing keystore: %w", err)
|
return nil, xerrors.Errorf("listing keystore: %w", err)
|
||||||
@ -190,7 +197,7 @@ func (w *Wallet) ListAddrs() ([]address.Address, error) {
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Wallet) GetDefault() (address.Address, error) {
|
func (w *LocalWallet) GetDefault() (address.Address, error) {
|
||||||
w.lk.Lock()
|
w.lk.Lock()
|
||||||
defer w.lk.Unlock()
|
defer w.lk.Unlock()
|
||||||
|
|
||||||
@ -207,7 +214,7 @@ func (w *Wallet) GetDefault() (address.Address, error) {
|
|||||||
return k.Address, nil
|
return k.Address, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Wallet) SetDefault(a address.Address) error {
|
func (w *LocalWallet) SetDefault(a address.Address) error {
|
||||||
w.lk.Lock()
|
w.lk.Lock()
|
||||||
defer w.lk.Unlock()
|
defer w.lk.Unlock()
|
||||||
|
|
||||||
@ -229,19 +236,7 @@ func (w *Wallet) SetDefault(a address.Address) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateKey(typ crypto.SigType) (*Key, error) {
|
func (w *LocalWallet) WalletNew(ctx context.Context, typ crypto.SigType) (address.Address, 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) {
|
|
||||||
w.lk.Lock()
|
w.lk.Lock()
|
||||||
defer w.lk.Unlock()
|
defer w.lk.Unlock()
|
||||||
|
|
||||||
@ -269,7 +264,7 @@ func (w *Wallet) GenerateKey(typ crypto.SigType) (address.Address, error) {
|
|||||||
return k.Address, nil
|
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)
|
k, err := w.findKey(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@ -277,11 +272,14 @@ func (w *Wallet) HasKey(addr address.Address) (bool, error) {
|
|||||||
return k != nil, nil
|
return k != nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Wallet) DeleteKey(addr address.Address) error {
|
func (w *LocalWallet) WalletDelete(ctx context.Context, addr address.Address) error {
|
||||||
k, err := w.findKey(addr)
|
k, err := w.findKey(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("failed to delete key %s : %w", addr, err)
|
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 {
|
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)
|
return xerrors.Errorf("failed to mark key %s as trashed: %w", addr, err)
|
||||||
@ -291,63 +289,26 @@ func (w *Wallet) DeleteKey(addr address.Address) error {
|
|||||||
return xerrors.Errorf("failed to delete key %s: %w", addr, err)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Key struct {
|
var _ api.WalletAPI = &LocalWallet{}
|
||||||
types.KeyInfo
|
|
||||||
|
|
||||||
PublicKey []byte
|
func swapMainnetForTestnetPrefix(addr string) (string, error) {
|
||||||
Address address.Address
|
aChars := []rune(addr)
|
||||||
}
|
prefixRunes := []rune(address.TestnetPrefix)
|
||||||
|
if len(prefixRunes) != 1 {
|
||||||
func NewKey(keyinfo types.KeyInfo) (*Key, error) {
|
return "", xerrors.Errorf("unexpected prefix length: %d", len(prefixRunes))
|
||||||
k := &Key{
|
}
|
||||||
KeyInfo: keyinfo,
|
|
||||||
}
|
aChars[0] = prefixRunes[0]
|
||||||
|
return string(aChars), nil
|
||||||
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
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func kstoreSigType(typ crypto.SigType) string {
|
|
||||||
switch typ {
|
|
||||||
case crypto.SigTypeBLS:
|
|
||||||
return KTBLS
|
|
||||||
case crypto.SigTypeSecp256k1:
|
|
||||||
return KTSecp256k1
|
|
||||||
default:
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ActSigType(typ string) crypto.SigType {
|
|
||||||
switch typ {
|
|
||||||
case KTBLS:
|
|
||||||
return crypto.SigTypeBLS
|
|
||||||
case KTSecp256k1:
|
|
||||||
return crypto.SigTypeSecp256k1
|
|
||||||
default:
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
18
cli/chain.go
18
cli/chain.go
@ -449,11 +449,16 @@ var chainInspectUsage = &cli.Command{
|
|||||||
bySender := make(map[string]int64)
|
bySender := make(map[string]int64)
|
||||||
byDest := make(map[string]int64)
|
byDest := make(map[string]int64)
|
||||||
byMethod := 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
|
var sum int64
|
||||||
for _, m := range msgs {
|
for _, m := range msgs {
|
||||||
bySender[m.Message.From.String()] += m.Message.GasLimit
|
bySender[m.Message.From.String()] += m.Message.GasLimit
|
||||||
|
bySenderC[m.Message.From.String()]++
|
||||||
byDest[m.Message.To.String()] += m.Message.GasLimit
|
byDest[m.Message.To.String()] += m.Message.GasLimit
|
||||||
|
byDestC[m.Message.To.String()]++
|
||||||
sum += m.Message.GasLimit
|
sum += m.Message.GasLimit
|
||||||
|
|
||||||
code, err := lookupActorCode(m.Message.To)
|
code, err := lookupActorCode(m.Message.To)
|
||||||
@ -464,7 +469,7 @@ var chainInspectUsage = &cli.Command{
|
|||||||
mm := stmgr.MethodsMap[code][m.Message.Method]
|
mm := stmgr.MethodsMap[code][m.Message.Method]
|
||||||
|
|
||||||
byMethod[mm.Name] += m.Message.GasLimit
|
byMethod[mm.Name] += m.Message.GasLimit
|
||||||
|
byMethodC[mm.Name]++
|
||||||
}
|
}
|
||||||
|
|
||||||
type keyGasPair struct {
|
type keyGasPair struct {
|
||||||
@ -496,19 +501,19 @@ var chainInspectUsage = &cli.Command{
|
|||||||
fmt.Printf("By Sender:\n")
|
fmt.Printf("By Sender:\n")
|
||||||
for i := 0; i < numRes && i < len(senderVals); i++ {
|
for i := 0; i < numRes && i < len(senderVals); i++ {
|
||||||
sv := 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.Println()
|
||||||
fmt.Printf("By Receiver:\n")
|
fmt.Printf("By Receiver:\n")
|
||||||
for i := 0; i < numRes && i < len(destVals); i++ {
|
for i := 0; i < numRes && i < len(destVals); i++ {
|
||||||
sv := 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.Println()
|
||||||
fmt.Printf("By Method:\n")
|
fmt.Printf("By Method:\n")
|
||||||
for i := 0; i < numRes && i < len(methodVals); i++ {
|
for i := 0; i < numRes && i < len(methodVals); i++ {
|
||||||
sv := 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
|
return nil
|
||||||
@ -516,8 +521,9 @@ var chainInspectUsage = &cli.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var chainListCmd = &cli.Command{
|
var chainListCmd = &cli.Command{
|
||||||
Name: "list",
|
Name: "list",
|
||||||
Usage: "View a segment of the chain",
|
Aliases: []string{"love"},
|
||||||
|
Usage: "View a segment of the chain",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.Uint64Flag{Name: "height"},
|
&cli.Uint64Flag{Name: "height"},
|
||||||
&cli.IntFlag{Name: "count", Value: 30},
|
&cli.IntFlag{Name: "count", Value: 30},
|
||||||
|
@ -536,7 +536,7 @@ func interactiveDeal(cctx *cli.Context) error {
|
|||||||
|
|
||||||
state = "miner"
|
state = "miner"
|
||||||
case "miner":
|
case "miner":
|
||||||
fmt.Print("Miner Address (t0..): ")
|
fmt.Print("Miner Address (f0..): ")
|
||||||
var maddrStr string
|
var maddrStr string
|
||||||
|
|
||||||
_, err := fmt.Scan(&maddrStr)
|
_, err := fmt.Scan(&maddrStr)
|
||||||
@ -1039,6 +1039,10 @@ var clientListDeals = &cli.Command{
|
|||||||
Usage: "use color in display output",
|
Usage: "use color in display output",
|
||||||
Value: true,
|
Value: true,
|
||||||
},
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "show-failed",
|
||||||
|
Usage: "show failed/failing deals",
|
||||||
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "watch",
|
Name: "watch",
|
||||||
Usage: "watch deal updates in real-time, rather than a one time list",
|
Usage: "watch deal updates in real-time, rather than a one time list",
|
||||||
@ -1055,6 +1059,7 @@ var clientListDeals = &cli.Command{
|
|||||||
verbose := cctx.Bool("verbose")
|
verbose := cctx.Bool("verbose")
|
||||||
color := cctx.Bool("color")
|
color := cctx.Bool("color")
|
||||||
watch := cctx.Bool("watch")
|
watch := cctx.Bool("watch")
|
||||||
|
showFailed := cctx.Bool("show-failed")
|
||||||
|
|
||||||
localDeals, err := api.ClientListDeals(ctx)
|
localDeals, err := api.ClientListDeals(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1071,7 +1076,7 @@ var clientListDeals = &cli.Command{
|
|||||||
tm.Clear()
|
tm.Clear()
|
||||||
tm.MoveCursor(1, 1)
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1097,7 +1102,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 +1125,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 {
|
sort.Slice(localDeals, func(i, j int) bool {
|
||||||
return localDeals[i].CreationTime.Before(localDeals[j].CreationTime)
|
return localDeals[i].CreationTime.Before(localDeals[j].CreationTime)
|
||||||
})
|
})
|
||||||
@ -1132,12 +1137,14 @@ func outputStorageDeals(ctx context.Context, out io.Writer, full api.FullNode, l
|
|||||||
|
|
||||||
var deals []deal
|
var deals []deal
|
||||||
for _, localDeal := range localDeals {
|
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 {
|
if verbose {
|
||||||
w := tabwriter.NewWriter(out, 2, 4, 2, ' ', 0)
|
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 {
|
for _, d := range deals {
|
||||||
onChain := "N"
|
onChain := "N"
|
||||||
if d.OnChainDealState.SectorStartEpoch != -1 {
|
if d.OnChainDealState.SectorStartEpoch != -1 {
|
||||||
@ -1150,7 +1157,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)))
|
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()
|
return w.Flush()
|
||||||
}
|
}
|
||||||
@ -1165,6 +1172,7 @@ func outputStorageDeals(ctx context.Context, out io.Writer, full api.FullNode, l
|
|||||||
tablewriter.Col("Size"),
|
tablewriter.Col("Size"),
|
||||||
tablewriter.Col("Price"),
|
tablewriter.Col("Price"),
|
||||||
tablewriter.Col("Duration"),
|
tablewriter.Col("Duration"),
|
||||||
|
tablewriter.Col("Verified"),
|
||||||
tablewriter.NewLineCol("Message"))
|
tablewriter.NewLineCol("Message"))
|
||||||
|
|
||||||
for _, d := range deals {
|
for _, d := range deals {
|
||||||
@ -1194,6 +1202,7 @@ func outputStorageDeals(ctx context.Context, out io.Writer, full api.FullNode, l
|
|||||||
"PieceCID": piece,
|
"PieceCID": piece,
|
||||||
"Size": types.SizeStr(types.NewInt(d.LocalDeal.Size)),
|
"Size": types.SizeStr(types.NewInt(d.LocalDeal.Size)),
|
||||||
"Price": price,
|
"Price": price,
|
||||||
|
"Verified": d.LocalDeal.Verified,
|
||||||
"Duration": d.LocalDeal.Duration,
|
"Duration": d.LocalDeal.Duration,
|
||||||
"Message": d.LocalDeal.Message,
|
"Message": d.LocalDeal.Message,
|
||||||
})
|
})
|
||||||
|
71
cli/cmd.go
71
cli/cmd.go
@ -11,8 +11,6 @@ import (
|
|||||||
|
|
||||||
logging "github.com/ipfs/go-log/v2"
|
logging "github.com/ipfs/go-log/v2"
|
||||||
"github.com/mitchellh/go-homedir"
|
"github.com/mitchellh/go-homedir"
|
||||||
"github.com/multiformats/go-multiaddr"
|
|
||||||
manet "github.com/multiformats/go-multiaddr/net"
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
@ -20,6 +18,7 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/api/client"
|
"github.com/filecoin-project/lotus/api/client"
|
||||||
|
cliutil "github.com/filecoin-project/lotus/cli/util"
|
||||||
"github.com/filecoin-project/lotus/node/repo"
|
"github.com/filecoin-project/lotus/node/repo"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -46,37 +45,16 @@ func NewCliError(s string) error {
|
|||||||
// ApiConnector returns API instance
|
// ApiConnector returns API instance
|
||||||
type ApiConnector func() api.FullNode
|
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
|
// The flag passed on the command line with the listen address of the API
|
||||||
// server (only used by the tests)
|
// server (only used by the tests)
|
||||||
func flagForAPI(t repo.RepoType) string {
|
func flagForAPI(t repo.RepoType) string {
|
||||||
switch t {
|
switch t {
|
||||||
case repo.FullNode:
|
case repo.FullNode:
|
||||||
return "api"
|
return "api-url"
|
||||||
case repo.StorageMiner:
|
case repo.StorageMiner:
|
||||||
return "miner-api"
|
return "miner-api-url"
|
||||||
case repo.Worker:
|
case repo.Worker:
|
||||||
return "worker-api"
|
return "worker-api-url"
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("Unknown repo type: %v", t))
|
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
|
// Check if there was a flag passed with the listen address of the API
|
||||||
// server (only used by the tests)
|
// server (only used by the tests)
|
||||||
apiFlag := flagForAPI(t)
|
apiFlag := flagForAPI(t)
|
||||||
@ -130,11 +108,7 @@ func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
|
|||||||
strma := ctx.String(apiFlag)
|
strma := ctx.String(apiFlag)
|
||||||
strma = strings.TrimSpace(strma)
|
strma = strings.TrimSpace(strma)
|
||||||
|
|
||||||
apima, err := multiaddr.NewMultiaddr(strma)
|
return cliutil.APIInfo{Addr: strma}, nil
|
||||||
if err != nil {
|
|
||||||
return APIInfo{}, err
|
|
||||||
}
|
|
||||||
return APIInfo{Addr: apima}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
envKey := envForRepo(t)
|
envKey := envForRepo(t)
|
||||||
@ -148,36 +122,24 @@ func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ok {
|
if ok {
|
||||||
sp := strings.SplitN(env, ":", 2)
|
return cliutil.ParseApiInfo(env), nil
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
repoFlag := flagForRepo(t)
|
repoFlag := flagForRepo(t)
|
||||||
|
|
||||||
p, err := homedir.Expand(ctx.String(repoFlag))
|
p, err := homedir.Expand(ctx.String(repoFlag))
|
||||||
if err != nil {
|
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)
|
r, err := repo.NewFS(p)
|
||||||
if err != nil {
|
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()
|
ma, err := r.APIEndpoint()
|
||||||
if err != nil {
|
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()
|
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)
|
log.Warnf("Couldn't load CLI token, capabilities may be limited: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return APIInfo{
|
return cliutil.APIInfo{
|
||||||
Addr: ma,
|
Addr: ma.String(),
|
||||||
Token: token,
|
Token: token,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -266,6 +228,15 @@ func GetWorkerAPI(ctx *cli.Context) (api.WorkerAPI, jsonrpc.ClientCloser, error)
|
|||||||
return client.NewWorkerRPC(ctx.Context, addr, headers)
|
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 {
|
func DaemonContext(cctx *cli.Context) context.Context {
|
||||||
if mtCtx, ok := cctx.App.Metadata[metadataTraceContext]; ok {
|
if mtCtx, ok := cctx.App.Metadata[metadataTraceContext]; ok {
|
||||||
return mtCtx.(context.Context)
|
return mtCtx.(context.Context)
|
||||||
|
@ -35,7 +35,7 @@ func RunApp(app *cli.App) {
|
|||||||
if os.Getenv("LOTUS_DEV") != "" {
|
if os.Getenv("LOTUS_DEV") != "" {
|
||||||
log.Warnf("%+v", err)
|
log.Warnf("%+v", err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("ERROR: %s\n\n", err)
|
fmt.Fprintf(os.Stderr, "ERROR: %s\n\n", err) // nolint:errcheck
|
||||||
}
|
}
|
||||||
var phe *PrintHelpErr
|
var phe *PrintHelpErr
|
||||||
if xerrors.As(err, &phe) {
|
if xerrors.As(err, &phe) {
|
||||||
|
@ -3,8 +3,10 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
@ -14,6 +16,8 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"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"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
|
|
||||||
@ -174,6 +178,10 @@ var msigInspectCmd = &cli.Command{
|
|||||||
Name: "vesting",
|
Name: "vesting",
|
||||||
Usage: "Include vesting details",
|
Usage: "Include vesting details",
|
||||||
},
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "decode-params",
|
||||||
|
Usage: "Decode parameters of transaction proposals",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
if !cctx.Args().Present() {
|
if !cctx.Args().Present() {
|
||||||
@ -204,6 +212,11 @@ var msigInspectCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ownId, err := api.StateLookupID(ctx, maddr, types.EmptyTSK)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
mstate, err := multisig.Load(store, act)
|
mstate, err := multisig.Load(store, act)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -256,6 +269,7 @@ var msigInspectCmd = &cli.Command{
|
|||||||
return xerrors.Errorf("reading pending transactions: %w", err)
|
return xerrors.Errorf("reading pending transactions: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
decParams := cctx.Bool("decode-params")
|
||||||
fmt.Println("Transactions: ", len(pending))
|
fmt.Println("Transactions: ", len(pending))
|
||||||
if len(pending) > 0 {
|
if len(pending) > 0 {
|
||||||
var txids []int64
|
var txids []int64
|
||||||
@ -266,11 +280,36 @@ var msigInspectCmd = &cli.Command{
|
|||||||
return txids[i] < txids[j]
|
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")
|
fmt.Fprintf(w, "ID\tState\tApprovals\tTo\tValue\tMethod\tParams\n")
|
||||||
for _, txid := range txids {
|
for _, txid := range txids {
|
||||||
tx := pending[txid]
|
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 {
|
if err := w.Flush(); err != nil {
|
||||||
return xerrors.Errorf("flushing output: %+v", err)
|
return xerrors.Errorf("flushing output: %+v", err)
|
||||||
@ -398,7 +437,7 @@ var msigProposeCmd = &cli.Command{
|
|||||||
var msigApproveCmd = &cli.Command{
|
var msigApproveCmd = &cli.Command{
|
||||||
Name: "approve",
|
Name: "approve",
|
||||||
Usage: "Approve a multisig message",
|
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{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "from",
|
Name: "from",
|
||||||
@ -484,7 +523,7 @@ var msigApproveCmd = &cli.Command{
|
|||||||
from = defaddr
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1129,7 +1168,7 @@ var msigLockApproveCmd = &cli.Command{
|
|||||||
return actErr
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -121,13 +121,13 @@ func TestPaymentChannelStatus(t *testing.T) {
|
|||||||
create := make(chan string)
|
create := make(chan string)
|
||||||
go func() {
|
go func() {
|
||||||
// creator: paych add-funds <creator> <receiver> <amount>
|
// 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)
|
create <- creatorCLI.runCmd(paychAddFundsCmd, cmd)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Wait for the output to stop being "Channel does not exist"
|
// Wait for the output to stop being "Channel does not exist"
|
||||||
for regexp.MustCompile(noChannelState).MatchString(out) {
|
for regexp.MustCompile(noChannelState).MatchString(out) {
|
||||||
cmd = []string{creatorAddr.String(), receiverAddr.String()}
|
cmd := []string{creatorAddr.String(), receiverAddr.String()}
|
||||||
out = creatorCLI.runCmd(paychStatusByFromToCmd, cmd)
|
out = creatorCLI.runCmd(paychStatusByFromToCmd, cmd)
|
||||||
}
|
}
|
||||||
fmt.Println(out)
|
fmt.Println(out)
|
||||||
@ -390,7 +390,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) {
|
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]
|
paymentCreator := n[0]
|
||||||
paymentReceiver := n[1]
|
paymentReceiver := n[1]
|
||||||
@ -439,12 +439,12 @@ type mockCLI struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newMockCLI(t *testing.T) *mockCLI {
|
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
|
// the command should be executed against
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
app.Flags = []cli.Flag{
|
app.Flags = []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "api",
|
Name: "api-url",
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -476,8 +476,8 @@ func (c *mockCLIClient) runCmd(cmd *cli.Command, input []string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *mockCLIClient) runCmdRaw(cmd *cli.Command, input []string) (string, error) {
|
func (c *mockCLIClient) runCmdRaw(cmd *cli.Command, input []string) (string, error) {
|
||||||
// prepend --api=<node api listener address>
|
// prepend --api-url=<node api listener address>
|
||||||
apiFlag := "--api=" + c.addr.String()
|
apiFlag := "--api-url=" + c.addr.String()
|
||||||
input = append([]string{apiFlag}, input...)
|
input = append([]string{apiFlag}, input...)
|
||||||
|
|
||||||
fs := c.flagSet(cmd)
|
fs := c.flagSet(cmd)
|
||||||
@ -493,7 +493,7 @@ func (c *mockCLIClient) runCmdRaw(cmd *cli.Command, input []string) (string, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *mockCLIClient) flagSet(cmd *cli.Command) *flag.FlagSet {
|
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{}
|
fs := &flag.FlagSet{}
|
||||||
for _, f := range c.cctx.App.Flags {
|
for _, f := range c.cctx.App.Flags {
|
||||||
err := f.Apply(fs)
|
err := f.Apply(fs)
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/node/repo"
|
"github.com/filecoin-project/lotus/node/repo"
|
||||||
manet "github.com/multiformats/go-multiaddr/net"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var pprofCmd = &cli.Command{
|
var pprofCmd = &cli.Command{
|
||||||
@ -37,7 +36,7 @@ var PprofGoroutines = &cli.Command{
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("could not get API info: %w", err)
|
return xerrors.Errorf("could not get API info: %w", err)
|
||||||
}
|
}
|
||||||
_, addr, err := manet.DialArgs(ainfo.Addr)
|
addr, err := ainfo.Host()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
98
cli/state.go
98
cli/state.go
@ -7,6 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
@ -32,6 +33,7 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/exitcode"
|
"github.com/filecoin-project/go-state-types/exitcode"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
lapi "github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/api/apibstore"
|
"github.com/filecoin-project/lotus/api/apibstore"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/state"
|
"github.com/filecoin-project/lotus/chain/state"
|
||||||
@ -70,6 +72,7 @@ var stateCmd = &cli.Command{
|
|||||||
stateMsgCostCmd,
|
stateMsgCostCmd,
|
||||||
stateMinerInfo,
|
stateMinerInfo,
|
||||||
stateMarketCmd,
|
stateMarketCmd,
|
||||||
|
stateExecTraceCmd,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,6 +316,74 @@ var stateActiveSectorsCmd = &cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var stateExecTraceCmd = &cli.Command{
|
||||||
|
Name: "exec-trace",
|
||||||
|
Usage: "Get the execution trace of a given message",
|
||||||
|
ArgsUsage: "<messageCid>",
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
if !cctx.Args().Present() {
|
||||||
|
return ShowHelp(cctx, fmt.Errorf("must pass message cid"))
|
||||||
|
}
|
||||||
|
|
||||||
|
mcid, err := cid.Decode(cctx.Args().First())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("message cid was invalid: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
capi, closer, err := GetFullNodeAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
|
||||||
|
ctx := ReqContext(cctx)
|
||||||
|
|
||||||
|
msg, err := capi.ChainGetMessage(ctx, mcid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
lookup, err := capi.StateSearchMsg(ctx, mcid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ts, err := capi.ChainGetTipSet(ctx, lookup.TipSet)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pts, err := capi.ChainGetTipSet(ctx, ts.Parents())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cso, err := capi.StateCompute(ctx, pts.Height(), nil, pts.Key())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var trace *api.InvocResult
|
||||||
|
for _, t := range cso.Trace {
|
||||||
|
if t.Msg.From == msg.From && t.Msg.Nonce == msg.Nonce {
|
||||||
|
trace = t
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if trace == nil {
|
||||||
|
return fmt.Errorf("failed to find message in tipset trace output")
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := json.MarshalIndent(trace, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(out))
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
var stateReplaySetCmd = &cli.Command{
|
var stateReplaySetCmd = &cli.Command{
|
||||||
Name: "replay",
|
Name: "replay",
|
||||||
Usage: "Replay a particular message within a tipset",
|
Usage: "Replay a particular message within a tipset",
|
||||||
@ -823,6 +894,10 @@ var stateComputeStateCmd = &cli.Command{
|
|||||||
Name: "json",
|
Name: "json",
|
||||||
Usage: "generate json output",
|
Usage: "generate json output",
|
||||||
},
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "compute-state-output",
|
||||||
|
Usage: "a json file containing pre-existing compute-state output, to generate html reports without rerunning state changes",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
api, closer, err := GetFullNodeAPI(cctx)
|
api, closer, err := GetFullNodeAPI(cctx)
|
||||||
@ -862,9 +937,26 @@ var stateComputeStateCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stout, err := api.StateCompute(ctx, h, msgs, ts.Key())
|
var stout *lapi.ComputeStateOutput
|
||||||
if err != nil {
|
if csofile := cctx.String("compute-state-output"); csofile != "" {
|
||||||
return err
|
data, err := ioutil.ReadFile(csofile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var o lapi.ComputeStateOutput
|
||||||
|
if err := json.Unmarshal(data, &o); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
stout = &o
|
||||||
|
} else {
|
||||||
|
o, err := api.StateCompute(ctx, h, msgs, ts.Key())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
stout = o
|
||||||
}
|
}
|
||||||
|
|
||||||
if cctx.Bool("json") {
|
if cctx.Bool("json") {
|
||||||
|
26
cli/sync.go
26
cli/sync.go
@ -122,8 +122,14 @@ var syncMarkBadCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var syncUnmarkBadCmd = &cli.Command{
|
var syncUnmarkBadCmd = &cli.Command{
|
||||||
Name: "unmark-bad",
|
Name: "unmark-bad",
|
||||||
Usage: "Unmark the given block as bad, makes it possible to sync to a chain containing it",
|
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]",
|
ArgsUsage: "[blockCid]",
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
napi, closer, err := GetFullNodeAPI(cctx)
|
napi, closer, err := GetFullNodeAPI(cctx)
|
||||||
@ -133,6 +139,10 @@ var syncUnmarkBadCmd = &cli.Command{
|
|||||||
defer closer()
|
defer closer()
|
||||||
ctx := ReqContext(cctx)
|
ctx := ReqContext(cctx)
|
||||||
|
|
||||||
|
if cctx.Bool("all") {
|
||||||
|
return napi.SyncUnmarkAllBad(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
if !cctx.Args().Present() {
|
if !cctx.Args().Present() {
|
||||||
return fmt.Errorf("must specify block cid to unmark")
|
return fmt.Errorf("must specify block cid to unmark")
|
||||||
}
|
}
|
||||||
@ -233,7 +243,13 @@ func SyncWait(ctx context.Context, napi api.FullNode) error {
|
|||||||
|
|
||||||
samples := 8
|
samples := 8
|
||||||
i := 0
|
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 {
|
for {
|
||||||
state, err := napi.SyncState(ctx)
|
state, err := napi.SyncState(ctx)
|
||||||
@ -286,10 +302,10 @@ func SyncWait(ctx context.Context, napi api.FullNode) error {
|
|||||||
|
|
||||||
if i%samples == 0 {
|
if i%samples == 0 {
|
||||||
lastApp = app
|
lastApp = app
|
||||||
app = state.VMApplied
|
app = state.VMApplied - firstApp
|
||||||
}
|
}
|
||||||
if i > 0 {
|
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++
|
lastLines++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
83
cli/util/apiinfo.go
Normal file
83
cli/util/apiinfo.go
Normal file
@ -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
|
||||||
|
}
|
@ -183,7 +183,7 @@ var importBenchCmd = &cli.Command{
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cs := store.NewChainStore(bs, ds, vm.Syscalls(verifier))
|
cs := store.NewChainStore(bs, ds, vm.Syscalls(verifier), nil)
|
||||||
stm := stmgr.NewStateManager(cs)
|
stm := stmgr.NewStateManager(cs)
|
||||||
|
|
||||||
if cctx.Bool("global-profile") {
|
if cctx.Bool("global-profile") {
|
||||||
|
@ -6,85 +6,174 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"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/api"
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/node/impl/full"
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const LookbackCap = time.Hour
|
const (
|
||||||
|
LookbackCap = time.Hour
|
||||||
|
stateWaitLookbackLimit = abi.ChainEpoch(20)
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrLookbackTooLong = fmt.Errorf("lookbacks of more than %s are disallowed", LookbackCap)
|
ErrLookbackTooLong = fmt.Errorf("lookbacks of more than %s are disallowed", LookbackCap)
|
||||||
)
|
)
|
||||||
|
|
||||||
type GatewayAPI struct {
|
// gatewayDepsAPI defines the API methods that the GatewayAPI depends on
|
||||||
api api.FullNode
|
// (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() {
|
if tsk.IsEmpty() {
|
||||||
return time.Now(), nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ts, err := a.api.ChainGetTipSet(ctx, tsk)
|
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 {
|
if err != nil {
|
||||||
return err
|
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 ErrLookbackTooLong
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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) {
|
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)
|
// TODO: cache and invalidate cache when timestamp is up (or have internal ChainNotify)
|
||||||
|
|
||||||
return a.api.ChainHead(ctx)
|
return a.api.ChainHead(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *GatewayAPI) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
|
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)
|
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) {
|
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
|
// TODO: additional anti-spam checks
|
||||||
|
|
||||||
return a.api.MpoolPushUntrusted(ctx, sm)
|
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)
|
||||||
|
191
cmd/lotus-gateway/api_test.go
Normal file
191
cmd/lotus-gateway/api_test.go
Normal file
@ -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")
|
||||||
|
}
|
211
cmd/lotus-gateway/endtoend_test.go
Normal file
211
cmd/lotus-gateway/endtoend_test.go
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
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/chain/wallet"
|
||||||
|
"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, wallet.ActSigType("secp256k1"))
|
||||||
|
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, wallet.ActSigType("secp256k1"))
|
||||||
|
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
|
||||||
|
}
|
@ -40,12 +40,12 @@ func main() {
|
|||||||
return fmt.Errorf("unrecognized key type: %q", cctx.String("type"))
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ki, err := w.Export(kaddr)
|
ki, err := w.WalletExport(cctx.Context, kaddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
|
||||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||||
@ -37,6 +38,7 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/tools/stats"
|
"github.com/filecoin-project/lotus/tools/stats"
|
||||||
@ -342,6 +344,18 @@ var runCmd = &cli.Command{
|
|||||||
Usage: "process ProveCommitSector messages",
|
Usage: "process ProveCommitSector messages",
|
||||||
Value: true,
|
Value: true,
|
||||||
},
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "windowed-post",
|
||||||
|
EnvVars: []string{"LOTUS_PCR_WINDOWED_POST"},
|
||||||
|
Usage: "process SubmitWindowedPoSt messages and refund gas fees",
|
||||||
|
Value: false,
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "storage-deals",
|
||||||
|
EnvVars: []string{"LOTUS_PCR_STORAGE_DEALS"},
|
||||||
|
Usage: "process PublishStorageDeals messages and refund gas fees",
|
||||||
|
Value: false,
|
||||||
|
},
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
Name: "head-delay",
|
Name: "head-delay",
|
||||||
EnvVars: []string{"LOTUS_PCR_HEAD_DELAY"},
|
EnvVars: []string{"LOTUS_PCR_HEAD_DELAY"},
|
||||||
@ -378,6 +392,18 @@ var runCmd = &cli.Command{
|
|||||||
Usage: "percent of refund to issue",
|
Usage: "percent of refund to issue",
|
||||||
Value: 110,
|
Value: 110,
|
||||||
},
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
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.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.000000001",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
go func() {
|
go func() {
|
||||||
@ -421,6 +447,8 @@ var runCmd = &cli.Command{
|
|||||||
dryRun := cctx.Bool("dry-run")
|
dryRun := cctx.Bool("dry-run")
|
||||||
preCommitEnabled := cctx.Bool("pre-commit")
|
preCommitEnabled := cctx.Bool("pre-commit")
|
||||||
proveCommitEnabled := cctx.Bool("prove-commit")
|
proveCommitEnabled := cctx.Bool("prove-commit")
|
||||||
|
windowedPoStEnabled := cctx.Bool("windowed-post")
|
||||||
|
publishStorageDealsEnabled := cctx.Bool("storage-deals")
|
||||||
aggregateTipsets := cctx.Int("aggregate-tipsets")
|
aggregateTipsets := cctx.Int("aggregate-tipsets")
|
||||||
minerRecoveryEnabled := cctx.Bool("miner-recovery")
|
minerRecoveryEnabled := cctx.Bool("miner-recovery")
|
||||||
minerRecoveryPeriod := abi.ChainEpoch(int64(cctx.Int("miner-recovery-period")))
|
minerRecoveryPeriod := abi.ChainEpoch(int64(cctx.Int("miner-recovery-period")))
|
||||||
@ -428,6 +456,16 @@ var runCmd = &cli.Command{
|
|||||||
minerRecoveryCutoff := uint64(cctx.Int("miner-recovery-cutoff"))
|
minerRecoveryCutoff := uint64(cctx.Int("miner-recovery-cutoff"))
|
||||||
minerRecoveryBonus := uint64(cctx.Int("miner-recovery-bonus"))
|
minerRecoveryBonus := uint64(cctx.Int("miner-recovery-bonus"))
|
||||||
|
|
||||||
|
preFeeCapMax, err := types.ParseFIL(cctx.String("pre-fee-cap-max"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
proveFeeCapMax, err := types.ParseFIL(cctx.String("prove-fee-cap-max"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
rf := &refunder{
|
rf := &refunder{
|
||||||
api: api,
|
api: api,
|
||||||
wallet: from,
|
wallet: from,
|
||||||
@ -438,6 +476,10 @@ var runCmd = &cli.Command{
|
|||||||
dryRun: dryRun,
|
dryRun: dryRun,
|
||||||
preCommitEnabled: preCommitEnabled,
|
preCommitEnabled: preCommitEnabled,
|
||||||
proveCommitEnabled: proveCommitEnabled,
|
proveCommitEnabled: proveCommitEnabled,
|
||||||
|
windowedPoStEnabled: windowedPoStEnabled,
|
||||||
|
publishStorageDealsEnabled: publishStorageDealsEnabled,
|
||||||
|
preFeeCapMax: types.BigInt(preFeeCapMax),
|
||||||
|
proveFeeCapMax: types.BigInt(proveFeeCapMax),
|
||||||
}
|
}
|
||||||
|
|
||||||
var refunds *MinersRefund = NewMinersRefund()
|
var refunds *MinersRefund = NewMinersRefund()
|
||||||
@ -589,7 +631,12 @@ type refunder struct {
|
|||||||
dryRun bool
|
dryRun bool
|
||||||
preCommitEnabled bool
|
preCommitEnabled bool
|
||||||
proveCommitEnabled bool
|
proveCommitEnabled bool
|
||||||
|
windowedPoStEnabled bool
|
||||||
|
publishStorageDealsEnabled bool
|
||||||
threshold big.Int
|
threshold big.Int
|
||||||
|
|
||||||
|
preFeeCapMax big.Int
|
||||||
|
proveFeeCapMax big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *refunder) FindMiners(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund, owner, worker, control bool) (*MinersRefund, error) {
|
func (r *refunder) FindMiners(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund, owner, worker, control bool) (*MinersRefund, error) {
|
||||||
@ -817,6 +864,147 @@ func (r *refunder) EnsureMinerMinimums(ctx context.Context, tipset *types.TipSet
|
|||||||
return refunds, nil
|
return refunds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *refunder) processTipsetStorageMarketActor(ctx context.Context, tipset *types.TipSet, msg api.Message, recp *types.MessageReceipt) (bool, string, types.BigInt, error) {
|
||||||
|
|
||||||
|
m := msg.Message
|
||||||
|
refundValue := types.NewInt(0)
|
||||||
|
var messageMethod string
|
||||||
|
|
||||||
|
switch m.Method {
|
||||||
|
case builtin0.MethodsMarket.PublishStorageDeals:
|
||||||
|
if !r.publishStorageDealsEnabled {
|
||||||
|
return false, messageMethod, types.NewInt(0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
messageMethod = "PublishStorageDeals"
|
||||||
|
|
||||||
|
if recp.ExitCode != exitcode.Ok {
|
||||||
|
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recp.ExitCode)
|
||||||
|
return false, messageMethod, types.NewInt(0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
refundValue = types.BigMul(types.NewInt(uint64(recp.GasUsed)), tipset.Blocks()[0].ParentBaseFee)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, messageMethod, refundValue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *refunder) processTipsetStorageMinerActor(ctx context.Context, tipset *types.TipSet, msg api.Message, recp *types.MessageReceipt) (bool, string, types.BigInt, error) {
|
||||||
|
|
||||||
|
m := msg.Message
|
||||||
|
refundValue := types.NewInt(0)
|
||||||
|
var messageMethod string
|
||||||
|
|
||||||
|
switch m.Method {
|
||||||
|
case builtin0.MethodsMiner.SubmitWindowedPoSt:
|
||||||
|
if !r.windowedPoStEnabled {
|
||||||
|
return false, messageMethod, types.NewInt(0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
messageMethod = "SubmitWindowedPoSt"
|
||||||
|
|
||||||
|
if recp.ExitCode != exitcode.Ok {
|
||||||
|
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recp.ExitCode)
|
||||||
|
return false, messageMethod, types.NewInt(0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
refundValue = types.BigMul(types.NewInt(uint64(recp.GasUsed)), tipset.Blocks()[0].ParentBaseFee)
|
||||||
|
case builtin0.MethodsMiner.ProveCommitSector:
|
||||||
|
if !r.proveCommitEnabled {
|
||||||
|
return false, messageMethod, types.NewInt(0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
messageMethod = "ProveCommitSector"
|
||||||
|
|
||||||
|
if recp.ExitCode != exitcode.Ok {
|
||||||
|
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recp.ExitCode)
|
||||||
|
return false, messageMethod, types.NewInt(0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.GasFeeCap.GreaterThan(r.proveFeeCapMax) {
|
||||||
|
log.Debugw("skipping high fee cap message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "gas_fee_cap", m.GasFeeCap, "fee_cap_max", r.proveFeeCapMax)
|
||||||
|
return false, messageMethod, types.NewInt(0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var sn abi.SectorNumber
|
||||||
|
|
||||||
|
var proveCommitSector miner0.ProveCommitSectorParams
|
||||||
|
if err := proveCommitSector.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil {
|
||||||
|
log.Warnw("failed to decode provecommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To)
|
||||||
|
return false, messageMethod, types.NewInt(0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sn = proveCommitSector.SectorNumber
|
||||||
|
|
||||||
|
// We use the parent tipset key because precommit information is removed when ProveCommitSector is executed
|
||||||
|
precommitChainInfo, err := r.api.StateSectorPreCommitInfo(ctx, m.To, sn, tipset.Parents())
|
||||||
|
if err != nil {
|
||||||
|
log.Warnw("failed to get precommit info for sector", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
|
||||||
|
return false, messageMethod, types.NewInt(0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
precommitTipset, err := r.api.ChainGetTipSetByHeight(ctx, precommitChainInfo.PreCommitEpoch, tipset.Key())
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("failed to lookup precommit epoch", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
|
||||||
|
return false, messageMethod, types.NewInt(0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitChainInfo.Info, precommitTipset.Key())
|
||||||
|
if err != nil {
|
||||||
|
log.Warnw("failed to get initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
|
||||||
|
return false, messageMethod, types.NewInt(0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
collateral = big.Sub(collateral, precommitChainInfo.PreCommitDeposit)
|
||||||
|
if collateral.LessThan(big.Zero()) {
|
||||||
|
log.Debugw("skipping zero pledge collateral difference", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
|
||||||
|
return false, messageMethod, types.NewInt(0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
refundValue = collateral
|
||||||
|
if r.refundPercent > 0 {
|
||||||
|
refundValue = types.BigMul(types.BigDiv(refundValue, types.NewInt(100)), types.NewInt(uint64(r.refundPercent)))
|
||||||
|
}
|
||||||
|
case builtin0.MethodsMiner.PreCommitSector:
|
||||||
|
if !r.preCommitEnabled {
|
||||||
|
return false, messageMethod, types.NewInt(0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
messageMethod = "PreCommitSector"
|
||||||
|
|
||||||
|
if recp.ExitCode != exitcode.Ok {
|
||||||
|
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recp.ExitCode)
|
||||||
|
return false, messageMethod, types.NewInt(0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.GasFeeCap.GreaterThan(r.preFeeCapMax) {
|
||||||
|
log.Debugw("skipping high fee cap message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "gas_fee_cap", m.GasFeeCap, "fee_cap_max", r.preFeeCapMax)
|
||||||
|
return false, messageMethod, types.NewInt(0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var precommitInfo miner.SectorPreCommitInfo
|
||||||
|
if err := precommitInfo.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil {
|
||||||
|
log.Warnw("failed to decode precommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To)
|
||||||
|
return false, messageMethod, types.NewInt(0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitInfo, tipset.Key())
|
||||||
|
if err != nil {
|
||||||
|
log.Warnw("failed to calculate initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", precommitInfo.SectorNumber)
|
||||||
|
return false, messageMethod, types.NewInt(0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
refundValue = collateral
|
||||||
|
if r.refundPercent > 0 {
|
||||||
|
refundValue = types.BigMul(types.BigDiv(refundValue, types.NewInt(100)), types.NewInt(uint64(r.refundPercent)))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false, messageMethod, types.NewInt(0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, messageMethod, refundValue, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund) (*MinersRefund, error) {
|
func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund) (*MinersRefund, error) {
|
||||||
cids := tipset.Cids()
|
cids := tipset.Cids()
|
||||||
if len(cids) == 0 {
|
if len(cids) == 0 {
|
||||||
@ -841,9 +1029,9 @@ func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refu
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
refundValue := types.NewInt(0)
|
|
||||||
tipsetRefunds := NewMinersRefund()
|
tipsetRefunds := NewMinersRefund()
|
||||||
for i, msg := range msgs {
|
for i, msg := range msgs {
|
||||||
|
refundValue := types.NewInt(0)
|
||||||
m := msg.Message
|
m := msg.Message
|
||||||
|
|
||||||
a, err := r.api.StateGetActor(ctx, m.To, tipset.Key())
|
a, err := r.api.StateGetActor(ctx, m.To, tipset.Key())
|
||||||
@ -852,91 +1040,23 @@ func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refu
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !builtin.IsStorageMinerActor(a.Code) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var messageMethod string
|
var messageMethod string
|
||||||
|
var processed bool
|
||||||
|
|
||||||
switch m.Method {
|
if m.To == market.Address {
|
||||||
case builtin0.MethodsMiner.ProveCommitSector:
|
processed, messageMethod, refundValue, err = r.processTipsetStorageMarketActor(ctx, tipset, msg, recps[i])
|
||||||
if !r.proveCommitEnabled {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
messageMethod = "ProveCommitSector"
|
|
||||||
|
|
||||||
if recps[i].ExitCode != exitcode.Ok {
|
|
||||||
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recps[i].ExitCode)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var sn abi.SectorNumber
|
|
||||||
|
|
||||||
var proveCommitSector miner0.ProveCommitSectorParams
|
|
||||||
if err := proveCommitSector.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil {
|
|
||||||
log.Warnw("failed to decode provecommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
sn = proveCommitSector.SectorNumber
|
|
||||||
|
|
||||||
// We use the parent tipset key because precommit information is removed when ProveCommitSector is executed
|
|
||||||
precommitChainInfo, err := r.api.StateSectorPreCommitInfo(ctx, m.To, sn, tipset.Parents())
|
|
||||||
if err != nil {
|
|
||||||
log.Warnw("failed to get precommit info for sector", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
precommitTipset, err := r.api.ChainGetTipSetByHeight(ctx, precommitChainInfo.PreCommitEpoch, tipset.Key())
|
|
||||||
if err != nil {
|
|
||||||
log.Warnf("failed to lookup precommit epoch", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitChainInfo.Info, precommitTipset.Key())
|
|
||||||
if err != nil {
|
|
||||||
log.Warnw("failed to get initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
|
|
||||||
}
|
|
||||||
|
|
||||||
collateral = big.Sub(collateral, precommitChainInfo.PreCommitDeposit)
|
|
||||||
if collateral.LessThan(big.Zero()) {
|
|
||||||
log.Debugw("skipping zero pledge collateral difference", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
refundValue = collateral
|
|
||||||
case builtin0.MethodsMiner.PreCommitSector:
|
|
||||||
if !r.preCommitEnabled {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
messageMethod = "PreCommitSector"
|
|
||||||
|
|
||||||
if recps[i].ExitCode != exitcode.Ok {
|
|
||||||
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recps[i].ExitCode)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var precommitInfo miner.SectorPreCommitInfo
|
|
||||||
if err := precommitInfo.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil {
|
|
||||||
log.Warnw("failed to decode precommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitInfo, tipset.Key())
|
|
||||||
if err != nil {
|
|
||||||
log.Warnw("failed to calculate initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", precommitInfo.SectorNumber)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
refundValue = collateral
|
|
||||||
default:
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.refundPercent > 0 {
|
if builtin.IsStorageMinerActor(a.Code) {
|
||||||
refundValue = types.BigMul(types.BigDiv(refundValue, types.NewInt(100)), types.NewInt(uint64(r.refundPercent)))
|
processed, messageMethod, refundValue, err = r.processTipsetStorageMinerActor(ctx, tipset, msg, recps[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Errorw("error while processing message", "cid", msg.Cid)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !processed {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugw(
|
log.Debugw(
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
"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/power"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
||||||
|
|
||||||
@ -33,16 +34,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type accountInfo struct {
|
type accountInfo struct {
|
||||||
Address address.Address
|
Address address.Address
|
||||||
Balance types.FIL
|
Balance types.FIL
|
||||||
Type string
|
Type string
|
||||||
Power abi.StoragePower
|
Power abi.StoragePower
|
||||||
Worker address.Address
|
Worker address.Address
|
||||||
Owner address.Address
|
Owner address.Address
|
||||||
InitialPledge types.FIL
|
InitialPledge types.FIL
|
||||||
PreCommits types.FIL
|
PreCommits types.FIL
|
||||||
LockedFunds types.FIL
|
LockedFunds types.FIL
|
||||||
Sectors uint64
|
Sectors uint64
|
||||||
|
VestingStart abi.ChainEpoch
|
||||||
|
VestingDuration abi.ChainEpoch
|
||||||
|
VestingAmount types.FIL
|
||||||
}
|
}
|
||||||
|
|
||||||
var auditsCmd = &cli.Command{
|
var auditsCmd = &cli.Command{
|
||||||
@ -115,10 +119,8 @@ var chainBalanceCmd = &cli.Command{
|
|||||||
infos = append(infos, ai)
|
infos = append(infos, ai)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Address,Balance,Type,Power,Worker,Owner\n")
|
printAccountInfos(infos, false)
|
||||||
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)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -171,7 +173,7 @@ var chainBalanceStateCmd = &cli.Command{
|
|||||||
|
|
||||||
bs := blockstore.NewBlockstore(ds)
|
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)
|
cst := cbor.NewCborStore(bs)
|
||||||
store := adt.WrapStore(ctx, cst)
|
store := adt.WrapStore(ctx, cst)
|
||||||
@ -196,6 +198,7 @@ var chainBalanceStateCmd = &cli.Command{
|
|||||||
LockedFunds: types.FIL(big.NewInt(0)),
|
LockedFunds: types.FIL(big.NewInt(0)),
|
||||||
InitialPledge: types.FIL(big.NewInt(0)),
|
InitialPledge: types.FIL(big.NewInt(0)),
|
||||||
PreCommits: types.FIL(big.NewInt(0)),
|
PreCommits: types.FIL(big.NewInt(0)),
|
||||||
|
VestingAmount: types.FIL(big.NewInt(0)),
|
||||||
}
|
}
|
||||||
|
|
||||||
if minerInfo && builtin.IsStorageMinerActor(act.Code) {
|
if minerInfo && builtin.IsStorageMinerActor(act.Code) {
|
||||||
@ -234,6 +237,32 @@ var chainBalanceStateCmd = &cli.Command{
|
|||||||
ai.Worker = minfo.Worker
|
ai.Worker = minfo.Worker
|
||||||
ai.Owner = minfo.Owner
|
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)
|
infos = append(infos, ai)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@ -241,22 +270,27 @@ var chainBalanceStateCmd = &cli.Command{
|
|||||||
return xerrors.Errorf("failed to loop over actors: %w", err)
|
return xerrors.Errorf("failed to loop over actors: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if minerInfo {
|
printAccountInfos(infos, 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
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{
|
var chainPledgeCmd = &cli.Command{
|
||||||
Name: "stateroot-pledge",
|
Name: "stateroot-pledge",
|
||||||
Description: "Calculate sector pledge numbers",
|
Description: "Calculate sector pledge numbers",
|
||||||
@ -309,7 +343,7 @@ var chainPledgeCmd = &cli.Command{
|
|||||||
|
|
||||||
bs := blockstore.NewBlockstore(ds)
|
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)
|
cst := cbor.NewCborStore(bs)
|
||||||
store := adt.WrapStore(ctx, cst)
|
store := adt.WrapStore(ctx, cst)
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
lcli "github.com/filecoin-project/lotus/cli"
|
lcli "github.com/filecoin-project/lotus/cli"
|
||||||
|
cliutil "github.com/filecoin-project/lotus/cli/util"
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
"github.com/multiformats/go-multiaddr"
|
"github.com/multiformats/go-multiaddr"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
@ -111,7 +112,7 @@ var consensusCheckCmd = &cli.Command{
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ainfo := lcli.APIInfo{Addr: apima}
|
ainfo := cliutil.APIInfo{Addr: apima.String()}
|
||||||
addr, err := ainfo.DialArgs()
|
addr, err := ainfo.DialArgs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -83,7 +83,7 @@ var exportChainCmd = &cli.Command{
|
|||||||
|
|
||||||
bs := blockstore.NewBlockstore(ds)
|
bs := blockstore.NewBlockstore(ds)
|
||||||
|
|
||||||
cs := store.NewChainStore(bs, mds, nil)
|
cs := store.NewChainStore(bs, mds, nil, nil)
|
||||||
if err := cs.Load(); err != nil {
|
if err := cs.Load(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ var genesisVerifyCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
bs := blockstore.NewBlockstore(datastore.NewMapDatastore())
|
bs := blockstore.NewBlockstore(datastore.NewMapDatastore())
|
||||||
|
|
||||||
cs := store.NewChainStore(bs, datastore.NewMapDatastore(), nil)
|
cs := store.NewChainStore(bs, datastore.NewMapDatastore(), nil, nil)
|
||||||
|
|
||||||
cf := cctx.Args().Get(0)
|
cf := cctx.Args().Get(0)
|
||||||
f, err := os.Open(cf)
|
f, err := os.Open(cf)
|
||||||
|
@ -105,7 +105,7 @@ var keyinfoVerifyCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := w.Import(&keyInfo); err != nil {
|
if _, err := w.WalletImport(cctx.Context, &keyInfo); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +220,7 @@ var keyinfoImportCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
addr, err := w.Import(&keyInfo)
|
addr, err := w.WalletImport(cctx.Context, &keyInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
@ -32,6 +34,10 @@ var noncefix = &cli.Command{
|
|||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "auto",
|
Name: "auto",
|
||||||
},
|
},
|
||||||
|
&cli.Int64Flag{
|
||||||
|
Name: "gas-fee-cap",
|
||||||
|
Usage: "specify gas fee cap for nonce filling messages",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
api, closer, err := lcli.GetFullNodeAPI(cctx)
|
api, closer, err := lcli.GetFullNodeAPI(cctx)
|
||||||
@ -84,15 +90,32 @@ var noncefix = &cli.Command{
|
|||||||
}
|
}
|
||||||
fmt.Printf("Creating %d filler messages (%d ~ %d)\n", end-start, start, end)
|
fmt.Printf("Creating %d filler messages (%d ~ %d)\n", end-start, start, end)
|
||||||
|
|
||||||
|
ts, err := api.ChainHead(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
feeCap := big.Mul(ts.Blocks()[0].ParentBaseFee, big.NewInt(2)) // default fee cap to 2 * parent base fee
|
||||||
|
if fcf := cctx.Int64("gas-fee-cap"); fcf != 0 {
|
||||||
|
feeCap = abi.NewTokenAmount(fcf)
|
||||||
|
}
|
||||||
|
|
||||||
for i := start; i < end; i++ {
|
for i := start; i < end; i++ {
|
||||||
msg := &types.Message{
|
msg := &types.Message{
|
||||||
From: addr,
|
From: addr,
|
||||||
To: addr,
|
To: addr,
|
||||||
Value: types.NewInt(1),
|
Value: types.NewInt(0),
|
||||||
Nonce: i,
|
Nonce: i,
|
||||||
|
GasLimit: 1000000,
|
||||||
|
GasFeeCap: feeCap,
|
||||||
|
GasPremium: abi.NewTokenAmount(5),
|
||||||
|
}
|
||||||
|
smsg, err := api.WalletSignMessage(ctx, addr, msg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = api.MpoolPushMessage(ctx, msg, nil)
|
_, err = api.MpoolPush(ctx, smsg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -162,7 +162,7 @@ var stateTreePruneCmd = &cli.Command{
|
|||||||
|
|
||||||
bs := blockstore.NewBlockstore(ds)
|
bs := blockstore.NewBlockstore(ds)
|
||||||
|
|
||||||
cs := store.NewChainStore(bs, mds, vm.Syscalls(ffiwrapper.ProofVerifier))
|
cs := store.NewChainStore(bs, mds, vm.Syscalls(ffiwrapper.ProofVerifier), nil)
|
||||||
if err := cs.Load(); err != nil {
|
if err := cs.Load(); err != nil {
|
||||||
return fmt.Errorf("loading chainstore: %w", err)
|
return fmt.Errorf("loading chainstore: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/node"
|
|
||||||
|
|
||||||
logging "github.com/ipfs/go-log/v2"
|
logging "github.com/ipfs/go-log/v2"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
@ -64,8 +62,8 @@ func TestMinerAllInfo(t *testing.T) {
|
|||||||
require.NoError(t, infoAllCmd.Action(cctx))
|
require.NoError(t, infoAllCmd.Action(cctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
bp := func(t *testing.T, nFull int, storage []test.StorageMiner, opts ...node.Option) ([]test.TestNode, []test.TestStorageNode) {
|
bp := func(t *testing.T, fullOpts []test.FullNodeOpts, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) {
|
||||||
n, sn = builder.Builder(t, nFull, storage, opts...)
|
n, sn = builder.Builder(t, fullOpts, storage)
|
||||||
|
|
||||||
t.Run("pre-info-all", run)
|
t.Run("pre-info-all", run)
|
||||||
|
|
||||||
|
@ -464,13 +464,12 @@ func storageMinerInit(ctx context.Context, cctx *cli.Context, api lapi.FullNode,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if jrnl, err := journal.OpenFSJournal(lr, journal.DefaultDisabledEvents); err == nil {
|
j, err := journal.OpenFSJournal(lr, journal.EnvDisabledEvents())
|
||||||
journal.J = jrnl
|
if err != nil {
|
||||||
} else {
|
|
||||||
return fmt.Errorf("failed to open filesystem journal: %w", err)
|
return fmt.Errorf("failed to open filesystem journal: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
m := miner.NewMiner(api, epp, a, slashfilter.New(mds))
|
m := miner.NewMiner(api, epp, a, slashfilter.New(mds), j)
|
||||||
{
|
{
|
||||||
if err := m.Start(ctx); err != nil {
|
if err := m.Start(ctx); err != nil {
|
||||||
return xerrors.Errorf("failed to start up genesis miner: %w", err)
|
return xerrors.Errorf("failed to start up genesis miner: %w", err)
|
||||||
|
@ -154,14 +154,14 @@ var setAskCmd = &cli.Command{
|
|||||||
Name: "set-ask",
|
Name: "set-ask",
|
||||||
Usage: "Configure the miner's ask",
|
Usage: "Configure the miner's ask",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.Uint64Flag{
|
&cli.StringFlag{
|
||||||
Name: "price",
|
Name: "price",
|
||||||
Usage: "Set the price of the ask for unverified deals (specified as attoFIL / GiB / Epoch) to `PRICE`",
|
Usage: "Set the price of the ask for unverified deals (specified as FIL / GiB / Epoch) to `PRICE`.",
|
||||||
Required: true,
|
Required: true,
|
||||||
},
|
},
|
||||||
&cli.Uint64Flag{
|
&cli.StringFlag{
|
||||||
Name: "verified-price",
|
Name: "verified-price",
|
||||||
Usage: "Set the price of the ask for verified deals (specified as attoFIL / GiB / Epoch) to `PRICE`",
|
Usage: "Set the price of the ask for verified deals (specified as FIL / GiB / Epoch) to `PRICE`",
|
||||||
Required: true,
|
Required: true,
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
@ -185,8 +185,15 @@ var setAskCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
defer closer()
|
defer closer()
|
||||||
|
|
||||||
pri := types.NewInt(cctx.Uint64("price"))
|
pri, err := types.ParseFIL(cctx.String("price"))
|
||||||
vpri := types.NewInt(cctx.Uint64("verified-price"))
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
vpri, err := types.ParseFIL(cctx.String("verified-price"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
dur, err := time.ParseDuration("720h0m0s")
|
dur, err := time.ParseDuration("720h0m0s")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -229,7 +236,7 @@ var setAskCmd = &cli.Command{
|
|||||||
return xerrors.Errorf("max piece size (w/bit-padding) %s cannot exceed miner sector size %s", types.SizeStr(types.NewInt(uint64(max))), types.SizeStr(types.NewInt(uint64(smax))))
|
return xerrors.Errorf("max piece size (w/bit-padding) %s cannot exceed miner sector size %s", types.SizeStr(types.NewInt(uint64(max))), types.SizeStr(types.NewInt(uint64(smax))))
|
||||||
}
|
}
|
||||||
|
|
||||||
return api.MarketSetAsk(ctx, pri, vpri, abi.ChainEpoch(qty), abi.PaddedPieceSize(min), abi.PaddedPieceSize(max))
|
return api.MarketSetAsk(ctx, types.BigInt(pri), types.BigInt(vpri), abi.ChainEpoch(qty), abi.PaddedPieceSize(min), abi.PaddedPieceSize(max))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,7 +288,7 @@ var getAskCmd = &cli.Command{
|
|||||||
rem = (time.Second * time.Duration(int64(dlt)*int64(build.BlockDelaySecs))).String()
|
rem = (time.Second * time.Duration(int64(dlt)*int64(build.BlockDelaySecs))).String()
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%d\t%s\t%d\n", ask.Price, ask.VerifiedPrice, types.SizeStr(types.NewInt(uint64(ask.MinPieceSize))), types.SizeStr(types.NewInt(uint64(ask.MaxPieceSize))), ask.Expiry, rem, ask.SeqNo)
|
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%d\t%s\t%d\n", types.FIL(ask.Price), types.FIL(ask.VerifiedPrice), types.SizeStr(types.NewInt(uint64(ask.MinPieceSize))), types.SizeStr(types.NewInt(uint64(ask.MaxPieceSize))), ask.Expiry, rem, ask.SeqNo)
|
||||||
|
|
||||||
return w.Flush()
|
return w.Flush()
|
||||||
},
|
},
|
||||||
|
@ -33,7 +33,7 @@ var runCmd = &cli.Command{
|
|||||||
Usage: "Start a lotus miner process",
|
Usage: "Start a lotus miner process",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "api",
|
Name: "miner-api",
|
||||||
Usage: "2345",
|
Usage: "2345",
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
@ -61,7 +61,7 @@ var runCmd = &cli.Command{
|
|||||||
|
|
||||||
nodeApi, ncloser, err := lcli.GetFullNodeAPI(cctx)
|
nodeApi, ncloser, err := lcli.GetFullNodeAPI(cctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return xerrors.Errorf("getting full node api: %w", err)
|
||||||
}
|
}
|
||||||
defer ncloser()
|
defer ncloser()
|
||||||
ctx := lcli.DaemonContext(cctx)
|
ctx := lcli.DaemonContext(cctx)
|
||||||
@ -112,29 +112,29 @@ var runCmd = &cli.Command{
|
|||||||
node.Online(),
|
node.Online(),
|
||||||
node.Repo(r),
|
node.Repo(r),
|
||||||
|
|
||||||
node.ApplyIf(func(s *node.Settings) bool { return cctx.IsSet("api") },
|
node.ApplyIf(func(s *node.Settings) bool { return cctx.IsSet("miner-api") },
|
||||||
node.Override(new(dtypes.APIEndpoint), func() (dtypes.APIEndpoint, error) {
|
node.Override(new(dtypes.APIEndpoint), func() (dtypes.APIEndpoint, error) {
|
||||||
return multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/" + cctx.String("api"))
|
return multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/" + cctx.String("miner-api"))
|
||||||
})),
|
})),
|
||||||
node.Override(new(api.FullNode), nodeApi),
|
node.Override(new(api.FullNode), nodeApi),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return xerrors.Errorf("creating node: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoint, err := r.APIEndpoint()
|
endpoint, err := r.APIEndpoint()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return xerrors.Errorf("getting API endpoint: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bootstrap with full node
|
// Bootstrap with full node
|
||||||
remoteAddrs, err := nodeApi.NetAddrsListen(ctx)
|
remoteAddrs, err := nodeApi.NetAddrsListen(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return xerrors.Errorf("getting full node libp2p address: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := minerapi.NetConnect(ctx, remoteAddrs); err != nil {
|
if err := minerapi.NetConnect(ctx, remoteAddrs); err != nil {
|
||||||
return err
|
return xerrors.Errorf("connecting to full node (libp2p): %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Remote version %s", v)
|
log.Infof("Remote version %s", v)
|
||||||
|
@ -31,6 +31,10 @@ const metaFile = "sectorstore.json"
|
|||||||
var storageCmd = &cli.Command{
|
var storageCmd = &cli.Command{
|
||||||
Name: "storage",
|
Name: "storage",
|
||||||
Usage: "manage sector storage",
|
Usage: "manage sector storage",
|
||||||
|
Description: `Sectors can be stored across many filesystem paths. These
|
||||||
|
commands provide ways to manage the storage the miner will used to store sectors
|
||||||
|
long term for proving (references as 'store') as well as how sectors will be
|
||||||
|
stored while moving through the sealing pipeline (references as 'seal').`,
|
||||||
Subcommands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
storageAttachCmd,
|
storageAttachCmd,
|
||||||
storageListCmd,
|
storageListCmd,
|
||||||
@ -41,6 +45,25 @@ var storageCmd = &cli.Command{
|
|||||||
var storageAttachCmd = &cli.Command{
|
var storageAttachCmd = &cli.Command{
|
||||||
Name: "attach",
|
Name: "attach",
|
||||||
Usage: "attach local storage path",
|
Usage: "attach local storage path",
|
||||||
|
Description: `Storage can be attached to the miner using this command. The storage volume
|
||||||
|
list is stored local to the miner in $LOTUS_MINER_PATH/storage.json. We do not
|
||||||
|
recommend manually modifying this value without further understanding of the
|
||||||
|
storage system.
|
||||||
|
|
||||||
|
Each storage volume contains a configuration file which describes the
|
||||||
|
capabilities of the volume. When the '--init' flag is provided, this file will
|
||||||
|
be created using the additional flags.
|
||||||
|
|
||||||
|
Weight
|
||||||
|
A high weight value means data will be more likely to be stored in this path
|
||||||
|
|
||||||
|
Seal
|
||||||
|
Data for the sealing process will be stored here
|
||||||
|
|
||||||
|
Store
|
||||||
|
Finalized sectors that will be moved here for long term storage and be proven
|
||||||
|
over time
|
||||||
|
`,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "init",
|
Name: "init",
|
||||||
|
94
cmd/lotus-wallet/logged.go
Normal file
94
cmd/lotus-wallet/logged.go
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
|
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LoggedWallet struct {
|
||||||
|
under api.WalletAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LoggedWallet) WalletNew(ctx context.Context, typ crypto.SigType) (address.Address, error) {
|
||||||
|
n, err := typ.Name()
|
||||||
|
if err != nil {
|
||||||
|
return address.Address{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infow("WalletNew", "type", n)
|
||||||
|
|
||||||
|
return c.under.WalletNew(ctx, typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LoggedWallet) WalletHas(ctx context.Context, addr address.Address) (bool, error) {
|
||||||
|
log.Infow("WalletHas", "address", addr)
|
||||||
|
|
||||||
|
return c.under.WalletHas(ctx, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LoggedWallet) WalletList(ctx context.Context) ([]address.Address, error) {
|
||||||
|
log.Infow("WalletList")
|
||||||
|
|
||||||
|
return c.under.WalletList(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LoggedWallet) WalletSign(ctx context.Context, k address.Address, msg []byte, meta api.MsgMeta) (*crypto.Signature, error) {
|
||||||
|
switch meta.Type {
|
||||||
|
case api.MTChainMsg:
|
||||||
|
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(msg)
|
||||||
|
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() != msg")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infow("WalletSign",
|
||||||
|
"address", k,
|
||||||
|
"type", meta.Type,
|
||||||
|
"from", cmsg.From,
|
||||||
|
"to", cmsg.To,
|
||||||
|
"value", types.FIL(cmsg.Value),
|
||||||
|
"feecap", types.FIL(cmsg.RequiredFunds()),
|
||||||
|
"method", cmsg.Method,
|
||||||
|
"params", hex.EncodeToString(cmsg.Params))
|
||||||
|
default:
|
||||||
|
log.Infow("WalletSign", "address", k, "type", meta.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.under.WalletSign(ctx, k, msg, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LoggedWallet) WalletExport(ctx context.Context, a address.Address) (*types.KeyInfo, error) {
|
||||||
|
log.Infow("WalletExport", "address", a)
|
||||||
|
|
||||||
|
return c.under.WalletExport(ctx, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LoggedWallet) WalletImport(ctx context.Context, ki *types.KeyInfo) (address.Address, error) {
|
||||||
|
log.Infow("WalletImport", "type", ki.Type)
|
||||||
|
|
||||||
|
return c.under.WalletImport(ctx, ki)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LoggedWallet) WalletDelete(ctx context.Context, addr address.Address) error {
|
||||||
|
log.Infow("WalletDelete", "address", addr)
|
||||||
|
|
||||||
|
return c.under.WalletDelete(ctx, addr)
|
||||||
|
}
|
141
cmd/lotus-wallet/main.go
Normal file
141
cmd/lotus-wallet/main.go
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
logging "github.com/ipfs/go-log/v2"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-jsonrpc"
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"github.com/filecoin-project/lotus/chain/wallet"
|
||||||
|
lcli "github.com/filecoin-project/lotus/cli"
|
||||||
|
"github.com/filecoin-project/lotus/lib/lotuslog"
|
||||||
|
"github.com/filecoin-project/lotus/node/repo"
|
||||||
|
)
|
||||||
|
|
||||||
|
var log = logging.Logger("main")
|
||||||
|
|
||||||
|
const FlagWalletRepo = "wallet-repo"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
lotuslog.SetupLogLevels()
|
||||||
|
|
||||||
|
local := []*cli.Command{
|
||||||
|
runCmd,
|
||||||
|
}
|
||||||
|
|
||||||
|
app := &cli.App{
|
||||||
|
Name: "lotus-wallet",
|
||||||
|
Usage: "Basic external wallet",
|
||||||
|
Version: build.UserVersion(),
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: FlagWalletRepo,
|
||||||
|
EnvVars: []string{"WALLET_PATH"},
|
||||||
|
Value: "~/.lotuswallet", // TODO: Consider XDG_DATA_HOME
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Commands: local,
|
||||||
|
}
|
||||||
|
app.Setup()
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Warnf("%+v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var runCmd = &cli.Command{
|
||||||
|
Name: "run",
|
||||||
|
Usage: "Start lotus wallet",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "listen",
|
||||||
|
Usage: "host address and port the wallet api will listen on",
|
||||||
|
Value: "0.0.0.0:1777",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
log.Info("Starting lotus wallet")
|
||||||
|
|
||||||
|
ctx := lcli.ReqContext(cctx)
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
repoPath := cctx.String(FlagWalletRepo)
|
||||||
|
r, err := repo.NewFS(repoPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, err := r.Exists()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
if err := r.Init(repo.Worker); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lr, err := r.Lock(repo.Wallet)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ks, err := lr.KeyStore()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
w, err := wallet.NewWallet(ks)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
address := cctx.String("listen")
|
||||||
|
mux := mux.NewRouter()
|
||||||
|
|
||||||
|
log.Info("Setting up API endpoint at " + address)
|
||||||
|
|
||||||
|
rpcServer := jsonrpc.NewServer()
|
||||||
|
rpcServer.Register("Filecoin", &LoggedWallet{under: w})
|
||||||
|
|
||||||
|
mux.Handle("/rpc/v0", rpcServer)
|
||||||
|
mux.PathPrefix("/").Handler(http.DefaultServeMux) // pprof
|
||||||
|
|
||||||
|
/*ah := &auth.Handler{
|
||||||
|
Verify: nodeApi.AuthVerify,
|
||||||
|
Next: mux.ServeHTTP,
|
||||||
|
}*/
|
||||||
|
|
||||||
|
srv := &http.Server{
|
||||||
|
Handler: mux,
|
||||||
|
BaseContext: func(listener net.Listener) context.Context {
|
||||||
|
return ctx
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
<-ctx.Done()
|
||||||
|
log.Warn("Shutting down...")
|
||||||
|
if err := srv.Shutdown(context.TODO()); err != nil {
|
||||||
|
log.Errorf("shutting down RPC server failed: %s", err)
|
||||||
|
}
|
||||||
|
log.Warn("Graceful shutdown successful")
|
||||||
|
}()
|
||||||
|
|
||||||
|
nl, err := net.Listen("tcp", address)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return srv.Serve(nl)
|
||||||
|
},
|
||||||
|
}
|
@ -15,8 +15,6 @@ import (
|
|||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
|
||||||
|
|
||||||
paramfetch "github.com/filecoin-project/go-paramfetch"
|
paramfetch "github.com/filecoin-project/go-paramfetch"
|
||||||
"github.com/mitchellh/go-homedir"
|
"github.com/mitchellh/go-homedir"
|
||||||
"github.com/multiformats/go-multiaddr"
|
"github.com/multiformats/go-multiaddr"
|
||||||
@ -32,9 +30,11 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
lcli "github.com/filecoin-project/lotus/cli"
|
lcli "github.com/filecoin-project/lotus/cli"
|
||||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||||
|
"github.com/filecoin-project/lotus/journal"
|
||||||
"github.com/filecoin-project/lotus/lib/blockstore"
|
"github.com/filecoin-project/lotus/lib/blockstore"
|
||||||
"github.com/filecoin-project/lotus/lib/peermgr"
|
"github.com/filecoin-project/lotus/lib/peermgr"
|
||||||
"github.com/filecoin-project/lotus/lib/ulimit"
|
"github.com/filecoin-project/lotus/lib/ulimit"
|
||||||
@ -114,6 +114,11 @@ var DaemonCmd = &cli.Command{
|
|||||||
Name: "halt-after-import",
|
Name: "halt-after-import",
|
||||||
Usage: "halt the process after importing chain from file",
|
Usage: "halt the process after importing chain from file",
|
||||||
},
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "lite",
|
||||||
|
Usage: "start lotus in lite mode",
|
||||||
|
Hidden: true,
|
||||||
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "pprof",
|
Name: "pprof",
|
||||||
Usage: "specify name of file for writing cpu profile to",
|
Usage: "specify name of file for writing cpu profile to",
|
||||||
@ -133,6 +138,8 @@ var DaemonCmd = &cli.Command{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
|
isLite := cctx.Bool("lite")
|
||||||
|
|
||||||
err := runmetrics.Enable(runmetrics.RunMetricOptions{
|
err := runmetrics.Enable(runmetrics.RunMetricOptions{
|
||||||
EnableCPU: true,
|
EnableCPU: true,
|
||||||
EnableMemory: true,
|
EnableMemory: true,
|
||||||
@ -192,8 +199,10 @@ var DaemonCmd = &cli.Command{
|
|||||||
return xerrors.Errorf("repo init error: %w", err)
|
return xerrors.Errorf("repo init error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := paramfetch.GetParams(lcli.ReqContext(cctx), build.ParametersJSON(), 0); err != nil {
|
if !isLite {
|
||||||
return xerrors.Errorf("fetching proof parameters: %w", err)
|
if err := paramfetch.GetParams(lcli.ReqContext(cctx), build.ParametersJSON(), 0); err != nil {
|
||||||
|
return xerrors.Errorf("fetching proof parameters: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var genBytes []byte
|
var genBytes []byte
|
||||||
@ -240,10 +249,23 @@ var DaemonCmd = &cli.Command{
|
|||||||
|
|
||||||
shutdownChan := make(chan struct{})
|
shutdownChan := make(chan struct{})
|
||||||
|
|
||||||
|
// If the daemon is started in "lite mode", provide a GatewayAPI
|
||||||
|
// for RPC calls
|
||||||
|
liteModeDeps := node.Options()
|
||||||
|
if isLite {
|
||||||
|
gapi, closer, err := lcli.GetGatewayAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer closer()
|
||||||
|
liteModeDeps = node.Override(new(api.GatewayAPI), gapi)
|
||||||
|
}
|
||||||
|
|
||||||
var api api.FullNode
|
var api api.FullNode
|
||||||
|
|
||||||
stop, err := node.New(ctx,
|
stop, err := node.New(ctx,
|
||||||
node.FullAPI(&api),
|
node.FullAPI(&api, node.Lite(isLite)),
|
||||||
|
|
||||||
node.Override(new(dtypes.Bootstrapper), isBootstrapper),
|
node.Override(new(dtypes.Bootstrapper), isBootstrapper),
|
||||||
node.Override(new(dtypes.ShutdownChan), shutdownChan),
|
node.Override(new(dtypes.ShutdownChan), shutdownChan),
|
||||||
@ -251,6 +273,7 @@ var DaemonCmd = &cli.Command{
|
|||||||
node.Repo(r),
|
node.Repo(r),
|
||||||
|
|
||||||
genesis,
|
genesis,
|
||||||
|
liteModeDeps,
|
||||||
|
|
||||||
node.ApplyIf(func(s *node.Settings) bool { return cctx.IsSet("api") },
|
node.ApplyIf(func(s *node.Settings) bool { return cctx.IsSet("api") },
|
||||||
node.Override(node.SetApiEndpointKey, func(lr repo.LockedRepo) error {
|
node.Override(node.SetApiEndpointKey, func(lr repo.LockedRepo) error {
|
||||||
@ -388,7 +411,11 @@ func ImportChain(r repo.Repo, fname string, snapshot bool) (err error) {
|
|||||||
|
|
||||||
bs := blockstore.NewBlockstore(ds)
|
bs := blockstore.NewBlockstore(ds)
|
||||||
|
|
||||||
cst := store.NewChainStore(bs, mds, vm.Syscalls(ffiwrapper.ProofVerifier))
|
j, err := journal.OpenFSJournal(lr, journal.EnvDisabledEvents())
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to open journal: %w", err)
|
||||||
|
}
|
||||||
|
cst := store.NewChainStore(bs, mds, vm.Syscalls(ffiwrapper.ProofVerifier), j)
|
||||||
|
|
||||||
log.Infof("importing chain from %s...", fname)
|
log.Infof("importing chain from %s...", fname)
|
||||||
|
|
||||||
@ -409,6 +436,10 @@ func ImportChain(r repo.Repo, fname string, snapshot bool) (err error) {
|
|||||||
return xerrors.Errorf("importing chain failed: %w", err)
|
return xerrors.Errorf("importing chain failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := cst.FlushValidationCache(); err != nil {
|
||||||
|
return xerrors.Errorf("flushing validation cache failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
gb, err := cst.GetTipsetByHeight(context.TODO(), 0, ts, true)
|
gb, err := cst.GetTipsetByHeight(context.TODO(), 0, ts, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -428,7 +459,7 @@ func ImportChain(r repo.Repo, fname string, snapshot bool) (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("accepting %s as new head", ts.Cids())
|
log.Infof("accepting %s as new head", ts.Cids())
|
||||||
if err := cst.SetHead(ts); err != nil {
|
if err := cst.SetHead(ts); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -198,8 +198,10 @@ func doExtract(ctx context.Context, fapi api.FullNode, opts extractOpts) error {
|
|||||||
Preroot: root,
|
Preroot: root,
|
||||||
Epoch: execTs.Height(),
|
Epoch: execTs.Height(),
|
||||||
Message: m,
|
Message: m,
|
||||||
CircSupply: &circSupplyDetail.FilCirculating,
|
CircSupply: circSupplyDetail.FilCirculating,
|
||||||
BaseFee: &basefee,
|
BaseFee: basefee,
|
||||||
|
// recorded randomness will be discarded.
|
||||||
|
Rand: conformance.NewRecordingRand(new(conformance.LogReporter), fapi),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to execute precursor message: %w", err)
|
return fmt.Errorf("failed to execute precursor message: %w", err)
|
||||||
@ -212,6 +214,9 @@ func doExtract(ctx context.Context, fapi api.FullNode, opts extractOpts) error {
|
|||||||
applyret *vm.ApplyRet
|
applyret *vm.ApplyRet
|
||||||
carWriter func(w io.Writer) error
|
carWriter func(w io.Writer) error
|
||||||
retention = opts.retain
|
retention = opts.retain
|
||||||
|
|
||||||
|
// recordingRand will record randomness so we can embed it in the test vector.
|
||||||
|
recordingRand = conformance.NewRecordingRand(new(conformance.LogReporter), fapi)
|
||||||
)
|
)
|
||||||
|
|
||||||
log.Printf("using state retention strategy: %s", retention)
|
log.Printf("using state retention strategy: %s", retention)
|
||||||
@ -229,8 +234,9 @@ func doExtract(ctx context.Context, fapi api.FullNode, opts extractOpts) error {
|
|||||||
Preroot: preroot,
|
Preroot: preroot,
|
||||||
Epoch: execTs.Height(),
|
Epoch: execTs.Height(),
|
||||||
Message: msg,
|
Message: msg,
|
||||||
CircSupply: &circSupplyDetail.FilCirculating,
|
CircSupply: circSupplyDetail.FilCirculating,
|
||||||
BaseFee: &basefee,
|
BaseFee: basefee,
|
||||||
|
Rand: recordingRand,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to execute message: %w", err)
|
return fmt.Errorf("failed to execute message: %w", err)
|
||||||
@ -260,8 +266,9 @@ func doExtract(ctx context.Context, fapi api.FullNode, opts extractOpts) error {
|
|||||||
Preroot: preroot,
|
Preroot: preroot,
|
||||||
Epoch: execTs.Height(),
|
Epoch: execTs.Height(),
|
||||||
Message: msg,
|
Message: msg,
|
||||||
CircSupply: &circSupplyDetail.FilCirculating,
|
CircSupply: circSupplyDetail.FilCirculating,
|
||||||
BaseFee: &basefee,
|
BaseFee: basefee,
|
||||||
|
Rand: recordingRand,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to execute message: %w", err)
|
return fmt.Errorf("failed to execute message: %w", err)
|
||||||
@ -356,7 +363,8 @@ func doExtract(ctx context.Context, fapi api.FullNode, opts extractOpts) error {
|
|||||||
{Source: fmt.Sprintf("execution_tipset:%s", execTs.Key().String())},
|
{Source: fmt.Sprintf("execution_tipset:%s", execTs.Key().String())},
|
||||||
{Source: "github.com/filecoin-project/lotus", Version: version.String()}},
|
{Source: "github.com/filecoin-project/lotus", Version: version.String()}},
|
||||||
},
|
},
|
||||||
CAR: out.Bytes(),
|
Randomness: recordingRand.Recorded(),
|
||||||
|
CAR: out.Bytes(),
|
||||||
Pre: &schema.Preconditions{
|
Pre: &schema.Preconditions{
|
||||||
Epoch: int64(execTs.Height()),
|
Epoch: int64(execTs.Height()),
|
||||||
CircSupply: circSupply.Int,
|
CircSupply: circSupply.Int,
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user