Merge remote-tracking branch 'origin/master' into feat/async-restartable-workers
This commit is contained in:
commit
71b3b9075d
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
|
||||||
|
39
CHANGELOG.md
39
CHANGELOG.md
@ -1,5 +1,44 @@
|
|||||||
# Lotus changelog
|
# Lotus changelog
|
||||||
|
|
||||||
|
# 0.10.0 / 2020-10-12
|
||||||
|
|
||||||
|
This is a consensus-breaking hotfix that addresses an issue in specs-actors v2.0.3 that made it impossible to pledge new 32GiB sectors. The change in Lotus is to update to actors v2.1.0, behind the new network version 5.
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
- make pledge test pass with the race detector (https://github.com/filecoin-project/lotus/pull/4291)
|
||||||
|
- fix a race in tipset cache usage (https://github.com/filecoin-project/lotus/pull/4282)
|
||||||
|
- add an api for removing multisig signers (https://github.com/filecoin-project/lotus/pull/4274)
|
||||||
|
- cli: Don't output errors to stdout (https://github.com/filecoin-project/lotus/pull/4298)
|
||||||
|
- Fix panic in wallet export when key is not found (https://github.com/filecoin-project/lotus/pull/4299)
|
||||||
|
- Dump the block validation cache whenever we perform an import (https://github.com/filecoin-project/lotus/pull/4287)
|
||||||
|
- Fix two races (https://github.com/filecoin-project/lotus/pull/4301)
|
||||||
|
- sync unmark-bad --all (https://github.com/filecoin-project/lotus/pull/4296)
|
||||||
|
- decode parameters for multisig transactions in inspect (https://github.com/filecoin-project/lotus/pull/4312)
|
||||||
|
- Chain is love (https://github.com/filecoin-project/lotus/pull/4321)
|
||||||
|
- lotus-stats: optmize getting miner power (https://github.com/filecoin-project/lotus/pull/4315)
|
||||||
|
- implement tape upgrade (https://github.com/filecoin-project/lotus/pull/4322)
|
||||||
|
|
||||||
|
# 0.9.1 / 2020-10-10
|
||||||
|
|
||||||
|
This release fixes an issue which may cause the actors v2 migration to compute the state incorrectly when more than one migration is running in parallel.
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
- Make concurrent actor migrations safe (https://github.com/filecoin-project/lotus/pull/4293)
|
||||||
|
- Remote wallet backends (https://github.com/filecoin-project/lotus/pull/3583)
|
||||||
|
- Track funds in FundMgr correctly in case of AddFunds failing (https://github.com/filecoin-project/lotus/pull/4273)
|
||||||
|
- Partial lite-node mode (https://github.com/filecoin-project/lotus/pull/4095)
|
||||||
|
- Fix potential infinite loop in GetBestMiningCandidate (https://github.com/filecoin-project/lotus/pull/3444)
|
||||||
|
- sync wait: Handle processed message offset (https://github.com/filecoin-project/lotus/pull/4253)
|
||||||
|
- Add some new endpoints for querying Msig info (https://github.com/filecoin-project/lotus/pull/4250)
|
||||||
|
- Update markets v0.7.1 (https://github.com/filecoin-project/lotus/pull/4254)
|
||||||
|
- Optimize SearchForMessage and GetReceipt (https://github.com/filecoin-project/lotus/pull/4246)
|
||||||
|
- Use FIL instead of attoFIL in CLI more consistently (https://github.com/filecoin-project/lotus/pull/4249)
|
||||||
|
- fix: clash between daemon --api flag and cli tests (https://github.com/filecoin-project/lotus/pull/4241)
|
||||||
|
- add more info to chain sync lookback failure (https://github.com/filecoin-project/lotus/pull/4245)
|
||||||
|
- Add message counts to inspect chain output (https://github.com/filecoin-project/lotus/pull/4230)
|
||||||
|
|
||||||
# 0.9.0 / 2020-10-07
|
# 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:
|
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:
|
||||||
|
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)
|
||||||
@ -226,7 +229,9 @@ type FullNode interface {
|
|||||||
// MethodGroup: Wallet
|
// MethodGroup: Wallet
|
||||||
|
|
||||||
// WalletNew creates a new address in the wallet with the given sigType.
|
// WalletNew creates a new address in the wallet with the given sigType.
|
||||||
WalletNew(context.Context, crypto.SigType) (address.Address, error)
|
// Available key types: bls, secp256k1, secp256k1-ledger
|
||||||
|
// Support for numerical types: 1 - secp256k1, 2 - BLS is deprecated
|
||||||
|
WalletNew(context.Context, types.KeyType) (address.Address, error)
|
||||||
// WalletHas indicates whether the given address is in the wallet.
|
// WalletHas indicates whether the given address is in the wallet.
|
||||||
WalletHas(context.Context, address.Address) (bool, error)
|
WalletHas(context.Context, address.Address) (bool, error)
|
||||||
// WalletList lists all the addresses in the wallet.
|
// WalletList lists all the addresses in the wallet.
|
||||||
@ -367,6 +372,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
|
||||||
@ -407,8 +416,12 @@ type FullNode interface {
|
|||||||
// can issue. It takes the deal size and verified status as parameters.
|
// can issue. It takes the deal size and verified status as parameters.
|
||||||
StateDealProviderCollateralBounds(context.Context, abi.PaddedPieceSize, bool, types.TipSetKey) (DealCollateralBounds, error)
|
StateDealProviderCollateralBounds(context.Context, abi.PaddedPieceSize, bool, types.TipSetKey) (DealCollateralBounds, error)
|
||||||
|
|
||||||
// StateCirculatingSupply returns the circulating supply of Filecoin at the given tipset
|
// StateCirculatingSupply returns the exact circulating supply of Filecoin at the given tipset.
|
||||||
StateCirculatingSupply(context.Context, types.TipSetKey) (CirculatingSupply, error)
|
// This is not used anywhere in the protocol itself, and is only for external consumption.
|
||||||
|
StateCirculatingSupply(context.Context, types.TipSetKey) (abi.TokenAmount, error)
|
||||||
|
// StateVMCirculatingSupplyInternal returns an approximation of the circulating supply of Filecoin at the given tipset.
|
||||||
|
// This is the value reported by the runtime interface to actors code.
|
||||||
|
StateVMCirculatingSupplyInternal(context.Context, types.TipSetKey) (CirculatingSupply, error)
|
||||||
// StateNetworkVersion returns the network version at the given tipset
|
// StateNetworkVersion returns the network version at the given tipset
|
||||||
StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error)
|
StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error)
|
||||||
|
|
||||||
@ -418,6 +431,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 +444,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 +486,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 +902,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, types.KeyType) (address.Address, error)
|
||||||
|
WalletHas(context.Context, address.Address) (bool, error)
|
||||||
|
WalletList(context.Context) ([]address.Address, error)
|
||||||
|
|
||||||
|
WalletSign(ctx context.Context, signer address.Address, toSign []byte, meta MsgMeta) (*crypto.Signature, error)
|
||||||
|
|
||||||
|
WalletExport(context.Context, address.Address) (*types.KeyInfo, error)
|
||||||
|
WalletImport(context.Context, *types.KeyInfo) (address.Address, error)
|
||||||
|
WalletDelete(context.Context, address.Address) error
|
||||||
|
}
|
@ -36,3 +36,9 @@ func PermissionedWorkerAPI(a api.WorkerAPI) api.WorkerAPI {
|
|||||||
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal)
|
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"`
|
||||||
|
|
||||||
@ -132,7 +133,7 @@ type FullNodeStruct struct {
|
|||||||
MinerGetBaseInfo func(context.Context, address.Address, abi.ChainEpoch, types.TipSetKey) (*api.MiningBaseInfo, error) `perm:"read"`
|
MinerGetBaseInfo func(context.Context, address.Address, abi.ChainEpoch, types.TipSetKey) (*api.MiningBaseInfo, error) `perm:"read"`
|
||||||
MinerCreateBlock func(context.Context, *api.BlockTemplate) (*types.BlockMsg, error) `perm:"write"`
|
MinerCreateBlock func(context.Context, *api.BlockTemplate) (*types.BlockMsg, error) `perm:"write"`
|
||||||
|
|
||||||
WalletNew func(context.Context, crypto.SigType) (address.Address, error) `perm:"write"`
|
WalletNew func(context.Context, types.KeyType) (address.Address, error) `perm:"write"`
|
||||||
WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"`
|
WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"`
|
||||||
WalletList func(context.Context) ([]address.Address, error) `perm:"write"`
|
WalletList func(context.Context) ([]address.Address, error) `perm:"write"`
|
||||||
WalletBalance func(context.Context, address.Address) (types.BigInt, error) `perm:"read"`
|
WalletBalance func(context.Context, address.Address) (types.BigInt, 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"`
|
||||||
@ -208,14 +210,17 @@ type FullNodeStruct struct {
|
|||||||
StateVerifiedClientStatus func(context.Context, address.Address, types.TipSetKey) (*abi.StoragePower, error) `perm:"read"`
|
StateVerifiedClientStatus func(context.Context, address.Address, types.TipSetKey) (*abi.StoragePower, error) `perm:"read"`
|
||||||
StateVerifiedRegistryRootKey func(ctx context.Context, tsk types.TipSetKey) (address.Address, error) `perm:"read"`
|
StateVerifiedRegistryRootKey func(ctx context.Context, tsk types.TipSetKey) (address.Address, error) `perm:"read"`
|
||||||
StateDealProviderCollateralBounds func(context.Context, abi.PaddedPieceSize, bool, types.TipSetKey) (api.DealCollateralBounds, error) `perm:"read"`
|
StateDealProviderCollateralBounds func(context.Context, abi.PaddedPieceSize, bool, types.TipSetKey) (api.DealCollateralBounds, error) `perm:"read"`
|
||||||
StateCirculatingSupply func(context.Context, types.TipSetKey) (api.CirculatingSupply, error) `perm:"read"`
|
StateCirculatingSupply func(context.Context, types.TipSetKey) (abi.TokenAmount, error) `perm:"read"`
|
||||||
|
StateVMCirculatingSupplyInternal func(context.Context, types.TipSetKey) (api.CirculatingSupply, error) `perm:"read"`
|
||||||
StateNetworkVersion func(context.Context, types.TipSetKey) (stnetwork.Version, error) `perm:"read"`
|
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 +228,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"`
|
||||||
|
|
||||||
@ -371,6 +377,35 @@ type WorkerStruct struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GatewayStruct struct {
|
||||||
|
Internal struct {
|
||||||
|
// TODO: does the gateway need perms?
|
||||||
|
ChainGetTipSet func(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error)
|
||||||
|
ChainGetTipSetByHeight func(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error)
|
||||||
|
ChainHead func(ctx context.Context) (*types.TipSet, error)
|
||||||
|
GasEstimateMessageGas func(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error)
|
||||||
|
MpoolPush func(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error)
|
||||||
|
MsigGetAvailableBalance func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error)
|
||||||
|
MsigGetVested func(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error)
|
||||||
|
StateAccountKey func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
|
||||||
|
StateGetActor func(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)
|
||||||
|
StateLookupID func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
|
||||||
|
StateWaitMsg func(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type WalletStruct struct {
|
||||||
|
Internal struct {
|
||||||
|
WalletNew func(context.Context, types.KeyType) (address.Address, error) `perm:"write"`
|
||||||
|
WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"`
|
||||||
|
WalletList func(context.Context) ([]address.Address, error) `perm:"write"`
|
||||||
|
WalletSign func(context.Context, address.Address, []byte, api.MsgMeta) (*crypto.Signature, error) `perm:"sign"`
|
||||||
|
WalletExport func(context.Context, address.Address) (*types.KeyInfo, error) `perm:"admin"`
|
||||||
|
WalletImport func(context.Context, *types.KeyInfo) (address.Address, error) `perm:"admin"`
|
||||||
|
WalletDelete func(context.Context, address.Address) error `perm:"write"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CommonStruct
|
// 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) {
|
||||||
@ -608,7 +643,7 @@ func (c *FullNodeStruct) ChainGetTipSetByHeight(ctx context.Context, h abi.Chain
|
|||||||
return c.Internal.ChainGetTipSetByHeight(ctx, h, tsk)
|
return c.Internal.ChainGetTipSetByHeight(ctx, h, tsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) WalletNew(ctx context.Context, typ crypto.SigType) (address.Address, error) {
|
func (c *FullNodeStruct) WalletNew(ctx context.Context, typ types.KeyType) (address.Address, error) {
|
||||||
return c.Internal.WalletNew(ctx, typ)
|
return c.Internal.WalletNew(ctx, typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -760,6 +795,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)
|
||||||
}
|
}
|
||||||
@ -864,6 +903,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)
|
||||||
}
|
}
|
||||||
@ -932,10 +975,14 @@ func (c *FullNodeStruct) StateDealProviderCollateralBounds(ctx context.Context,
|
|||||||
return c.Internal.StateDealProviderCollateralBounds(ctx, size, verified, tsk)
|
return c.Internal.StateDealProviderCollateralBounds(ctx, size, verified, tsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) StateCirculatingSupply(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) {
|
func (c *FullNodeStruct) StateCirculatingSupply(ctx context.Context, tsk types.TipSetKey) (abi.TokenAmount, error) {
|
||||||
return c.Internal.StateCirculatingSupply(ctx, tsk)
|
return c.Internal.StateCirculatingSupply(ctx, tsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *FullNodeStruct) StateVMCirculatingSupplyInternal(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) {
|
||||||
|
return c.Internal.StateVMCirculatingSupplyInternal(ctx, tsk)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (stnetwork.Version, error) {
|
func (c *FullNodeStruct) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (stnetwork.Version, error) {
|
||||||
return c.Internal.StateNetworkVersion(ctx, tsk)
|
return c.Internal.StateNetworkVersion(ctx, tsk)
|
||||||
}
|
}
|
||||||
@ -944,6 +991,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)
|
||||||
}
|
}
|
||||||
@ -956,8 +1007,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) {
|
||||||
@ -988,6 +1043,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)
|
||||||
}
|
}
|
||||||
@ -1422,7 +1481,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 types.KeyType) (address.Address, error) {
|
||||||
|
return c.Internal.WalletNew(ctx, typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *WalletStruct) WalletHas(ctx context.Context, addr address.Address) (bool, error) {
|
||||||
|
return c.Internal.WalletHas(ctx, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *WalletStruct) WalletList(ctx context.Context) ([]address.Address, error) {
|
||||||
|
return c.Internal.WalletList(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *WalletStruct) WalletSign(ctx context.Context, k address.Address, msg []byte, meta api.MsgMeta) (*crypto.Signature, error) {
|
||||||
|
return c.Internal.WalletSign(ctx, k, msg, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *WalletStruct) WalletExport(ctx context.Context, a address.Address) (*types.KeyInfo, error) {
|
||||||
|
return c.Internal.WalletExport(ctx, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *WalletStruct) WalletImport(ctx context.Context, ki *types.KeyInfo) (address.Address, error) {
|
||||||
|
return c.Internal.WalletImport(ctx, ki)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *WalletStruct) WalletDelete(ctx context.Context, addr address.Address) error {
|
||||||
|
return c.Internal.WalletDelete(ctx, addr)
|
||||||
|
}
|
||||||
|
|
||||||
var _ api.Common = &CommonStruct{}
|
var _ api.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
|
||||||
|
}
|
||||||
|
@ -87,6 +87,7 @@ func init() {
|
|||||||
addExample(abi.RegisteredPoStProof_StackedDrgWindow32GiBV1)
|
addExample(abi.RegisteredPoStProof_StackedDrgWindow32GiBV1)
|
||||||
addExample(abi.ChainEpoch(10101))
|
addExample(abi.ChainEpoch(10101))
|
||||||
addExample(crypto.SigTypeBLS)
|
addExample(crypto.SigTypeBLS)
|
||||||
|
addExample(types.KTBLS)
|
||||||
addExample(int64(9))
|
addExample(int64(9))
|
||||||
addExample(12.3)
|
addExample(12.3)
|
||||||
addExample(123)
|
addExample(123)
|
||||||
|
@ -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
|
||||||
})
|
})
|
||||||
|
@ -26,14 +26,13 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/events"
|
"github.com/filecoin-project/lotus/chain/events"
|
||||||
"github.com/filecoin-project/lotus/chain/events/state"
|
"github.com/filecoin-project/lotus/chain/events/state"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/wallet"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
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]
|
||||||
@ -58,7 +57,7 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
|||||||
bm.MineBlocks()
|
bm.MineBlocks()
|
||||||
|
|
||||||
// send some funds to register the receiver
|
// send some funds to register the receiver
|
||||||
receiverAddr, err := paymentReceiver.WalletNew(ctx, wallet.ActSigType("secp256k1"))
|
receiverAddr, err := paymentReceiver.WalletNew(ctx, types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
114
api/test/tape.go
Normal file
114
api/test/tape.go
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
|
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
||||||
|
"github.com/filecoin-project/lotus/node"
|
||||||
|
"github.com/filecoin-project/lotus/node/impl"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTapeFix(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||||
|
t.Run("before", func(t *testing.T) { testTapeFix(t, b, blocktime, false) })
|
||||||
|
t.Run("after", func(t *testing.T) { testTapeFix(t, b, blocktime, true) })
|
||||||
|
}
|
||||||
|
func testTapeFix(t *testing.T, b APIBuilder, blocktime time.Duration, after bool) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
upgradeSchedule := stmgr.UpgradeSchedule{{
|
||||||
|
Network: build.ActorUpgradeNetworkVersion,
|
||||||
|
Height: 1,
|
||||||
|
Migration: stmgr.UpgradeActorsV2,
|
||||||
|
}}
|
||||||
|
if after {
|
||||||
|
upgradeSchedule = append(upgradeSchedule, stmgr.Upgrade{
|
||||||
|
Network: network.Version5,
|
||||||
|
Height: 2,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
n, sn := b(t, []FullNodeOpts{{Opts: func(_ []TestNode) node.Option {
|
||||||
|
return node.Override(new(stmgr.UpgradeSchedule), upgradeSchedule)
|
||||||
|
}}}, OneMiner)
|
||||||
|
|
||||||
|
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||||
|
miner := sn[0]
|
||||||
|
|
||||||
|
addrinfo, err := client.NetAddrsListen(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := miner.NetConnect(ctx, addrinfo); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
build.Clock.Sleep(time.Second)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
defer close(done)
|
||||||
|
for ctx.Err() == nil {
|
||||||
|
build.Clock.Sleep(blocktime)
|
||||||
|
if err := sn[0].MineOne(ctx, MineNext); err != nil {
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
// context was canceled, ignore the error.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
defer func() {
|
||||||
|
cancel()
|
||||||
|
<-done
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = miner.PledgeSector(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Wait till done.
|
||||||
|
var sectorNo abi.SectorNumber
|
||||||
|
for {
|
||||||
|
s, err := miner.SectorsList(ctx) // Note - the test builder doesn't import genesis sectors into FSM
|
||||||
|
require.NoError(t, err)
|
||||||
|
fmt.Printf("Sectors: %d\n", len(s))
|
||||||
|
if len(s) == 1 {
|
||||||
|
sectorNo = s[0]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
build.Clock.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("All sectors is fsm\n")
|
||||||
|
|
||||||
|
// If before, we expect the precommit to fail
|
||||||
|
successState := api.SectorState(sealing.CommitFailed)
|
||||||
|
failureState := api.SectorState(sealing.Proving)
|
||||||
|
if after {
|
||||||
|
// otherwise, it should succeed.
|
||||||
|
successState, failureState = failureState, successState
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
st, err := miner.SectorsStatus(ctx, sectorNo, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
if st.State == successState {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
require.NotEqual(t, failureState, st.State)
|
||||||
|
build.Clock.Sleep(100 * time.Millisecond)
|
||||||
|
fmt.Println("WaitSeal")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -4,11 +4,15 @@ 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/go-state-types/network"
|
||||||
"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 +39,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 +77,40 @@ 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{{
|
||||||
|
// Skip directly to tape height so precommits work.
|
||||||
|
Network: network.Version5,
|
||||||
|
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 +122,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 +134,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]
|
||||||
|
@ -17,9 +17,10 @@ const BreezeGasTampingDuration = 0
|
|||||||
const UpgradeSmokeHeight = -1
|
const UpgradeSmokeHeight = -1
|
||||||
const UpgradeIgnitionHeight = -2
|
const UpgradeIgnitionHeight = -2
|
||||||
const UpgradeRefuelHeight = -3
|
const UpgradeRefuelHeight = -3
|
||||||
|
const UpgradeTapeHeight = -4
|
||||||
|
|
||||||
var UpgradeActorsV2Height = abi.ChainEpoch(10)
|
var UpgradeActorsV2Height = abi.ChainEpoch(10)
|
||||||
var UpgradeLiftoffHeight = abi.ChainEpoch(-4)
|
var UpgradeLiftoffHeight = abi.ChainEpoch(-5)
|
||||||
|
|
||||||
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||||
0: DrandMainnet,
|
0: DrandMainnet,
|
||||||
|
@ -30,6 +30,8 @@ const UpgradeRefuelHeight = 130800
|
|||||||
|
|
||||||
var UpgradeActorsV2Height = abi.ChainEpoch(138720)
|
var UpgradeActorsV2Height = abi.ChainEpoch(138720)
|
||||||
|
|
||||||
|
const UpgradeTapeHeight = 140760
|
||||||
|
|
||||||
// This signals our tentative epoch for mainnet launch. Can make it later, but not earlier.
|
// This signals our tentative epoch for mainnet launch. Can make it later, but not earlier.
|
||||||
// Miners, clients, developers, custodians all need time to prepare.
|
// Miners, clients, developers, custodians all need time to prepare.
|
||||||
// We still have upgrades and state changes to do, but can happen after signaling timing here.
|
// We still have upgrades and state changes to do, but can happen after signaling timing here.
|
@ -25,7 +25,7 @@ const UnixfsLinksPerLevel = 1024
|
|||||||
// Consensus / Network
|
// Consensus / Network
|
||||||
|
|
||||||
const AllowableClockDriftSecs = uint64(1)
|
const AllowableClockDriftSecs = uint64(1)
|
||||||
const NewestNetworkVersion = network.Version4
|
const NewestNetworkVersion = network.Version5
|
||||||
const ActorUpgradeNetworkVersion = network.Version4
|
const ActorUpgradeNetworkVersion = network.Version4
|
||||||
|
|
||||||
// Epochs
|
// Epochs
|
||||||
|
@ -83,14 +83,15 @@ var (
|
|||||||
UpgradeSmokeHeight abi.ChainEpoch = -1
|
UpgradeSmokeHeight abi.ChainEpoch = -1
|
||||||
UpgradeIgnitionHeight abi.ChainEpoch = -2
|
UpgradeIgnitionHeight abi.ChainEpoch = -2
|
||||||
UpgradeRefuelHeight abi.ChainEpoch = -3
|
UpgradeRefuelHeight abi.ChainEpoch = -3
|
||||||
|
UpgradeTapeHeight abi.ChainEpoch = -4
|
||||||
UpgradeActorsV2Height abi.ChainEpoch = 10
|
UpgradeActorsV2Height abi.ChainEpoch = 10
|
||||||
UpgradeLiftoffHeight abi.ChainEpoch = -4
|
UpgradeLiftoffHeight abi.ChainEpoch = -5
|
||||||
|
|
||||||
DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||||
0: DrandMainnet,
|
0: DrandMainnet,
|
||||||
}
|
}
|
||||||
|
|
||||||
NewestNetworkVersion = network.Version4
|
NewestNetworkVersion = network.Version5
|
||||||
ActorUpgradeNetworkVersion = network.Version4
|
ActorUpgradeNetworkVersion = network.Version4
|
||||||
|
|
||||||
Devnet = true
|
Devnet = true
|
||||||
|
@ -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.9.0"
|
const BuildVersion = "0.10.0"
|
||||||
|
|
||||||
func UserVersion() string {
|
func UserVersion() string {
|
||||||
return BuildVersion + buildType() + CurrentCommit
|
return BuildVersion + buildType() + CurrentCommit
|
||||||
|
@ -2,25 +2,28 @@ package builtin
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
|
smoothing2 "github.com/filecoin-project/specs-actors/v2/actors/util/smoothing"
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/cbor"
|
"github.com/filecoin-project/go-state-types/cbor"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
|
||||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||||
proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||||
smoothing0 "github.com/filecoin-project/specs-actors/actors/util/smoothing"
|
smoothing0 "github.com/filecoin-project/specs-actors/actors/util/smoothing"
|
||||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
|
||||||
smoothing2 "github.com/filecoin-project/specs-actors/v2/actors/util/smoothing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var SystemActorAddr = builtin0.SystemActorAddr
|
var SystemActorAddr = builtin0.SystemActorAddr
|
||||||
var BurntFundsActorAddr = builtin0.BurntFundsActorAddr
|
var BurntFundsActorAddr = builtin0.BurntFundsActorAddr
|
||||||
|
var CronActorAddr = builtin0.CronActorAddr
|
||||||
|
var SaftAddress = makeAddress("t0122")
|
||||||
var ReserveAddress = makeAddress("t090")
|
var ReserveAddress = makeAddress("t090")
|
||||||
var RootVerifierAddress = makeAddress("t080")
|
var RootVerifierAddress = makeAddress("t080")
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package miner
|
package miner
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
@ -148,6 +149,20 @@ type MinerInfo struct {
|
|||||||
ConsensusFaultElapsed abi.ChainEpoch
|
ConsensusFaultElapsed abi.ChainEpoch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mi MinerInfo) IsController(addr address.Address) bool {
|
||||||
|
if addr == mi.Owner || addr == mi.Worker {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ca := range mi.ControlAddresses {
|
||||||
|
if addr == ca {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type SectorExpiration struct {
|
type SectorExpiration struct {
|
||||||
OnTime abi.ChainEpoch
|
OnTime abi.ChainEpoch
|
||||||
|
|
||||||
@ -182,3 +197,7 @@ type LockedFunds struct {
|
|||||||
InitialPledgeRequirement abi.TokenAmount
|
InitialPledgeRequirement abi.TokenAmount
|
||||||
PreCommitDeposits abi.TokenAmount
|
PreCommitDeposits abi.TokenAmount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (lf LockedFunds) TotalLockedFunds() abi.TokenAmount {
|
||||||
|
return big.Add(lf.VestingFunds, big.Add(lf.InitialPledgeRequirement, lf.PreCommitDeposits))
|
||||||
|
}
|
||||||
|
@ -47,8 +47,16 @@ type partition0 struct {
|
|||||||
store adt.Store
|
store adt.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state0) AvailableBalance(bal abi.TokenAmount) (abi.TokenAmount, error) {
|
func (s *state0) AvailableBalance(bal abi.TokenAmount) (available abi.TokenAmount, err error) {
|
||||||
return s.GetAvailableBalance(bal), nil
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
err = xerrors.Errorf("failed to get available balance: %w", r)
|
||||||
|
available = abi.NewTokenAmount(0)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
// this panics if the miner doesnt have enough funds to cover their locked pledge
|
||||||
|
available = s.GetAvailableBalance(bal)
|
||||||
|
return available, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state0) VestedFunds(epoch abi.ChainEpoch) (abi.TokenAmount, error) {
|
func (s *state0) VestedFunds(epoch abi.ChainEpoch) (abi.TokenAmount, error) {
|
||||||
|
@ -45,8 +45,16 @@ type partition2 struct {
|
|||||||
store adt.Store
|
store adt.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state2) AvailableBalance(bal abi.TokenAmount) (abi.TokenAmount, error) {
|
func (s *state2) AvailableBalance(bal abi.TokenAmount) (available abi.TokenAmount, err error) {
|
||||||
return s.GetAvailableBalance(bal)
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
err = xerrors.Errorf("failed to get available balance: %w", r)
|
||||||
|
available = abi.NewTokenAmount(0)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
// this panics if the miner doesnt have enough funds to cover their locked pledge
|
||||||
|
available, err = s.GetAvailableBalance(bal)
|
||||||
|
return available, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state2) VestedFunds(epoch abi.ChainEpoch) (abi.TokenAmount, error) {
|
func (s *state2) VestedFunds(epoch abi.ChainEpoch) (abi.TokenAmount, error) {
|
||||||
|
@ -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) {
|
||||||
|
@ -18,7 +18,7 @@ func VersionForNetwork(version network.Version) Version {
|
|||||||
switch version {
|
switch version {
|
||||||
case network.Version0, network.Version1, network.Version2, network.Version3:
|
case network.Version0, network.Version1, network.Version2, network.Version3:
|
||||||
return Version0
|
return Version0
|
||||||
case network.Version4:
|
case network.Version4, network.Version5:
|
||||||
return Version2
|
return Version2
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unsupported network version %d", version))
|
panic(fmt.Sprintf("unsupported network version %d", 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(), types.KTSecp256k1)
|
||||||
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(), types.KTBLS)
|
||||||
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"
|
||||||
@ -466,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)
|
||||||
@ -478,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()}}}
|
||||||
|
@ -8,7 +8,6 @@ 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/crypto"
|
|
||||||
"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/chain/types/mock"
|
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||||
@ -225,14 +224,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(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -266,14 +265,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(), types.KTBLS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -315,7 +314,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 +322,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(), types.KTBLS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -378,7 +377,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 +385,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(), types.KTBLS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -422,7 +421,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 +432,7 @@ func TestLoadLocal(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -443,7 +442,7 @@ func TestLoadLocal(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -465,7 +464,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 +493,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 +504,7 @@ func TestClearAll(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -515,7 +514,7 @@ func TestClearAll(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -548,7 +547,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 +558,7 @@ func TestClearNonLocal(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -569,7 +568,7 @@ func TestClearNonLocal(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -609,7 +608,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 +619,7 @@ func TestUpdates(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -630,7 +629,7 @@ func TestUpdates(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
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,11 +1,12 @@
|
|||||||
package messagepool
|
package messagepool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
|
||||||
"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/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-datastore"
|
"github.com/ipfs/go-datastore"
|
||||||
@ -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(), types.KTSecp256k1)
|
||||||
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(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -13,20 +13,21 @@ 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/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/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 +35,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 +46,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 +59,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 +76,7 @@ func TestMessageChains(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -85,7 +86,7 @@ func TestMessageChains(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -313,7 +314,7 @@ func TestMessageChainSkipping(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -323,7 +324,7 @@ func TestMessageChainSkipping(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -389,7 +390,7 @@ func TestBasicMessageSelection(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -399,7 +400,7 @@ func TestBasicMessageSelection(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -533,7 +534,7 @@ func TestMessageSelectionTrimming(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -543,7 +544,7 @@ func TestMessageSelectionTrimming(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -596,7 +597,7 @@ func TestPriorityMessageSelection(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -606,7 +607,7 @@ func TestPriorityMessageSelection(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -675,7 +676,7 @@ func TestPriorityMessageSelection2(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -685,7 +686,7 @@ func TestPriorityMessageSelection2(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -744,7 +745,7 @@ func TestPriorityMessageSelection3(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -754,7 +755,7 @@ func TestPriorityMessageSelection3(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -841,7 +842,7 @@ func TestOptimalMessageSelection1(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -851,7 +852,7 @@ func TestOptimalMessageSelection1(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -908,7 +909,7 @@ func TestOptimalMessageSelection2(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -918,7 +919,7 @@ func TestOptimalMessageSelection2(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -984,7 +985,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 +993,7 @@ func TestOptimalMessageSelection3(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
a, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -1064,7 +1065,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 +1073,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(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -1330,7 +1331,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 +1343,7 @@ readLoop:
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
a, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -1360,7 +1361,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)
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/wallet"
|
"github.com/filecoin-project/lotus/chain/wallet"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
ds_sync "github.com/ipfs/go-datastore/sync"
|
ds_sync "github.com/ipfs/go-datastore/sync"
|
||||||
@ -47,13 +46,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, types.KTSecp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
from2, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
from2, err := w.WalletNew(ctx, types.KTSecp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
to1, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
to1, err := w.WalletNew(ctx, types.KTSecp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
to2, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
to2, err := w.WalletNew(ctx, types.KTSecp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
type msgSpec struct {
|
type msgSpec struct {
|
||||||
@ -177,7 +176,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 {
|
||||||
|
@ -61,7 +61,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.
|
|||||||
Rand: store.NewChainRand(sm.cs, ts.Cids()),
|
Rand: store.NewChainRand(sm.cs, ts.Cids()),
|
||||||
Bstore: sm.cs.Blockstore(),
|
Bstore: sm.cs.Blockstore(),
|
||||||
Syscalls: sm.cs.VMSys(),
|
Syscalls: sm.cs.VMSys(),
|
||||||
CircSupplyCalc: sm.GetCirculatingSupply,
|
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||||
NtwkVersion: sm.GetNtwkVersion,
|
NtwkVersion: sm.GetNtwkVersion,
|
||||||
BaseFee: types.NewInt(0),
|
BaseFee: types.NewInt(0),
|
||||||
}
|
}
|
||||||
@ -174,7 +174,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
|||||||
Rand: r,
|
Rand: r,
|
||||||
Bstore: sm.cs.Blockstore(),
|
Bstore: sm.cs.Blockstore(),
|
||||||
Syscalls: sm.cs.VMSys(),
|
Syscalls: sm.cs.VMSys(),
|
||||||
CircSupplyCalc: sm.GetCirculatingSupply,
|
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||||
NtwkVersion: sm.GetNtwkVersion,
|
NtwkVersion: sm.GetNtwkVersion,
|
||||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ 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/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
@ -80,9 +79,12 @@ func DefaultUpgradeSchedule() UpgradeSchedule {
|
|||||||
Network: network.Version4,
|
Network: network.Version4,
|
||||||
Expensive: true,
|
Expensive: true,
|
||||||
Migration: UpgradeActorsV2,
|
Migration: UpgradeActorsV2,
|
||||||
|
}, {
|
||||||
|
Height: build.UpgradeTapeHeight,
|
||||||
|
Network: network.Version5,
|
||||||
}, {
|
}, {
|
||||||
Height: build.UpgradeLiftoffHeight,
|
Height: build.UpgradeLiftoffHeight,
|
||||||
Network: network.Version4,
|
Network: network.Version5,
|
||||||
Migration: UpgradeLiftoff,
|
Migration: UpgradeLiftoff,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@ -263,11 +265,6 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
|||||||
return cid.Undef, xerrors.Errorf("loading state tree failed: %w", err)
|
return cid.Undef, xerrors.Errorf("loading state tree failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ReserveAddress, err := address.NewFromString("t090")
|
|
||||||
if err != nil {
|
|
||||||
return cid.Undef, xerrors.Errorf("failed to parse reserve address: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tree, err := sm.StateTree(root)
|
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)
|
||||||
@ -293,7 +290,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
|||||||
if !sysAcc {
|
if !sysAcc {
|
||||||
transfers = append(transfers, transfer{
|
transfers = append(transfers, transfer{
|
||||||
From: addr,
|
From: addr,
|
||||||
To: ReserveAddress,
|
To: builtin.ReserveAddress,
|
||||||
Amt: act.Balance,
|
Amt: act.Balance,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -317,7 +314,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
|||||||
|
|
||||||
transfers = append(transfers, transfer{
|
transfers = append(transfers, transfer{
|
||||||
From: addr,
|
From: addr,
|
||||||
To: ReserveAddress,
|
To: builtin.ReserveAddress,
|
||||||
Amt: available,
|
Amt: available,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -368,7 +365,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
|||||||
nbalance := big.Min(prevBalance, AccountCap)
|
nbalance := big.Min(prevBalance, AccountCap)
|
||||||
if nbalance.Sign() != 0 {
|
if nbalance.Sign() != 0 {
|
||||||
transfersBack = append(transfersBack, transfer{
|
transfersBack = append(transfersBack, transfer{
|
||||||
From: ReserveAddress,
|
From: builtin.ReserveAddress,
|
||||||
To: addr,
|
To: addr,
|
||||||
Amt: nbalance,
|
Amt: nbalance,
|
||||||
})
|
})
|
||||||
@ -395,7 +392,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
|||||||
|
|
||||||
mfunds := minerFundsAlloc(power, totalPower)
|
mfunds := minerFundsAlloc(power, totalPower)
|
||||||
transfersBack = append(transfersBack, transfer{
|
transfersBack = append(transfersBack, transfer{
|
||||||
From: ReserveAddress,
|
From: builtin.ReserveAddress,
|
||||||
To: minfo.Worker,
|
To: minfo.Worker,
|
||||||
Amt: mfunds,
|
Amt: mfunds,
|
||||||
})
|
})
|
||||||
@ -415,7 +412,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
|||||||
|
|
||||||
if lbsectors.Length() > 0 {
|
if lbsectors.Length() > 0 {
|
||||||
transfersBack = append(transfersBack, transfer{
|
transfersBack = append(transfersBack, transfer{
|
||||||
From: ReserveAddress,
|
From: builtin.ReserveAddress,
|
||||||
To: minfo.Worker,
|
To: minfo.Worker,
|
||||||
Amt: BaseMinerBalance,
|
Amt: BaseMinerBalance,
|
||||||
})
|
})
|
||||||
@ -442,7 +439,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("failed to load burnt funds actor: %w", err)
|
return cid.Undef, xerrors.Errorf("failed to load burnt funds actor: %w", err)
|
||||||
}
|
}
|
||||||
if err := doTransfer(cb, tree, builtin0.BurntFundsActorAddr, ReserveAddress, burntAct.Balance); err != nil {
|
if err := doTransfer(cb, tree, builtin0.BurntFundsActorAddr, builtin.ReserveAddress, burntAct.Balance); err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("failed to unburn funds: %w", err)
|
return cid.Undef, xerrors.Errorf("failed to unburn funds: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,7 +455,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
|||||||
}
|
}
|
||||||
|
|
||||||
difference := types.BigSub(DesiredReimbursementBalance, reimb.Balance)
|
difference := types.BigSub(DesiredReimbursementBalance, reimb.Balance)
|
||||||
if err := doTransfer(cb, tree, ReserveAddress, reimbAddr, difference); err != nil {
|
if err := doTransfer(cb, tree, builtin.ReserveAddress, reimbAddr, difference); err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("failed to top up reimbursement account: %w", err)
|
return cid.Undef, xerrors.Errorf("failed to top up reimbursement account: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -543,12 +540,7 @@ func UpgradeRefuel(ctx context.Context, sm *StateManager, cb ExecCallback, root
|
|||||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
addr, err := address.NewFromString("t0122")
|
err = resetMultisigVesting(ctx, store, tree, builtin.SaftAddress, 0, 0, big.Zero())
|
||||||
if err != nil {
|
|
||||||
return cid.Undef, xerrors.Errorf("getting address: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = resetMultisigVesting(ctx, store, tree, addr, 0, 0, big.Zero())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, xerrors.Errorf("tweaking msig vesting: %w", err)
|
return cid.Undef, xerrors.Errorf("tweaking msig vesting: %w", err)
|
||||||
}
|
}
|
||||||
@ -580,19 +572,6 @@ 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{
|
||||||
Version: types.StateTreeVersion1,
|
Version: types.StateTreeVersion1,
|
||||||
Actors: newHamtRoot,
|
Actors: newHamtRoot,
|
||||||
|
@ -6,15 +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"
|
||||||
init0 "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"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"golang.org/x/xerrors"
|
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
"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"
|
||||||
@ -25,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() {
|
||||||
@ -186,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)
|
||||||
}
|
}
|
||||||
@ -214,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
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,16 @@ package stmgr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin/verifreg"
|
||||||
|
|
||||||
|
_init "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||||
|
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||||
@ -37,8 +43,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
|
||||||
@ -220,7 +234,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
|||||||
Rand: r,
|
Rand: r,
|
||||||
Bstore: sm.cs.Blockstore(),
|
Bstore: sm.cs.Blockstore(),
|
||||||
Syscalls: sm.cs.VMSys(),
|
Syscalls: sm.cs.VMSys(),
|
||||||
CircSupplyCalc: sm.GetCirculatingSupply,
|
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||||
NtwkVersion: sm.GetNtwkVersion,
|
NtwkVersion: sm.GetNtwkVersion,
|
||||||
BaseFee: baseFee,
|
BaseFee: baseFee,
|
||||||
}
|
}
|
||||||
@ -507,16 +521,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)
|
||||||
}
|
}
|
||||||
@ -525,9 +530,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()
|
||||||
|
|
||||||
@ -565,7 +570,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
|
||||||
@ -657,7 +662,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)
|
||||||
@ -671,11 +676,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
|
||||||
}
|
}
|
||||||
@ -686,32 +713,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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1267,7 +1299,16 @@ func GetFilBurnt(ctx context.Context, st *state.StateTree) (abi.TokenAmount, err
|
|||||||
return burnt.Balance, nil
|
return burnt.Balance, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) GetCirculatingSupplyDetailed(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (api.CirculatingSupply, error) {
|
func (sm *StateManager) GetVMCirculatingSupply(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (abi.TokenAmount, error) {
|
||||||
|
cs, err := sm.GetVMCirculatingSupplyDetailed(ctx, height, st)
|
||||||
|
if err != nil {
|
||||||
|
return types.EmptyInt, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cs.FilCirculating, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm *StateManager) GetVMCirculatingSupplyDetailed(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (api.CirculatingSupply, error) {
|
||||||
sm.genesisMsigLk.Lock()
|
sm.genesisMsigLk.Lock()
|
||||||
defer sm.genesisMsigLk.Unlock()
|
defer sm.genesisMsigLk.Unlock()
|
||||||
if sm.preIgnitionGenInfos == nil {
|
if sm.preIgnitionGenInfos == nil {
|
||||||
@ -1330,12 +1371,91 @@ func (sm *StateManager) GetCirculatingSupplyDetailed(ctx context.Context, height
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (abi.TokenAmount, error) {
|
func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (abi.TokenAmount, error) {
|
||||||
csi, err := sm.GetCirculatingSupplyDetailed(ctx, height, st)
|
circ := big.Zero()
|
||||||
|
unCirc := big.Zero()
|
||||||
|
err := st.ForEach(func(a address.Address, actor *types.Actor) error {
|
||||||
|
switch {
|
||||||
|
case actor.Balance.IsZero():
|
||||||
|
// Do nothing for zero-balance actors
|
||||||
|
break
|
||||||
|
case a == _init.Address ||
|
||||||
|
a == reward.Address ||
|
||||||
|
a == verifreg.Address ||
|
||||||
|
// The power actor itself should never receive funds
|
||||||
|
a == power.Address ||
|
||||||
|
a == builtin.SystemActorAddr ||
|
||||||
|
a == builtin.CronActorAddr ||
|
||||||
|
a == builtin.BurntFundsActorAddr ||
|
||||||
|
a == builtin.SaftAddress ||
|
||||||
|
a == builtin.ReserveAddress:
|
||||||
|
|
||||||
|
unCirc = big.Add(unCirc, actor.Balance)
|
||||||
|
|
||||||
|
case a == market.Address:
|
||||||
|
mst, err := market.Load(sm.cs.Store(ctx), actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
lb, err := mst.TotalLocked()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
circ = big.Add(circ, big.Sub(actor.Balance, lb))
|
||||||
|
unCirc = big.Add(unCirc, lb)
|
||||||
|
|
||||||
|
case builtin.IsAccountActor(actor.Code) || builtin.IsPaymentChannelActor(actor.Code):
|
||||||
|
circ = big.Add(circ, actor.Balance)
|
||||||
|
|
||||||
|
case builtin.IsStorageMinerActor(actor.Code):
|
||||||
|
mst, err := miner.Load(sm.cs.Store(ctx), actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ab, err := mst.AvailableBalance(actor.Balance)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
circ = big.Add(circ, ab)
|
||||||
|
unCirc = big.Add(unCirc, big.Sub(actor.Balance, ab))
|
||||||
|
} else {
|
||||||
|
// Assume any error is because the miner state is "broken" (lower actor balance than locked funds)
|
||||||
|
// In this case, the actor's entire balance is considered "uncirculating"
|
||||||
|
unCirc = big.Add(unCirc, actor.Balance)
|
||||||
|
}
|
||||||
|
|
||||||
|
case builtin.IsMultisigActor(actor.Code):
|
||||||
|
mst, err := multisig.Load(sm.cs.Store(ctx), actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
lb, err := mst.LockedBalance(height)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ab := big.Sub(actor.Balance, lb)
|
||||||
|
circ = big.Add(circ, big.Max(ab, big.Zero()))
|
||||||
|
unCirc = big.Add(unCirc, big.Min(actor.Balance, lb))
|
||||||
|
default:
|
||||||
|
return xerrors.Errorf("unexpected actor: %s", a)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return big.Zero(), err
|
return types.EmptyInt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return csi.FilCirculating, nil
|
total := big.Add(circ, unCirc)
|
||||||
|
if !total.Equals(types.TotalFilecoinInt) {
|
||||||
|
return types.EmptyInt, xerrors.Errorf("total filecoin didn't add to expected amount: %s != %s", total, types.TotalFilecoinInt)
|
||||||
|
}
|
||||||
|
|
||||||
|
return circ, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) network.Version {
|
func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) network.Version {
|
||||||
@ -1384,3 +1504,5 @@ func (sm *StateManager) GetMarketState(ctx context.Context, ts *types.TipSet) (m
|
|||||||
}
|
}
|
||||||
return actState, nil
|
return actState, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ StateManagerAPI = (*StateManager)(nil)
|
||||||
|
@ -383,7 +383,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
|||||||
Rand: r,
|
Rand: r,
|
||||||
Bstore: sm.cs.Blockstore(),
|
Bstore: sm.cs.Blockstore(),
|
||||||
Syscalls: sm.cs.VMSys(),
|
Syscalls: sm.cs.VMSys(),
|
||||||
CircSupplyCalc: sm.GetCirculatingSupply,
|
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||||
NtwkVersion: sm.GetNtwkVersion,
|
NtwkVersion: sm.GetNtwkVersion,
|
||||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1466,7 +1478,7 @@ func (syncer *Syncer) syncFork(ctx context.Context, incoming *types.TipSet, know
|
|||||||
|
|
||||||
func (syncer *Syncer) syncMessagesAndCheckState(ctx context.Context, headers []*types.TipSet) error {
|
func (syncer *Syncer) syncMessagesAndCheckState(ctx context.Context, headers []*types.TipSet) error {
|
||||||
ss := extractSyncState(ctx)
|
ss := extractSyncState(ctx)
|
||||||
ss.SetHeight(0)
|
ss.SetHeight(headers[len(headers)-1].Height())
|
||||||
|
|
||||||
return syncer.iterFullTipsets(ctx, headers, func(ctx context.Context, fts *store.FullTipSet) error {
|
return syncer.iterFullTipsets(ctx, headers, func(ctx context.Context, fts *store.FullTipSet) error {
|
||||||
log.Debugw("validating tipset", "height", fts.TipSet().Height(), "size", len(fts.TipSet().Cids()))
|
log.Debugw("validating tipset", "height", fts.TipSet().Height(), "size", len(fts.TipSet().Cids()))
|
||||||
@ -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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -9,9 +12,50 @@ var (
|
|||||||
ErrKeyExists = fmt.Errorf("key already exists")
|
ErrKeyExists = fmt.Errorf("key already exists")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// KeyType defines a type of a key
|
||||||
|
type KeyType string
|
||||||
|
|
||||||
|
func (kt *KeyType) UnmarshalJSON(bb []byte) error {
|
||||||
|
{
|
||||||
|
// first option, try unmarshaling as string
|
||||||
|
var s string
|
||||||
|
err := json.Unmarshal(bb, &s)
|
||||||
|
if err == nil {
|
||||||
|
*kt = KeyType(s)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var b byte
|
||||||
|
err := json.Unmarshal(bb, &b)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not unmarshal KeyType either as string nor integer: %w", err)
|
||||||
|
}
|
||||||
|
bst := crypto.SigType(b)
|
||||||
|
|
||||||
|
switch bst {
|
||||||
|
case crypto.SigTypeBLS:
|
||||||
|
*kt = KTBLS
|
||||||
|
case crypto.SigTypeSecp256k1:
|
||||||
|
*kt = KTSecp256k1
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown sigtype: %d", bst)
|
||||||
|
}
|
||||||
|
log.Warnf("deprecation: integer style 'KeyType' is deprecated, switch to string style")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
KTBLS KeyType = "bls"
|
||||||
|
KTSecp256k1 KeyType = "secp256k1"
|
||||||
|
KTSecp256k1Ledger KeyType = "secp256k1-ledger"
|
||||||
|
)
|
||||||
|
|
||||||
// KeyInfo is used for storing keys in KeyStore
|
// KeyInfo is used for storing keys in KeyStore
|
||||||
type KeyInfo struct {
|
type KeyInfo struct {
|
||||||
Type string
|
Type KeyType
|
||||||
PrivateKey []byte
|
PrivateKey []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package types
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
@ -106,6 +107,20 @@ func (m *Message) Cid() cid.Cid {
|
|||||||
return b.Cid()
|
return b.Cid()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mCid struct {
|
||||||
|
*RawMessage
|
||||||
|
CID cid.Cid
|
||||||
|
}
|
||||||
|
|
||||||
|
type RawMessage Message
|
||||||
|
|
||||||
|
func (m *Message) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(&mCid{
|
||||||
|
RawMessage: (*RawMessage)(m),
|
||||||
|
CID: m.Cid(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Message) RequiredFunds() BigInt {
|
func (m *Message) RequiredFunds() BigInt {
|
||||||
return BigMul(m.GasFeeCap, NewInt(uint64(m.GasLimit)))
|
return BigMul(m.GasFeeCap, NewInt(uint64(m.GasLimit)))
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -70,3 +73,66 @@ func TestEqualCall(t *testing.T) {
|
|||||||
require.True(t, m1.EqualCall(m3))
|
require.True(t, m1.EqualCall(m3))
|
||||||
require.False(t, m1.EqualCall(m4))
|
require.False(t, m1.EqualCall(m4))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMessageJson(t *testing.T) {
|
||||||
|
m := &Message{
|
||||||
|
To: builtin.StoragePowerActorAddr,
|
||||||
|
From: builtin.SystemActorAddr,
|
||||||
|
Nonce: 34,
|
||||||
|
Value: big.Zero(),
|
||||||
|
|
||||||
|
GasLimit: 123,
|
||||||
|
GasFeeCap: big.NewInt(234),
|
||||||
|
GasPremium: big.NewInt(234),
|
||||||
|
|
||||||
|
Method: 6,
|
||||||
|
Params: []byte("hai"),
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := json.Marshal(m)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
exp := []byte("{\"Version\":0,\"To\":\"f04\",\"From\":\"f00\",\"Nonce\":34,\"Value\":\"0\",\"GasLimit\":123,\"GasFeeCap\":\"234\",\"GasPremium\":\"234\",\"Method\":6,\"Params\":\"aGFp\",\"CID\":{\"/\":\"bafy2bzaced5rdpz57e64sc7mdwjn3blicglhpialnrph2dlbufhf6iha63dmc\"}}")
|
||||||
|
fmt.Println(string(b))
|
||||||
|
|
||||||
|
require.Equal(t, exp, b)
|
||||||
|
|
||||||
|
var um Message
|
||||||
|
require.NoError(t, json.Unmarshal(b, &um))
|
||||||
|
|
||||||
|
require.EqualValues(t, *m, um)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSignedMessageJson(t *testing.T) {
|
||||||
|
m := Message{
|
||||||
|
To: builtin.StoragePowerActorAddr,
|
||||||
|
From: builtin.SystemActorAddr,
|
||||||
|
Nonce: 34,
|
||||||
|
Value: big.Zero(),
|
||||||
|
|
||||||
|
GasLimit: 123,
|
||||||
|
GasFeeCap: big.NewInt(234),
|
||||||
|
GasPremium: big.NewInt(234),
|
||||||
|
|
||||||
|
Method: 6,
|
||||||
|
Params: []byte("hai"),
|
||||||
|
}
|
||||||
|
|
||||||
|
sm := &SignedMessage{
|
||||||
|
Message: m,
|
||||||
|
Signature: crypto.Signature{},
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := json.Marshal(sm)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
exp := []byte("{\"Message\":{\"Version\":0,\"To\":\"f04\",\"From\":\"f00\",\"Nonce\":34,\"Value\":\"0\",\"GasLimit\":123,\"GasFeeCap\":\"234\",\"GasPremium\":\"234\",\"Method\":6,\"Params\":\"aGFp\",\"CID\":{\"/\":\"bafy2bzaced5rdpz57e64sc7mdwjn3blicglhpialnrph2dlbufhf6iha63dmc\"}},\"Signature\":{\"Type\":0,\"Data\":null},\"CID\":{\"/\":\"bafy2bzacea5ainifngxj3rygaw2hppnyz2cw72x5pysqty2x6dxmjs5qg2uus\"}}")
|
||||||
|
fmt.Println(string(b))
|
||||||
|
|
||||||
|
require.Equal(t, exp, b)
|
||||||
|
|
||||||
|
var um SignedMessage
|
||||||
|
require.NoError(t, json.Unmarshal(b, &um))
|
||||||
|
|
||||||
|
require.EqualValues(t, *sm, um)
|
||||||
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/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,6 +2,7 @@ package types
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
@ -62,6 +63,20 @@ func (sm *SignedMessage) Serialize() ([]byte, error) {
|
|||||||
return buf.Bytes(), nil
|
return buf.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type smCid struct {
|
||||||
|
*RawSignedMessage
|
||||||
|
CID cid.Cid
|
||||||
|
}
|
||||||
|
|
||||||
|
type RawSignedMessage SignedMessage
|
||||||
|
|
||||||
|
func (sm *SignedMessage) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(&smCid{
|
||||||
|
RawSignedMessage: (*RawSignedMessage)(sm),
|
||||||
|
CID: sm.Cid(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (sm *SignedMessage) ChainLength() int {
|
func (sm *SignedMessage) ChainLength() int {
|
||||||
ser, err := sm.Serialize()
|
ser, err := sm.Serialize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@ -10,7 +11,6 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||||
"github.com/filecoin-project/lotus/chain/gen"
|
"github.com/filecoin-project/lotus/chain/gen"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
@ -61,11 +61,11 @@ func MakeMessageSigningVectors() []vectors.MessageSigningVector {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
blsk, err := w.GenerateKey(crypto.SigTypeBLS)
|
blsk, err := w.WalletNew(context.Background(), types.KTBLS)
|
||||||
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 +85,11 @@ func MakeMessageSigningVectors() []vectors.MessageSigningVector {
|
|||||||
Signature: &bmsg.Signature,
|
Signature: &bmsg.Signature,
|
||||||
}
|
}
|
||||||
|
|
||||||
secpk, err := w.GenerateKey(crypto.SigTypeBLS)
|
secpk, err := w.WalletNew(context.Background(), types.KTBLS)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
74
chain/wallet/key.go
Normal file
74
chain/wallet/key.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package wallet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/lib/sigs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GenerateKey(typ types.KeyType) (*Key, error) {
|
||||||
|
ctyp := ActSigType(typ)
|
||||||
|
if ctyp == crypto.SigTypeUnknown {
|
||||||
|
return nil, xerrors.Errorf("unknown sig type: %s", typ)
|
||||||
|
}
|
||||||
|
pk, err := sigs.Generate(ctyp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ki := types.KeyInfo{
|
||||||
|
Type: typ,
|
||||||
|
PrivateKey: pk,
|
||||||
|
}
|
||||||
|
return NewKey(ki)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Key struct {
|
||||||
|
types.KeyInfo
|
||||||
|
|
||||||
|
PublicKey []byte
|
||||||
|
Address address.Address
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewKey(keyinfo types.KeyInfo) (*Key, error) {
|
||||||
|
k := &Key{
|
||||||
|
KeyInfo: keyinfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
k.PublicKey, err = sigs.ToPublic(ActSigType(k.Type), k.PrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch k.Type {
|
||||||
|
case types.KTSecp256k1:
|
||||||
|
k.Address, err = address.NewSecp256k1Address(k.PublicKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("converting Secp256k1 to address: %w", err)
|
||||||
|
}
|
||||||
|
case types.KTBLS:
|
||||||
|
k.Address, err = address.NewBLSAddress(k.PublicKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("converting BLS to address: %w", err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, xerrors.Errorf("unsupported key type: %s", k.Type)
|
||||||
|
}
|
||||||
|
return k, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func ActSigType(typ types.KeyType) crypto.SigType {
|
||||||
|
switch typ {
|
||||||
|
case types.KTBLS:
|
||||||
|
return crypto.SigTypeBLS
|
||||||
|
case types.KTSecp256k1:
|
||||||
|
return crypto.SigTypeSecp256k1
|
||||||
|
default:
|
||||||
|
return crypto.SigTypeUnknown
|
||||||
|
}
|
||||||
|
}
|
242
chain/wallet/ledger/ledger.go
Normal file
242
chain/wallet/ledger/ledger.go
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
package ledgerwallet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
"github.com/ipfs/go-datastore"
|
||||||
|
"github.com/ipfs/go-datastore/query"
|
||||||
|
logging "github.com/ipfs/go-log"
|
||||||
|
ledgerfil "github.com/whyrusleeping/ledger-filecoin-go"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
var log = logging.Logger("wallet-ledger")
|
||||||
|
|
||||||
|
type LedgerWallet struct {
|
||||||
|
ds datastore.Datastore
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWallet(ds dtypes.MetadataDS) *LedgerWallet {
|
||||||
|
return &LedgerWallet{ds}
|
||||||
|
}
|
||||||
|
|
||||||
|
type LedgerKeyInfo struct {
|
||||||
|
Address address.Address
|
||||||
|
Path []uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ api.WalletAPI = (*LedgerWallet)(nil)
|
||||||
|
|
||||||
|
func (lw LedgerWallet) WalletSign(ctx context.Context, signer address.Address, toSign []byte, meta api.MsgMeta) (*crypto.Signature, error) {
|
||||||
|
ki, err := lw.getKeyInfo(signer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fl, err := ledgerfil.FindLedgerFilecoinApp()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer fl.Close() // nolint:errcheck
|
||||||
|
if meta.Type != api.MTChainMsg {
|
||||||
|
return nil, fmt.Errorf("ledger can only sign chain messages")
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var cmsg types.Message
|
||||||
|
if err := cmsg.UnmarshalCBOR(bytes.NewReader(meta.Extra)); err != nil {
|
||||||
|
return nil, xerrors.Errorf("unmarshalling message: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, bc, err := cid.CidFromBytes(toSign)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("getting cid from signing bytes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cmsg.Cid().Equals(bc) {
|
||||||
|
return nil, xerrors.Errorf("cid(meta.Extra).bytes() != toSign")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sig, err := fl.SignSECP256K1(ki.Path, meta.Extra)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &crypto.Signature{
|
||||||
|
Type: crypto.SigTypeSecp256k1,
|
||||||
|
Data: sig.SignatureBytes(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lw LedgerWallet) getKeyInfo(addr address.Address) (*LedgerKeyInfo, error) {
|
||||||
|
kib, err := lw.ds.Get(keyForAddr(addr))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var out LedgerKeyInfo
|
||||||
|
if err := json.Unmarshal(kib, &out); err != nil {
|
||||||
|
return nil, xerrors.Errorf("unmarshalling ledger key info: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lw LedgerWallet) WalletDelete(ctx context.Context, k address.Address) error {
|
||||||
|
return lw.ds.Delete(keyForAddr(k))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lw LedgerWallet) WalletExport(ctx context.Context, k address.Address) (*types.KeyInfo, error) {
|
||||||
|
return nil, fmt.Errorf("cannot export keys from ledger wallets")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lw LedgerWallet) WalletHas(ctx context.Context, k address.Address) (bool, error) {
|
||||||
|
_, err := lw.ds.Get(keyForAddr(k))
|
||||||
|
if err == nil {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if err == datastore.ErrNotFound {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lw LedgerWallet) WalletImport(ctx context.Context, kinfo *types.KeyInfo) (address.Address, error) {
|
||||||
|
var ki LedgerKeyInfo
|
||||||
|
if err := json.Unmarshal(kinfo.PrivateKey, &ki); err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
return lw.importKey(ki)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lw LedgerWallet) importKey(ki LedgerKeyInfo) (address.Address, error) {
|
||||||
|
if ki.Address == address.Undef {
|
||||||
|
return address.Undef, fmt.Errorf("no address given in imported key info")
|
||||||
|
}
|
||||||
|
if len(ki.Path) != filHdPathLen {
|
||||||
|
return address.Undef, fmt.Errorf("bad hd path len: %d, expected: %d", len(ki.Path), filHdPathLen)
|
||||||
|
}
|
||||||
|
bb, err := json.Marshal(ki)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, xerrors.Errorf("marshaling key info: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := lw.ds.Put(keyForAddr(ki.Address), bb); err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ki.Address, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lw LedgerWallet) WalletList(ctx context.Context) ([]address.Address, error) {
|
||||||
|
res, err := lw.ds.Query(query.Query{Prefix: dsLedgerPrefix})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Close() // nolint:errcheck
|
||||||
|
|
||||||
|
var out []address.Address
|
||||||
|
for {
|
||||||
|
res, ok := res.NextSync()
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
var ki LedgerKeyInfo
|
||||||
|
if err := json.Unmarshal(res.Value, &ki); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out = append(out, ki.Address)
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const hdHard = 0x80000000
|
||||||
|
|
||||||
|
var filHDBasePath = []uint32{hdHard | 44, hdHard | 461, hdHard, 0}
|
||||||
|
var filHdPathLen = 5
|
||||||
|
|
||||||
|
func (lw LedgerWallet) WalletNew(ctx context.Context, t types.KeyType) (address.Address, error) {
|
||||||
|
if t != types.KTSecp256k1Ledger {
|
||||||
|
return address.Undef, fmt.Errorf("unsupported key type: '%s', only '%s' supported",
|
||||||
|
t, types.KTSecp256k1Ledger)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := lw.ds.Query(query.Query{Prefix: dsLedgerPrefix})
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
defer res.Close() // nolint:errcheck
|
||||||
|
|
||||||
|
var maxi int64 = -1
|
||||||
|
for {
|
||||||
|
res, ok := res.NextSync()
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
var ki LedgerKeyInfo
|
||||||
|
if err := json.Unmarshal(res.Value, &ki); err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
if i := ki.Path[filHdPathLen-1]; maxi == -1 || maxi < int64(i) {
|
||||||
|
maxi = int64(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fl, err := ledgerfil.FindLedgerFilecoinApp()
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, xerrors.Errorf("finding ledger: %w", err)
|
||||||
|
}
|
||||||
|
defer fl.Close() // nolint:errcheck
|
||||||
|
|
||||||
|
path := append(append([]uint32(nil), filHDBasePath...), uint32(maxi+1))
|
||||||
|
_, _, addr, err := fl.GetAddressPubKeySECP256K1(path)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, xerrors.Errorf("getting public key from ledger: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Warnf("creating key: %s, accept the key in ledger device", addr)
|
||||||
|
_, _, addr, err = fl.ShowAddressPubKeySECP256K1(path)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, xerrors.Errorf("verifying public key with ledger: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
a, err := address.NewFromString(addr)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, fmt.Errorf("parsing address: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var lki LedgerKeyInfo
|
||||||
|
lki.Address = a
|
||||||
|
lki.Path = path
|
||||||
|
|
||||||
|
return lw.importKey(lki)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lw *LedgerWallet) Get() api.WalletAPI {
|
||||||
|
if lw == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return lw
|
||||||
|
}
|
||||||
|
|
||||||
|
var dsLedgerPrefix = "/ledgerkey/"
|
||||||
|
|
||||||
|
func keyForAddr(addr address.Address) datastore.Key {
|
||||||
|
return datastore.NewKey(dsLedgerPrefix + addr.String())
|
||||||
|
}
|
170
chain/wallet/multi.go
Normal file
170
chain/wallet/multi.go
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
package wallet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"go.uber.org/fx"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
ledgerwallet "github.com/filecoin-project/lotus/chain/wallet/ledger"
|
||||||
|
"github.com/filecoin-project/lotus/chain/wallet/remotewallet"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MultiWallet struct {
|
||||||
|
fx.In // "constructed" with fx.In instead of normal constructor
|
||||||
|
|
||||||
|
Local *LocalWallet `optional:"true"`
|
||||||
|
Remote *remotewallet.RemoteWallet `optional:"true"`
|
||||||
|
Ledger *ledgerwallet.LedgerWallet `optional:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type getif interface {
|
||||||
|
api.WalletAPI
|
||||||
|
|
||||||
|
// workaround for the fact that iface(*struct(nil)) != nil
|
||||||
|
Get() api.WalletAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
func firstNonNil(wallets ...getif) api.WalletAPI {
|
||||||
|
for _, w := range wallets {
|
||||||
|
if w.Get() != nil {
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func nonNil(wallets ...getif) []api.WalletAPI {
|
||||||
|
var out []api.WalletAPI
|
||||||
|
for _, w := range wallets {
|
||||||
|
if w.Get() == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
out = append(out, w)
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MultiWallet) find(ctx context.Context, address address.Address, wallets ...getif) (api.WalletAPI, error) {
|
||||||
|
ws := nonNil(wallets...)
|
||||||
|
|
||||||
|
for _, w := range ws {
|
||||||
|
have, err := w.WalletHas(ctx, address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if have {
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MultiWallet) WalletNew(ctx context.Context, keyType types.KeyType) (address.Address, error) {
|
||||||
|
var local getif = m.Local
|
||||||
|
if keyType == types.KTSecp256k1Ledger {
|
||||||
|
local = m.Ledger
|
||||||
|
}
|
||||||
|
|
||||||
|
w := firstNonNil(m.Remote, local)
|
||||||
|
if w == nil {
|
||||||
|
return address.Undef, xerrors.Errorf("no wallet backends supporting key type: %s", keyType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return w.WalletNew(ctx, keyType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MultiWallet) WalletHas(ctx context.Context, address address.Address) (bool, error) {
|
||||||
|
w, err := m.find(ctx, address, m.Remote, m.Ledger, m.Local)
|
||||||
|
return w != nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MultiWallet) WalletList(ctx context.Context) ([]address.Address, error) {
|
||||||
|
var out []address.Address
|
||||||
|
seen := map[address.Address]struct{}{}
|
||||||
|
|
||||||
|
ws := nonNil(m.Remote, m.Ledger, m.Local)
|
||||||
|
for _, w := range ws {
|
||||||
|
l, err := w.WalletList(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, a := range l {
|
||||||
|
if _, ok := seen[a]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[a] = struct{}{}
|
||||||
|
|
||||||
|
out = append(out, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MultiWallet) WalletSign(ctx context.Context, signer address.Address, toSign []byte, meta api.MsgMeta) (*crypto.Signature, error) {
|
||||||
|
w, err := m.find(ctx, signer, m.Remote, m.Ledger, m.Local)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if w == nil {
|
||||||
|
return nil, xerrors.Errorf("key not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return w.WalletSign(ctx, signer, toSign, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MultiWallet) WalletExport(ctx context.Context, address address.Address) (*types.KeyInfo, error) {
|
||||||
|
w, err := m.find(ctx, address, m.Remote, m.Local)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if w == nil {
|
||||||
|
return nil, xerrors.Errorf("key not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return w.WalletExport(ctx, address)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MultiWallet) WalletImport(ctx context.Context, info *types.KeyInfo) (address.Address, error) {
|
||||||
|
var local getif = m.Local
|
||||||
|
if info.Type == types.KTSecp256k1Ledger {
|
||||||
|
local = m.Ledger
|
||||||
|
}
|
||||||
|
|
||||||
|
w := firstNonNil(m.Remote, local)
|
||||||
|
if w == nil {
|
||||||
|
return address.Undef, xerrors.Errorf("no wallet backends configured")
|
||||||
|
}
|
||||||
|
|
||||||
|
return w.WalletImport(ctx, info)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MultiWallet) WalletDelete(ctx context.Context, address address.Address) error {
|
||||||
|
for {
|
||||||
|
w, err := m.find(ctx, address, m.Remote, m.Ledger, m.Local)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if w == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := w.WalletDelete(ctx, address); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ api.WalletAPI = MultiWallet{}
|
50
chain/wallet/remotewallet/remote.go
Normal file
50
chain/wallet/remotewallet/remote.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package remotewallet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"go.uber.org/fx"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/api/client"
|
||||||
|
cliutil "github.com/filecoin-project/lotus/cli/util"
|
||||||
|
"github.com/filecoin-project/lotus/node/modules/helpers"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RemoteWallet struct {
|
||||||
|
api.WalletAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetupRemoteWallet(info string) func(mctx helpers.MetricsCtx, lc fx.Lifecycle) (*RemoteWallet, error) {
|
||||||
|
return func(mctx helpers.MetricsCtx, lc fx.Lifecycle) (*RemoteWallet, error) {
|
||||||
|
ai := cliutil.ParseApiInfo(info)
|
||||||
|
|
||||||
|
url, err := ai.DialArgs()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
wapi, closer, err := client.NewWalletRPC(mctx, url, ai.AuthHeader())
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("creating jsonrpc client: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
lc.Append(fx.Hook{
|
||||||
|
OnStop: func(ctx context.Context) error {
|
||||||
|
closer()
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return &RemoteWallet{wapi}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *RemoteWallet) Get() api.WalletAPI {
|
||||||
|
if w == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return w
|
||||||
|
}
|
@ -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
|
||||||
|
|
||||||
@ -25,19 +26,22 @@ const (
|
|||||||
KNamePrefix = "wallet-"
|
KNamePrefix = "wallet-"
|
||||||
KTrashPrefix = "trash-"
|
KTrashPrefix = "trash-"
|
||||||
KDefault = "default"
|
KDefault = "default"
|
||||||
KTBLS = "bls"
|
|
||||||
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 +49,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 +72,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 +100,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 +114,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 +134,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 +162,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 +195,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 +212,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 +234,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 types.KeyType) (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 +262,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 +270,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 +287,47 @@ 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 {
|
func (w *LocalWallet) Get() api.WalletAPI {
|
||||||
types.KeyInfo
|
if w == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
PublicKey []byte
|
return w
|
||||||
Address address.Address
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewKey(keyinfo types.KeyInfo) (*Key, error) {
|
var _ api.WalletAPI = &LocalWallet{}
|
||||||
k := &Key{
|
|
||||||
KeyInfo: keyinfo,
|
func swapMainnetForTestnetPrefix(addr string) (string, error) {
|
||||||
|
aChars := []rune(addr)
|
||||||
|
prefixRunes := []rune(address.TestnetPrefix)
|
||||||
|
if len(prefixRunes) != 1 {
|
||||||
|
return "", xerrors.Errorf("unexpected prefix length: %d", len(prefixRunes))
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
aChars[0] = prefixRunes[0]
|
||||||
k.PublicKey, err = sigs.ToPublic(ActSigType(k.Type), k.PrivateKey)
|
return string(aChars), nil
|
||||||
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 {
|
type nilDefault struct{}
|
||||||
switch typ {
|
|
||||||
case crypto.SigTypeBLS:
|
func (n nilDefault) GetDefault() (address.Address, error) {
|
||||||
return KTBLS
|
return address.Undef, nil
|
||||||
case crypto.SigTypeSecp256k1:
|
|
||||||
return KTSecp256k1
|
|
||||||
default:
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ActSigType(typ string) crypto.SigType {
|
func (n nilDefault) SetDefault(a address.Address) error {
|
||||||
switch typ {
|
return xerrors.Errorf("not supported; local wallet disabled")
|
||||||
case KTBLS:
|
|
||||||
return crypto.SigTypeBLS
|
|
||||||
case KTSecp256k1:
|
|
||||||
return crypto.SigTypeSecp256k1
|
|
||||||
default:
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var NilDefault nilDefault
|
||||||
|
var _ Default = NilDefault
|
||||||
|
85
cli/chain.go
85
cli/chain.go
@ -3,6 +3,7 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
@ -53,6 +54,7 @@ var chainCmd = &cli.Command{
|
|||||||
slashConsensusFault,
|
slashConsensusFault,
|
||||||
chainGasPriceCmd,
|
chainGasPriceCmd,
|
||||||
chainInspectUsage,
|
chainInspectUsage,
|
||||||
|
chainDecodeCmd,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,11 +451,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 +471,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 +503,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 +523,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},
|
||||||
@ -1228,3 +1236,68 @@ var chainGasPriceCmd = &cli.Command{
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var chainDecodeCmd = &cli.Command{
|
||||||
|
Name: "decode",
|
||||||
|
Usage: "decode various types",
|
||||||
|
Subcommands: []*cli.Command{
|
||||||
|
chainDecodeParamsCmd,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var chainDecodeParamsCmd = &cli.Command{
|
||||||
|
Name: "params",
|
||||||
|
Usage: "Decode message params",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "tipset",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ArgsUsage: "[toAddr method hexParams]",
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
api, closer, err := GetFullNodeAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
ctx := ReqContext(cctx)
|
||||||
|
|
||||||
|
if cctx.Args().Len() != 3 {
|
||||||
|
return ShowHelp(cctx, fmt.Errorf("incorrect number of arguments"))
|
||||||
|
}
|
||||||
|
|
||||||
|
to, err := address.NewFromString(cctx.Args().First())
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("parsing toAddr: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
method, err := strconv.ParseInt(cctx.Args().Get(1), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("parsing method id: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
params, err := hex.DecodeString(cctx.Args().Get(2))
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("parsing hex params: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ts, err := LoadTipSet(ctx, cctx, api)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
act, err := api.StateGetActor(ctx, to, ts.Key())
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getting actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pstr, err := jsonParams(act.Code, abi.MethodNum(method), params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(pstr)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,6 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/events"
|
"github.com/filecoin-project/lotus/chain/events"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/wallet"
|
|
||||||
builder "github.com/filecoin-project/lotus/node/test"
|
builder "github.com/filecoin-project/lotus/node/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -121,13 +120,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 +389,7 @@ func checkVoucherOutput(t *testing.T, list string, vouchers []voucherSpec) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func startTwoNodesOneMiner(ctx context.Context, t *testing.T, blocktime time.Duration) ([]test.TestNode, []address.Address) {
|
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]
|
||||||
@ -415,7 +414,7 @@ func startTwoNodesOneMiner(ctx context.Context, t *testing.T, blocktime time.Dur
|
|||||||
bm.MineBlocks()
|
bm.MineBlocks()
|
||||||
|
|
||||||
// Send some funds to register the receiver
|
// Send some funds to register the receiver
|
||||||
receiverAddr, err := paymentReceiver.WalletNew(ctx, wallet.ActSigType("secp256k1"))
|
receiverAddr, err := paymentReceiver.WalletNew(ctx, types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -439,12 +438,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 +475,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 +492,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
|
||||||
}
|
}
|
||||||
|
37
cli/state.go
37
cli/state.go
@ -1688,7 +1688,14 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er
|
|||||||
|
|
||||||
var stateCircSupplyCmd = &cli.Command{
|
var stateCircSupplyCmd = &cli.Command{
|
||||||
Name: "circulating-supply",
|
Name: "circulating-supply",
|
||||||
Usage: "Get the current circulating supply of filecoin",
|
Usage: "Get the exact current circulating supply of Filecoin",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "vm-supply",
|
||||||
|
Usage: "calculates the approximation of the circulating supply used internally by the VM (instead of the exact amount)",
|
||||||
|
Value: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
api, closer, err := GetFullNodeAPI(cctx)
|
api, closer, err := GetFullNodeAPI(cctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1703,16 +1710,26 @@ var stateCircSupplyCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
circ, err := api.StateCirculatingSupply(ctx, ts.Key())
|
if cctx.IsSet("vm-supply") {
|
||||||
if err != nil {
|
circ, err := api.StateVMCirculatingSupplyInternal(ctx, ts.Key())
|
||||||
return err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println("Circulating supply: ", types.FIL(circ.FilCirculating))
|
fmt.Println("Circulating supply: ", types.FIL(circ.FilCirculating))
|
||||||
fmt.Println("Mined: ", types.FIL(circ.FilMined))
|
fmt.Println("Mined: ", types.FIL(circ.FilMined))
|
||||||
fmt.Println("Vested: ", types.FIL(circ.FilVested))
|
fmt.Println("Vested: ", types.FIL(circ.FilVested))
|
||||||
fmt.Println("Burnt: ", types.FIL(circ.FilBurnt))
|
fmt.Println("Burnt: ", types.FIL(circ.FilBurnt))
|
||||||
fmt.Println("Locked: ", types.FIL(circ.FilLocked))
|
fmt.Println("Locked: ", types.FIL(circ.FilLocked))
|
||||||
|
} else {
|
||||||
|
circ, err := api.StateCirculatingSupply(ctx, ts.Key())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Exact circulating supply: ", types.FIL(circ))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
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
|
||||||
|
}
|
@ -17,7 +17,6 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
|
|
||||||
types "github.com/filecoin-project/lotus/chain/types"
|
types "github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/wallet"
|
|
||||||
"github.com/filecoin-project/lotus/lib/tablewriter"
|
"github.com/filecoin-project/lotus/lib/tablewriter"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -55,7 +54,7 @@ var walletNew = &cli.Command{
|
|||||||
t = "secp256k1"
|
t = "secp256k1"
|
||||||
}
|
}
|
||||||
|
|
||||||
nk, err := api.WalletNew(ctx, wallet.ActSigType(t))
|
nk, err := api.WalletNew(ctx, types.KeyType(t))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -329,9 +328,9 @@ var walletImport = &cli.Command{
|
|||||||
ki.PrivateKey = gk.PrivateKey
|
ki.PrivateKey = gk.PrivateKey
|
||||||
switch gk.SigType {
|
switch gk.SigType {
|
||||||
case 1:
|
case 1:
|
||||||
ki.Type = wallet.KTSecp256k1
|
ki.Type = types.KTSecp256k1
|
||||||
case 2:
|
case 2:
|
||||||
ki.Type = wallet.KTBLS
|
ki.Type = types.KTBLS
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unrecognized key type: %d", gk.SigType)
|
return fmt.Errorf("unrecognized key type: %d", gk.SigType)
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
@ -61,7 +59,7 @@ var runCmd = &cli.Command{
|
|||||||
func sendSmallFundsTxs(ctx context.Context, api api.FullNode, from address.Address, rate int) error {
|
func sendSmallFundsTxs(ctx context.Context, api api.FullNode, from address.Address, rate int) error {
|
||||||
var sendSet []address.Address
|
var sendSet []address.Address
|
||||||
for i := 0; i < 20; i++ {
|
for i := 0; i < 20; i++ {
|
||||||
naddr, err := api.WalletNew(ctx, crypto.SigTypeSecp256k1)
|
naddr, err := api.WalletNew(ctx, types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -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") {
|
||||||
|
@ -316,7 +316,7 @@ limit 1
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Syncer) storeCirculatingSupply(ctx context.Context, tipset *types.TipSet) error {
|
func (s *Syncer) storeCirculatingSupply(ctx context.Context, tipset *types.TipSet) error {
|
||||||
supply, err := s.node.StateCirculatingSupply(ctx, tipset.Key())
|
supply, err := s.node.StateVMCirculatingSupplyInternal(ctx, tipset.Key())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
|
}
|
210
cmd/lotus-gateway/endtoend_test.go
Normal file
210
cmd/lotus-gateway/endtoend_test.go
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-jsonrpc"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/api/client"
|
||||||
|
"github.com/filecoin-project/lotus/api/test"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/node"
|
||||||
|
builder "github.com/filecoin-project/lotus/node/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1)
|
||||||
|
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
|
||||||
|
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestEndToEnd tests that API calls can be made on a lite node that is
|
||||||
|
// connected through a gateway to a full API node
|
||||||
|
func TestEndToEnd(t *testing.T) {
|
||||||
|
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||||
|
|
||||||
|
blocktime := 5 * time.Millisecond
|
||||||
|
ctx := context.Background()
|
||||||
|
full, lite, closer := startNodes(ctx, t, blocktime)
|
||||||
|
defer closer()
|
||||||
|
|
||||||
|
// The full node starts with a wallet
|
||||||
|
fullWalletAddr, err := full.WalletDefaultAddress(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Check the full node's wallet balance from the lite node
|
||||||
|
balance, err := lite.WalletBalance(ctx, fullWalletAddr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
fmt.Println(balance)
|
||||||
|
|
||||||
|
// Create a wallet on the lite node
|
||||||
|
liteWalletAddr, err := lite.WalletNew(ctx, types.KTSecp256k1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Send some funds from the full node to the lite node
|
||||||
|
err = sendFunds(ctx, t, full, fullWalletAddr, liteWalletAddr, types.NewInt(1e18))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Send some funds from the lite node back to the full node
|
||||||
|
err = sendFunds(ctx, t, lite, liteWalletAddr, fullWalletAddr, types.NewInt(100))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Sign some data with the lite node wallet address
|
||||||
|
data := []byte("hello")
|
||||||
|
sig, err := lite.WalletSign(ctx, liteWalletAddr, data)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Verify the signature
|
||||||
|
ok, err := lite.WalletVerify(ctx, liteWalletAddr, data, sig)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
|
// Create some wallets on the lite node to use for testing multisig
|
||||||
|
var walletAddrs []address.Address
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
addr, err := lite.WalletNew(ctx, types.KTSecp256k1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
walletAddrs = append(walletAddrs, addr)
|
||||||
|
|
||||||
|
err = sendFunds(ctx, t, lite, liteWalletAddr, addr, types.NewInt(1e15))
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an msig with three of the addresses and threshold of two sigs
|
||||||
|
msigAddrs := walletAddrs[:3]
|
||||||
|
amt := types.NewInt(1000)
|
||||||
|
addProposal, err := lite.MsigCreate(ctx, 2, msigAddrs, abi.ChainEpoch(50), amt, liteWalletAddr, types.NewInt(0))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
res, err := lite.StateWaitMsg(ctx, addProposal, 1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, 0, res.Receipt.ExitCode)
|
||||||
|
|
||||||
|
var execReturn init0.ExecReturn
|
||||||
|
err = execReturn.UnmarshalCBOR(bytes.NewReader(res.Receipt.Return))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Get available balance of msig: should be greater than zero and less
|
||||||
|
// than initial amount
|
||||||
|
msig := execReturn.IDAddress
|
||||||
|
msigBalance, err := lite.MsigGetAvailableBalance(ctx, msig, types.EmptyTSK)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Greater(t, msigBalance.Int64(), int64(0))
|
||||||
|
require.Less(t, msigBalance.Int64(), amt.Int64())
|
||||||
|
|
||||||
|
// Propose to add a new address to the msig
|
||||||
|
addProposal, err = lite.MsigAddPropose(ctx, msig, walletAddrs[0], walletAddrs[3], false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
res, err = lite.StateWaitMsg(ctx, addProposal, 1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, 0, res.Receipt.ExitCode)
|
||||||
|
|
||||||
|
var proposeReturn multisig.ProposeReturn
|
||||||
|
err = proposeReturn.UnmarshalCBOR(bytes.NewReader(res.Receipt.Return))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Approve proposal (proposer is first (implicit) signer, approver is
|
||||||
|
// second signer
|
||||||
|
txnID := uint64(proposeReturn.TxnID)
|
||||||
|
approval1, err := lite.MsigAddApprove(ctx, msig, walletAddrs[1], txnID, walletAddrs[0], walletAddrs[3], false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
res, err = lite.StateWaitMsg(ctx, approval1, 1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, 0, res.Receipt.ExitCode)
|
||||||
|
|
||||||
|
var approveReturn multisig.ApproveReturn
|
||||||
|
err = approveReturn.UnmarshalCBOR(bytes.NewReader(res.Receipt.Return))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, approveReturn.Applied)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendFunds(ctx context.Context, t *testing.T, fromNode test.TestNode, fromAddr address.Address, toAddr address.Address, amt types.BigInt) error {
|
||||||
|
msg := &types.Message{
|
||||||
|
From: fromAddr,
|
||||||
|
To: toAddr,
|
||||||
|
Value: amt,
|
||||||
|
}
|
||||||
|
|
||||||
|
sm, err := fromNode.MpoolPushMessage(ctx, msg, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := fromNode.StateWaitMsg(ctx, sm.Cid(), 1)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if res.Receipt.ExitCode != 0 {
|
||||||
|
return xerrors.Errorf("send funds failed with exit code %d", res.Receipt.ExitCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func startNodes(ctx context.Context, t *testing.T, blocktime time.Duration) (test.TestNode, test.TestNode, jsonrpc.ClientCloser) {
|
||||||
|
var closer jsonrpc.ClientCloser
|
||||||
|
|
||||||
|
// Create one miner and two full nodes.
|
||||||
|
// - Put a gateway server in front of full node 1
|
||||||
|
// - Start full node 2 in lite mode
|
||||||
|
// - Connect lite node -> gateway server -> full node
|
||||||
|
opts := append(
|
||||||
|
// Full node
|
||||||
|
test.OneFull,
|
||||||
|
// Lite node
|
||||||
|
test.FullNodeOpts{
|
||||||
|
Lite: true,
|
||||||
|
Opts: func(nodes []test.TestNode) node.Option {
|
||||||
|
fullNode := nodes[0]
|
||||||
|
|
||||||
|
// Create a gateway server in front of the full node
|
||||||
|
_, addr, err := builder.CreateRPCServer(&GatewayAPI{api: fullNode})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Create a gateway client API that connects to the gateway server
|
||||||
|
var gapi api.GatewayAPI
|
||||||
|
gapi, closer, err = client.NewGatewayRPC(ctx, addr, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Provide the gateway API to dependency injection
|
||||||
|
return node.Override(new(api.GatewayAPI), gapi)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
n, sn := builder.RPCMockSbBuilder(t, opts, test.OneMiner)
|
||||||
|
|
||||||
|
full := n[0]
|
||||||
|
lite := n[1]
|
||||||
|
miner := sn[0]
|
||||||
|
|
||||||
|
// Get the listener address for the full node
|
||||||
|
fullAddr, err := full.NetAddrsListen(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Connect the miner and the full node
|
||||||
|
err = miner.NetConnect(ctx, fullAddr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Start mining blocks
|
||||||
|
bm := test.NewBlockMiner(ctx, t, miner, blocktime)
|
||||||
|
bm.MineBlocks()
|
||||||
|
|
||||||
|
return full, lite, closer
|
||||||
|
}
|
@ -5,7 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/wallet"
|
"github.com/filecoin-project/lotus/chain/wallet"
|
||||||
_ "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"
|
||||||
@ -30,22 +30,22 @@ func main() {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var kt crypto.SigType
|
var kt types.KeyType
|
||||||
switch cctx.String("type") {
|
switch cctx.String("type") {
|
||||||
case "bls":
|
case "bls":
|
||||||
kt = crypto.SigTypeBLS
|
kt = types.KTBLS
|
||||||
case "secp256k1":
|
case "secp256k1":
|
||||||
kt = crypto.SigTypeSecp256k1
|
kt = types.KTSecp256k1
|
||||||
default:
|
default:
|
||||||
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
|
||||||
}
|
}
|
||||||
|
@ -396,13 +396,13 @@ var runCmd = &cli.Command{
|
|||||||
Name: "pre-fee-cap-max",
|
Name: "pre-fee-cap-max",
|
||||||
EnvVars: []string{"LOTUS_PCR_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",
|
Usage: "messages with a fee cap larger than this will be skipped when processing pre commit messages",
|
||||||
Value: "0.0000000001",
|
Value: "0.000000001",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "prove-fee-cap-max",
|
Name: "prove-fee-cap-max",
|
||||||
EnvVars: []string{"LOTUS_PCR_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",
|
Usage: "messages with a prove cap larger than this will be skipped when processing pre commit messages",
|
||||||
Value: "0.0000000001",
|
Value: "0.000000001",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
@ -884,6 +884,8 @@ func (r *refunder) processTipsetStorageMarketActor(ctx context.Context, tipset *
|
|||||||
}
|
}
|
||||||
|
|
||||||
refundValue = types.BigMul(types.NewInt(uint64(recp.GasUsed)), tipset.Blocks()[0].ParentBaseFee)
|
refundValue = types.BigMul(types.NewInt(uint64(recp.GasUsed)), tipset.Blocks()[0].ParentBaseFee)
|
||||||
|
default:
|
||||||
|
return false, messageMethod, types.NewInt(0), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, messageMethod, refundValue, nil
|
return true, messageMethod, refundValue, nil
|
||||||
|
@ -21,7 +21,6 @@ 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/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
|
||||||
"github.com/filecoin-project/lotus/extern/sector-storage/zerocomm"
|
"github.com/filecoin-project/lotus/extern/sector-storage/zerocomm"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||||
|
|
||||||
@ -94,7 +93,7 @@ func PreSeal(maddr address.Address, spt abi.RegisteredSealProof, offset abi.Sect
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
minerAddr, err = wallet.GenerateKey(crypto.SigTypeBLS)
|
minerAddr, err = wallet.GenerateKey(types.KTBLS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
@ -338,7 +372,7 @@ var chainPledgeCmd = &cli.Command{
|
|||||||
pledgeCollateral = c
|
pledgeCollateral = c
|
||||||
}
|
}
|
||||||
|
|
||||||
circ, err := sm.GetCirculatingSupplyDetailed(ctx, abi.ChainEpoch(epoch), state)
|
circ, err := sm.GetVMCirculatingSupplyDetailed(ctx, abi.ChainEpoch(epoch), state)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -32,10 +32,10 @@ import (
|
|||||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||||
)
|
)
|
||||||
|
|
||||||
var validTypes = []string{wallet.KTBLS, wallet.KTSecp256k1, lp2p.KTLibp2pHost}
|
var validTypes = []types.KeyType{types.KTBLS, types.KTSecp256k1, lp2p.KTLibp2pHost}
|
||||||
|
|
||||||
type keyInfoOutput struct {
|
type keyInfoOutput struct {
|
||||||
Type string
|
Type types.KeyType
|
||||||
Address string
|
Address string
|
||||||
PublicKey string
|
PublicKey string
|
||||||
}
|
}
|
||||||
@ -86,7 +86,7 @@ var keyinfoVerifyCmd = &cli.Command{
|
|||||||
return xerrors.Errorf("decoding key: '%s': %w", fileName, err)
|
return xerrors.Errorf("decoding key: '%s': %w", fileName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if string(name) != keyInfo.Type {
|
if types.KeyType(name) != keyInfo.Type {
|
||||||
return fmt.Errorf("%s of type %s is incorrect", fileName, keyInfo.Type)
|
return fmt.Errorf("%s of type %s is incorrect", fileName, keyInfo.Type)
|
||||||
}
|
}
|
||||||
case modules.KTJwtHmacSecret:
|
case modules.KTJwtHmacSecret:
|
||||||
@ -98,14 +98,14 @@ var keyinfoVerifyCmd = &cli.Command{
|
|||||||
if string(name) != modules.JWTSecretName {
|
if string(name) != modules.JWTSecretName {
|
||||||
return fmt.Errorf("%s of type %s is incorrect", fileName, keyInfo.Type)
|
return fmt.Errorf("%s of type %s is incorrect", fileName, keyInfo.Type)
|
||||||
}
|
}
|
||||||
case wallet.KTSecp256k1, wallet.KTBLS:
|
case types.KTSecp256k1, types.KTBLS:
|
||||||
keystore := wallet.NewMemKeyStore()
|
keystore := wallet.NewMemKeyStore()
|
||||||
w, err := wallet.NewWallet(keystore)
|
w, err := wallet.NewWallet(keystore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := w.Import(&keyInfo); err != nil {
|
if _, err := w.WalletImport(cctx.Context, &keyInfo); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,13 +214,13 @@ var keyinfoImportCmd = &cli.Command{
|
|||||||
fmt.Printf("%s\n", peerid.String())
|
fmt.Printf("%s\n", peerid.String())
|
||||||
|
|
||||||
break
|
break
|
||||||
case wallet.KTSecp256k1, wallet.KTBLS:
|
case types.KTSecp256k1, types.KTBLS:
|
||||||
w, err := wallet.NewWallet(keystore)
|
w, err := wallet.NewWallet(keystore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
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
|
||||||
}
|
}
|
||||||
@ -317,7 +317,7 @@ var keyinfoInfoCmd = &cli.Command{
|
|||||||
kio.PublicKey = base64.StdEncoding.EncodeToString(pkBytes)
|
kio.PublicKey = base64.StdEncoding.EncodeToString(pkBytes)
|
||||||
|
|
||||||
break
|
break
|
||||||
case wallet.KTSecp256k1, wallet.KTBLS:
|
case types.KTSecp256k1, types.KTBLS:
|
||||||
kio.Type = keyInfo.Type
|
kio.Type = keyInfo.Type
|
||||||
|
|
||||||
key, err := wallet.NewKey(keyInfo)
|
key, err := wallet.NewKey(keyInfo)
|
||||||
@ -366,7 +366,7 @@ var keyinfoNewCmd = &cli.Command{
|
|||||||
return fmt.Errorf("please specify a type to generate")
|
return fmt.Errorf("please specify a type to generate")
|
||||||
}
|
}
|
||||||
|
|
||||||
keyType := cctx.Args().First()
|
keyType := types.KeyType(cctx.Args().First())
|
||||||
flagOutput := cctx.String("output")
|
flagOutput := cctx.String("output")
|
||||||
|
|
||||||
if i := SliceIndex(len(validTypes), func(i int) bool {
|
if i := SliceIndex(len(validTypes), func(i int) bool {
|
||||||
@ -404,8 +404,8 @@ var keyinfoNewCmd = &cli.Command{
|
|||||||
keyInfo = ki
|
keyInfo = ki
|
||||||
|
|
||||||
break
|
break
|
||||||
case wallet.KTSecp256k1, wallet.KTBLS:
|
case types.KTSecp256k1, types.KTBLS:
|
||||||
key, err := wallet.GenerateKey(wallet.ActSigType(keyType))
|
key, err := wallet.GenerateKey(keyType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -418,7 +418,7 @@ var keyinfoNewCmd = &cli.Command{
|
|||||||
|
|
||||||
filename := flagOutput
|
filename := flagOutput
|
||||||
filename = strings.ReplaceAll(filename, "<addr>", keyAddr)
|
filename = strings.ReplaceAll(filename, "<addr>", keyAddr)
|
||||||
filename = strings.ReplaceAll(filename, "<type>", keyType)
|
filename = strings.ReplaceAll(filename, "<type>", string(keyType))
|
||||||
|
|
||||||
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
|
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
248
cmd/lotus-shed/ledger.go
Normal file
248
cmd/lotus-shed/ledger.go
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
ledgerfil "github.com/whyrusleeping/ledger-filecoin-go"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
ledgerwallet "github.com/filecoin-project/lotus/chain/wallet/ledger"
|
||||||
|
lcli "github.com/filecoin-project/lotus/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ledgerCmd = &cli.Command{
|
||||||
|
Name: "ledger",
|
||||||
|
Usage: "Ledger interactions",
|
||||||
|
Flags: []cli.Flag{},
|
||||||
|
Subcommands: []*cli.Command{
|
||||||
|
ledgerListAddressesCmd,
|
||||||
|
ledgerKeyInfoCmd,
|
||||||
|
ledgerSignTestCmd,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const hdHard = 0x80000000
|
||||||
|
|
||||||
|
var ledgerListAddressesCmd = &cli.Command{
|
||||||
|
Name: "list",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "print-balances",
|
||||||
|
Usage: "print balances",
|
||||||
|
Aliases: []string{"b"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
var api api.FullNode
|
||||||
|
if cctx.Bool("print-balances") {
|
||||||
|
a, closer, err := lcli.GetFullNodeAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
api = a
|
||||||
|
|
||||||
|
defer closer()
|
||||||
|
}
|
||||||
|
ctx := lcli.ReqContext(cctx)
|
||||||
|
|
||||||
|
fl, err := ledgerfil.FindLedgerFilecoinApp()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
end := 20
|
||||||
|
for i := 0; i < end; i++ {
|
||||||
|
if err := ctx.Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
p := []uint32{hdHard | 44, hdHard | 461, hdHard, 0, uint32(i)}
|
||||||
|
pubk, err := fl.GetPublicKeySECP256K1(p)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := address.NewSecp256k1Address(pubk)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if cctx.Bool("print-balances") && api != nil { // api check makes linter happier
|
||||||
|
b, err := api.WalletBalance(ctx, addr)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getting balance: %w", err)
|
||||||
|
}
|
||||||
|
if !b.IsZero() {
|
||||||
|
end = i + 21 // BIP32 spec, stop after 20 empty addresses
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%s %s %s\n", addr, printHDPath(p), types.FIL(b))
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%s %s\n", addr, printHDPath(p))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseHDPath(s string) ([]uint32, error) {
|
||||||
|
parts := strings.Split(s, "/")
|
||||||
|
if parts[0] != "m" {
|
||||||
|
return nil, fmt.Errorf("expected HD path to start with 'm'")
|
||||||
|
}
|
||||||
|
|
||||||
|
var out []uint32
|
||||||
|
for _, p := range parts[1:] {
|
||||||
|
var hard bool
|
||||||
|
if strings.HasSuffix(p, "'") {
|
||||||
|
p = p[:len(p)-1]
|
||||||
|
hard = true
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := strconv.ParseUint(p, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if v >= hdHard {
|
||||||
|
return nil, fmt.Errorf("path element %s too large", p)
|
||||||
|
}
|
||||||
|
|
||||||
|
if hard {
|
||||||
|
v += hdHard
|
||||||
|
}
|
||||||
|
out = append(out, uint32(v))
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func printHDPath(pth []uint32) string {
|
||||||
|
s := "m"
|
||||||
|
for _, p := range pth {
|
||||||
|
s += "/"
|
||||||
|
|
||||||
|
hard := p&hdHard != 0
|
||||||
|
p &^= hdHard // remove hdHard bit
|
||||||
|
|
||||||
|
s += fmt.Sprint(p)
|
||||||
|
if hard {
|
||||||
|
s += "'"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
var ledgerKeyInfoCmd = &cli.Command{
|
||||||
|
Name: "key-info",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "verbose",
|
||||||
|
Aliases: []string{"v"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
if !cctx.Args().Present() {
|
||||||
|
return cli.ShowCommandHelp(cctx, cctx.Command.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fl, err := ledgerfil.FindLedgerFilecoinApp()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
p, err := parseHDPath(cctx.Args().First())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pubk, _, addr, err := fl.GetAddressPubKeySECP256K1(p)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if cctx.Bool("verbose") {
|
||||||
|
fmt.Println(addr)
|
||||||
|
fmt.Println(pubk)
|
||||||
|
}
|
||||||
|
|
||||||
|
a, err := address.NewFromString(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var pd ledgerwallet.LedgerKeyInfo
|
||||||
|
pd.Address = a
|
||||||
|
pd.Path = p
|
||||||
|
|
||||||
|
b, err := json.Marshal(pd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ki types.KeyInfo
|
||||||
|
ki.Type = types.KTSecp256k1Ledger
|
||||||
|
ki.PrivateKey = b
|
||||||
|
|
||||||
|
out, err := json.Marshal(ki)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(out))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var ledgerSignTestCmd = &cli.Command{
|
||||||
|
Name: "sign",
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
if !cctx.Args().Present() {
|
||||||
|
return cli.ShowCommandHelp(cctx, cctx.Command.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fl, err := ledgerfil.FindLedgerFilecoinApp()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
p, err := parseHDPath(cctx.Args().First())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := address.NewFromString("f1xc3hws5n6y5m3m44gzb3gyjzhups6wzmhe663ji")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
m := &types.Message{
|
||||||
|
To: addr,
|
||||||
|
From: addr,
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := m.ToStorageBlock()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sig, err := fl.SignSECP256K1(p, b.RawData())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(sig.SignatureBytes())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
@ -41,6 +41,7 @@ func main() {
|
|||||||
syncCmd,
|
syncCmd,
|
||||||
stateTreePruneCmd,
|
stateTreePruneCmd,
|
||||||
datastoreCmd,
|
datastoreCmd,
|
||||||
|
ledgerCmd,
|
||||||
}
|
}
|
||||||
|
|
||||||
app := &cli.App{
|
app := &cli.App{
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user