Merge branch 'master' into inmem-journal
This commit is contained in:
commit
1ec534d607
@ -1,3 +1,5 @@
|
|||||||
comment: off
|
comment: off
|
||||||
ignore:
|
ignore:
|
||||||
- "cbor_gen.go"
|
- "cbor_gen.go"
|
||||||
|
github_checks:
|
||||||
|
annotations: false
|
||||||
|
40
CHANGELOG.md
40
CHANGELOG.md
@ -1,5 +1,45 @@
|
|||||||
# Lotus changelog
|
# Lotus changelog
|
||||||
|
|
||||||
|
# 0.5.10 / 2020-09-03
|
||||||
|
|
||||||
|
This patch includes a crucial fix to the message pool selection logic, strongly disfavouring messages that might cause a miner penalty.
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
- Fix calculation of GasReward in messagepool (https://github.com/filecoin-project/lotus/pull/3528)
|
||||||
|
|
||||||
|
# 0.5.9 / 2020-09-03
|
||||||
|
|
||||||
|
This patch includes a hotfix to the `GasEstimateFeeCap` method, capping the estimated fee to a reasonable level by default.
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
- Added target height to sync wait (https://github.com/filecoin-project/lotus/pull/3502)
|
||||||
|
- Disable codecov annotations (https://github.com/filecoin-project/lotus/pull/3514)
|
||||||
|
- Cap fees to reasonable level by default (https://github.com/filecoin-project/lotus/pull/3516)
|
||||||
|
- Add APIs and command to inspect bandwidth usage (https://github.com/filecoin-project/lotus/pull/3497)
|
||||||
|
- Track expected nonce in mpool, ignore messages with large nonce gaps (https://github.com/filecoin-project/lotus/pull/3450)
|
||||||
|
|
||||||
|
# 0.5.8 / 2020-09-02
|
||||||
|
|
||||||
|
This patch includes some bugfixes to the sector sealing process, and updates go-fil-markets. It also improves the performance of blocksync, adds a method to export chain state trees, and improves chainwatch.
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
- Upgrade markets to v0.5.9 (https://github.com/filecoin-project/lotus/pull/3496)
|
||||||
|
- Improve blocksync to load fewer messages: (https://github.com/filecoin-project/lotus/pull/3494)
|
||||||
|
- Fix a panic in the ffi-wrapper's `ReadPiece` (https://github.com/filecoin-project/lotus/pull/3492/files)
|
||||||
|
- Fix a deadlock in the sealing scheduler (https://github.com/filecoin-project/lotus/pull/3489)
|
||||||
|
- Add test vectors for tipset tests (https://github.com/filecoin-project/lotus/pull/3485/files)
|
||||||
|
- Improve the advance-block debug command (https://github.com/filecoin-project/lotus/pull/3476)
|
||||||
|
- Add toggle for message processing to Lotus PCR (https://github.com/filecoin-project/lotus/pull/3470)
|
||||||
|
- Allow exporting recent chain state trees (https://github.com/filecoin-project/lotus/pull/3463)
|
||||||
|
- Remove height from chain rand (https://github.com/filecoin-project/lotus/pull/3458)
|
||||||
|
- Disable GC on chain badger datastore (https://github.com/filecoin-project/lotus/pull/3457)
|
||||||
|
- Account for `GasPremium` in `GasEstimateFeeCap` (https://github.com/filecoin-project/lotus/pull/3456)
|
||||||
|
- Update go-libp2p-pubsub to `master` (https://github.com/filecoin-project/lotus/pull/3455)
|
||||||
|
- Chainwatch improvements (https://github.com/filecoin-project/lotus/pull/3442)
|
||||||
|
|
||||||
# 0.5.7 / 2020-08-31
|
# 0.5.7 / 2020-08-31
|
||||||
|
|
||||||
This patch release includes some bugfixes and enhancements to the sector lifecycle and message pool logic.
|
This patch release includes some bugfixes and enhancements to the sector lifecycle and message pool logic.
|
||||||
|
@ -5,8 +5,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-jsonrpc/auth"
|
"github.com/filecoin-project/go-jsonrpc/auth"
|
||||||
|
metrics "github.com/libp2p/go-libp2p-core/metrics"
|
||||||
"github.com/libp2p/go-libp2p-core/network"
|
"github.com/libp2p/go-libp2p-core/network"
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
protocol "github.com/libp2p/go-libp2p-core/protocol"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
)
|
)
|
||||||
@ -28,6 +30,19 @@ type Common interface {
|
|||||||
NetFindPeer(context.Context, peer.ID) (peer.AddrInfo, error)
|
NetFindPeer(context.Context, peer.ID) (peer.AddrInfo, error)
|
||||||
NetPubsubScores(context.Context) ([]PubsubScore, error)
|
NetPubsubScores(context.Context) ([]PubsubScore, error)
|
||||||
NetAutoNatStatus(context.Context) (NatInfo, error)
|
NetAutoNatStatus(context.Context) (NatInfo, error)
|
||||||
|
NetAgentVersion(ctx context.Context, p peer.ID) (string, error)
|
||||||
|
|
||||||
|
// NetBandwidthStats returns statistics about the nodes total bandwidth
|
||||||
|
// usage and current rate across all peers and protocols.
|
||||||
|
NetBandwidthStats(ctx context.Context) (metrics.Stats, error)
|
||||||
|
|
||||||
|
// NetBandwidthStatsByPeer returns statistics about the nodes bandwidth
|
||||||
|
// usage and current rate per peer
|
||||||
|
NetBandwidthStatsByPeer(ctx context.Context) (map[string]metrics.Stats, error)
|
||||||
|
|
||||||
|
// NetBandwidthStatsByProtocol returns statistics about the nodes bandwidth
|
||||||
|
// usage and current rate per protocol
|
||||||
|
NetBandwidthStatsByProtocol(ctx context.Context) (map[protocol.ID]metrics.Stats, error)
|
||||||
|
|
||||||
// MethodGroup: Common
|
// MethodGroup: Common
|
||||||
|
|
||||||
|
@ -421,6 +421,7 @@ type FullNode interface {
|
|||||||
|
|
||||||
PaychGet(ctx context.Context, from, to address.Address, amt types.BigInt) (*ChannelInfo, error)
|
PaychGet(ctx context.Context, from, to address.Address, amt types.BigInt) (*ChannelInfo, error)
|
||||||
PaychGetWaitReady(context.Context, cid.Cid) (address.Address, error)
|
PaychGetWaitReady(context.Context, cid.Cid) (address.Address, error)
|
||||||
|
PaychAvailableFunds(from, to address.Address) (*ChannelAvailableFunds, error)
|
||||||
PaychList(context.Context) ([]address.Address, error)
|
PaychList(context.Context) ([]address.Address, error)
|
||||||
PaychStatus(context.Context, address.Address) (*PaychStatus, error)
|
PaychStatus(context.Context, address.Address) (*PaychStatus, error)
|
||||||
PaychSettle(context.Context, address.Address) (cid.Cid, error)
|
PaychSettle(context.Context, address.Address) (cid.Cid, error)
|
||||||
@ -429,7 +430,7 @@ type FullNode interface {
|
|||||||
PaychNewPayment(ctx context.Context, from, to address.Address, vouchers []VoucherSpec) (*PaymentInfo, error)
|
PaychNewPayment(ctx context.Context, from, to address.Address, vouchers []VoucherSpec) (*PaymentInfo, error)
|
||||||
PaychVoucherCheckValid(context.Context, address.Address, *paych.SignedVoucher) error
|
PaychVoucherCheckValid(context.Context, address.Address, *paych.SignedVoucher) error
|
||||||
PaychVoucherCheckSpendable(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (bool, error)
|
PaychVoucherCheckSpendable(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (bool, error)
|
||||||
PaychVoucherCreate(context.Context, address.Address, types.BigInt, uint64) (*paych.SignedVoucher, error)
|
PaychVoucherCreate(context.Context, address.Address, types.BigInt, uint64) (*VoucherCreateResult, error)
|
||||||
PaychVoucherAdd(context.Context, address.Address, *paych.SignedVoucher, []byte, types.BigInt) (types.BigInt, error)
|
PaychVoucherAdd(context.Context, address.Address, *paych.SignedVoucher, []byte, types.BigInt) (types.BigInt, error)
|
||||||
PaychVoucherList(context.Context, address.Address) ([]*paych.SignedVoucher, error)
|
PaychVoucherList(context.Context, address.Address) ([]*paych.SignedVoucher, error)
|
||||||
PaychVoucherSubmit(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error)
|
PaychVoucherSubmit(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error)
|
||||||
@ -538,6 +539,23 @@ type ChannelInfo struct {
|
|||||||
WaitSentinel cid.Cid
|
WaitSentinel cid.Cid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ChannelAvailableFunds struct {
|
||||||
|
Channel *address.Address
|
||||||
|
// ConfirmedAmt is the amount of funds that have been confirmed on-chain
|
||||||
|
// for the channel
|
||||||
|
ConfirmedAmt types.BigInt
|
||||||
|
// PendingAmt is the amount of funds that are pending confirmation on-chain
|
||||||
|
PendingAmt types.BigInt
|
||||||
|
// PendingWaitSentinel can be used with PaychGetWaitReady to wait for
|
||||||
|
// confirmation of pending funds
|
||||||
|
PendingWaitSentinel *cid.Cid
|
||||||
|
// QueuedAmt is the amount that is queued up behind a pending request
|
||||||
|
QueuedAmt types.BigInt
|
||||||
|
// VoucherRedeemedAmt is the amount that is redeemed by vouchers on-chain
|
||||||
|
// and in the local datastore
|
||||||
|
VoucherReedeemedAmt types.BigInt
|
||||||
|
}
|
||||||
|
|
||||||
type PaymentInfo struct {
|
type PaymentInfo struct {
|
||||||
Channel address.Address
|
Channel address.Address
|
||||||
WaitSentinel cid.Cid
|
WaitSentinel cid.Cid
|
||||||
@ -553,6 +571,16 @@ type VoucherSpec struct {
|
|||||||
Extra *paych.ModVerifyParams
|
Extra *paych.ModVerifyParams
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VoucherCreateResult is the response to calling PaychVoucherCreate
|
||||||
|
type VoucherCreateResult struct {
|
||||||
|
// Voucher that was created, or nil if there was an error or if there
|
||||||
|
// were insufficient funds in the channel
|
||||||
|
Voucher *paych.SignedVoucher
|
||||||
|
// Shortfall is the additional amount that would be needed in the channel
|
||||||
|
// in order to be able to create the voucher
|
||||||
|
Shortfall types.BigInt
|
||||||
|
}
|
||||||
|
|
||||||
type MinerPower struct {
|
type MinerPower struct {
|
||||||
MinerPower power.Claim
|
MinerPower power.Claim
|
||||||
TotalPower power.Claim
|
TotalPower power.Claim
|
||||||
|
@ -73,7 +73,7 @@ type StorageMiner interface {
|
|||||||
MarketImportDealData(ctx context.Context, propcid cid.Cid, path string) error
|
MarketImportDealData(ctx context.Context, propcid cid.Cid, path string) error
|
||||||
MarketListDeals(ctx context.Context) ([]storagemarket.StorageDeal, error)
|
MarketListDeals(ctx context.Context) ([]storagemarket.StorageDeal, error)
|
||||||
MarketListRetrievalDeals(ctx context.Context) ([]retrievalmarket.ProviderDealState, error)
|
MarketListRetrievalDeals(ctx context.Context) ([]retrievalmarket.ProviderDealState, error)
|
||||||
MarketGetDealUpdates(ctx context.Context, d cid.Cid) (<-chan storagemarket.MinerDeal, error)
|
MarketGetDealUpdates(ctx context.Context) (<-chan storagemarket.MinerDeal, error)
|
||||||
MarketListIncompleteDeals(ctx context.Context) ([]storagemarket.MinerDeal, error)
|
MarketListIncompleteDeals(ctx context.Context) ([]storagemarket.MinerDeal, error)
|
||||||
MarketSetAsk(ctx context.Context, price types.BigInt, verifiedPrice types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error
|
MarketSetAsk(ctx context.Context, price types.BigInt, verifiedPrice types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error
|
||||||
MarketGetAsk(ctx context.Context) (*storagemarket.SignedStorageAsk, error)
|
MarketGetAsk(ctx context.Context) (*storagemarket.SignedStorageAsk, error)
|
||||||
|
@ -6,8 +6,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
|
metrics "github.com/libp2p/go-libp2p-core/metrics"
|
||||||
"github.com/libp2p/go-libp2p-core/network"
|
"github.com/libp2p/go-libp2p-core/network"
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
protocol "github.com/libp2p/go-libp2p-core/protocol"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-fil-markets/piecestore"
|
"github.com/filecoin-project/go-fil-markets/piecestore"
|
||||||
@ -42,14 +44,18 @@ type CommonStruct struct {
|
|||||||
AuthVerify func(ctx context.Context, token string) ([]auth.Permission, error) `perm:"read"`
|
AuthVerify func(ctx context.Context, token string) ([]auth.Permission, error) `perm:"read"`
|
||||||
AuthNew func(ctx context.Context, perms []auth.Permission) ([]byte, error) `perm:"admin"`
|
AuthNew func(ctx context.Context, perms []auth.Permission) ([]byte, error) `perm:"admin"`
|
||||||
|
|
||||||
NetConnectedness func(context.Context, peer.ID) (network.Connectedness, error) `perm:"read"`
|
NetConnectedness func(context.Context, peer.ID) (network.Connectedness, error) `perm:"read"`
|
||||||
NetPeers func(context.Context) ([]peer.AddrInfo, error) `perm:"read"`
|
NetPeers func(context.Context) ([]peer.AddrInfo, error) `perm:"read"`
|
||||||
NetConnect func(context.Context, peer.AddrInfo) error `perm:"write"`
|
NetConnect func(context.Context, peer.AddrInfo) error `perm:"write"`
|
||||||
NetAddrsListen func(context.Context) (peer.AddrInfo, error) `perm:"read"`
|
NetAddrsListen func(context.Context) (peer.AddrInfo, error) `perm:"read"`
|
||||||
NetDisconnect func(context.Context, peer.ID) error `perm:"write"`
|
NetDisconnect func(context.Context, peer.ID) error `perm:"write"`
|
||||||
NetFindPeer func(context.Context, peer.ID) (peer.AddrInfo, error) `perm:"read"`
|
NetFindPeer func(context.Context, peer.ID) (peer.AddrInfo, error) `perm:"read"`
|
||||||
NetPubsubScores func(context.Context) ([]api.PubsubScore, error) `perm:"read"`
|
NetPubsubScores func(context.Context) ([]api.PubsubScore, error) `perm:"read"`
|
||||||
NetAutoNatStatus func(context.Context) (api.NatInfo, error) `perm:"read"`
|
NetAutoNatStatus func(context.Context) (api.NatInfo, error) `perm:"read"`
|
||||||
|
NetBandwidthStats func(ctx context.Context) (metrics.Stats, error) `perm:"read"`
|
||||||
|
NetBandwidthStatsByPeer func(ctx context.Context) (map[string]metrics.Stats, error) `perm:"read"`
|
||||||
|
NetBandwidthStatsByProtocol func(ctx context.Context) (map[protocol.ID]metrics.Stats, error) `perm:"read"`
|
||||||
|
NetAgentVersion func(ctx context.Context, p peer.ID) (string, error) `perm:"read"`
|
||||||
|
|
||||||
ID func(context.Context) (peer.ID, error) `perm:"read"`
|
ID func(context.Context) (peer.ID, error) `perm:"read"`
|
||||||
Version func(context.Context) (api.Version, error) `perm:"read"`
|
Version func(context.Context) (api.Version, error) `perm:"read"`
|
||||||
@ -203,6 +209,7 @@ type FullNodeStruct struct {
|
|||||||
|
|
||||||
PaychGet func(ctx context.Context, from, to address.Address, amt types.BigInt) (*api.ChannelInfo, error) `perm:"sign"`
|
PaychGet func(ctx context.Context, from, to address.Address, amt types.BigInt) (*api.ChannelInfo, error) `perm:"sign"`
|
||||||
PaychGetWaitReady func(context.Context, cid.Cid) (address.Address, error) `perm:"sign"`
|
PaychGetWaitReady func(context.Context, cid.Cid) (address.Address, error) `perm:"sign"`
|
||||||
|
PaychAvailableFunds func(address.Address, address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"`
|
||||||
PaychList func(context.Context) ([]address.Address, error) `perm:"read"`
|
PaychList func(context.Context) ([]address.Address, error) `perm:"read"`
|
||||||
PaychStatus func(context.Context, address.Address) (*api.PaychStatus, error) `perm:"read"`
|
PaychStatus func(context.Context, address.Address) (*api.PaychStatus, error) `perm:"read"`
|
||||||
PaychSettle func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"`
|
PaychSettle func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||||
@ -213,7 +220,7 @@ type FullNodeStruct struct {
|
|||||||
PaychVoucherCheckValid func(context.Context, address.Address, *paych.SignedVoucher) error `perm:"read"`
|
PaychVoucherCheckValid func(context.Context, address.Address, *paych.SignedVoucher) error `perm:"read"`
|
||||||
PaychVoucherCheckSpendable func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (bool, error) `perm:"read"`
|
PaychVoucherCheckSpendable func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (bool, error) `perm:"read"`
|
||||||
PaychVoucherAdd func(context.Context, address.Address, *paych.SignedVoucher, []byte, types.BigInt) (types.BigInt, error) `perm:"write"`
|
PaychVoucherAdd func(context.Context, address.Address, *paych.SignedVoucher, []byte, types.BigInt) (types.BigInt, error) `perm:"write"`
|
||||||
PaychVoucherCreate func(context.Context, address.Address, big.Int, uint64) (*paych.SignedVoucher, error) `perm:"sign"`
|
PaychVoucherCreate func(context.Context, address.Address, big.Int, uint64) (*api.VoucherCreateResult, error) `perm:"sign"`
|
||||||
PaychVoucherList func(context.Context, address.Address) ([]*paych.SignedVoucher, error) `perm:"write"`
|
PaychVoucherList func(context.Context, address.Address) ([]*paych.SignedVoucher, error) `perm:"write"`
|
||||||
PaychVoucherSubmit func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error) `perm:"sign"`
|
PaychVoucherSubmit func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error) `perm:"sign"`
|
||||||
}
|
}
|
||||||
@ -235,7 +242,7 @@ type StorageMinerStruct struct {
|
|||||||
MarketImportDealData func(context.Context, cid.Cid, string) error `perm:"write"`
|
MarketImportDealData func(context.Context, cid.Cid, string) error `perm:"write"`
|
||||||
MarketListDeals func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"`
|
MarketListDeals func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"`
|
||||||
MarketListRetrievalDeals func(ctx context.Context) ([]retrievalmarket.ProviderDealState, error) `perm:"read"`
|
MarketListRetrievalDeals func(ctx context.Context) ([]retrievalmarket.ProviderDealState, error) `perm:"read"`
|
||||||
MarketGetDealUpdates func(ctx context.Context, d cid.Cid) (<-chan storagemarket.MinerDeal, error) `perm:"read"`
|
MarketGetDealUpdates func(ctx context.Context) (<-chan storagemarket.MinerDeal, error) `perm:"read"`
|
||||||
MarketListIncompleteDeals func(ctx context.Context) ([]storagemarket.MinerDeal, error) `perm:"read"`
|
MarketListIncompleteDeals func(ctx context.Context) ([]storagemarket.MinerDeal, error) `perm:"read"`
|
||||||
MarketSetAsk func(ctx context.Context, price types.BigInt, verifiedPrice types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error `perm:"admin"`
|
MarketSetAsk func(ctx context.Context, price types.BigInt, verifiedPrice types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error `perm:"admin"`
|
||||||
MarketGetAsk func(ctx context.Context) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
|
MarketGetAsk func(ctx context.Context) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
|
||||||
@ -371,6 +378,22 @@ func (c *CommonStruct) NetAutoNatStatus(ctx context.Context) (api.NatInfo, error
|
|||||||
return c.Internal.NetAutoNatStatus(ctx)
|
return c.Internal.NetAutoNatStatus(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *CommonStruct) NetBandwidthStats(ctx context.Context) (metrics.Stats, error) {
|
||||||
|
return c.Internal.NetBandwidthStats(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommonStruct) NetBandwidthStatsByPeer(ctx context.Context) (map[string]metrics.Stats, error) {
|
||||||
|
return c.Internal.NetBandwidthStatsByPeer(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommonStruct) NetBandwidthStatsByProtocol(ctx context.Context) (map[protocol.ID]metrics.Stats, error) {
|
||||||
|
return c.Internal.NetBandwidthStatsByProtocol(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommonStruct) NetAgentVersion(ctx context.Context, p peer.ID) (string, error) {
|
||||||
|
return c.Internal.NetAgentVersion(ctx, p)
|
||||||
|
}
|
||||||
|
|
||||||
// ID implements API.ID
|
// ID implements API.ID
|
||||||
func (c *CommonStruct) ID(ctx context.Context) (peer.ID, error) {
|
func (c *CommonStruct) ID(ctx context.Context) (peer.ID, error) {
|
||||||
return c.Internal.ID(ctx)
|
return c.Internal.ID(ctx)
|
||||||
@ -882,6 +905,10 @@ func (c *FullNodeStruct) PaychGetWaitReady(ctx context.Context, sentinel cid.Cid
|
|||||||
return c.Internal.PaychGetWaitReady(ctx, sentinel)
|
return c.Internal.PaychGetWaitReady(ctx, sentinel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *FullNodeStruct) PaychAvailableFunds(from address.Address, to address.Address) (*api.ChannelAvailableFunds, error) {
|
||||||
|
return c.Internal.PaychAvailableFunds(from, to)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) PaychList(ctx context.Context) ([]address.Address, error) {
|
func (c *FullNodeStruct) PaychList(ctx context.Context) ([]address.Address, error) {
|
||||||
return c.Internal.PaychList(ctx)
|
return c.Internal.PaychList(ctx)
|
||||||
}
|
}
|
||||||
@ -902,7 +929,7 @@ func (c *FullNodeStruct) PaychVoucherAdd(ctx context.Context, addr address.Addre
|
|||||||
return c.Internal.PaychVoucherAdd(ctx, addr, sv, proof, minDelta)
|
return c.Internal.PaychVoucherAdd(ctx, addr, sv, proof, minDelta)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) PaychVoucherCreate(ctx context.Context, pch address.Address, amt types.BigInt, lane uint64) (*paych.SignedVoucher, error) {
|
func (c *FullNodeStruct) PaychVoucherCreate(ctx context.Context, pch address.Address, amt types.BigInt, lane uint64) (*api.VoucherCreateResult, error) {
|
||||||
return c.Internal.PaychVoucherCreate(ctx, pch, amt, lane)
|
return c.Internal.PaychVoucherCreate(ctx, pch, amt, lane)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1070,8 +1097,8 @@ func (c *StorageMinerStruct) MarketListRetrievalDeals(ctx context.Context) ([]re
|
|||||||
return c.Internal.MarketListRetrievalDeals(ctx)
|
return c.Internal.MarketListRetrievalDeals(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StorageMinerStruct) MarketGetDealUpdates(ctx context.Context, d cid.Cid) (<-chan storagemarket.MinerDeal, error) {
|
func (c *StorageMinerStruct) MarketGetDealUpdates(ctx context.Context) (<-chan storagemarket.MinerDeal, error) {
|
||||||
return c.Internal.MarketGetDealUpdates(ctx, d)
|
return c.Internal.MarketGetDealUpdates(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StorageMinerStruct) MarketListIncompleteDeals(ctx context.Context) ([]storagemarket.MinerDeal, error) {
|
func (c *StorageMinerStruct) MarketListIncompleteDeals(ctx context.Context) ([]storagemarket.MinerDeal, error) {
|
||||||
|
@ -14,8 +14,10 @@ import (
|
|||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/ipfs/go-filestore"
|
"github.com/ipfs/go-filestore"
|
||||||
|
metrics "github.com/libp2p/go-libp2p-core/metrics"
|
||||||
"github.com/libp2p/go-libp2p-core/network"
|
"github.com/libp2p/go-libp2p-core/network"
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
protocol "github.com/libp2p/go-libp2p-core/protocol"
|
||||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||||
"github.com/multiformats/go-multiaddr"
|
"github.com/multiformats/go-multiaddr"
|
||||||
|
|
||||||
@ -133,6 +135,22 @@ func init() {
|
|||||||
InvalidMessageDeliveries: 3,
|
InvalidMessageDeliveries: 3,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
addExample(map[string]metrics.Stats{
|
||||||
|
"12D3KooWSXmXLJmBR1M7i9RW9GQPNUhZSzXKzxDHWtAgNuJAbyEJ": {
|
||||||
|
RateIn: 100,
|
||||||
|
RateOut: 50,
|
||||||
|
TotalIn: 174000,
|
||||||
|
TotalOut: 12500,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
addExample(map[protocol.ID]metrics.Stats{
|
||||||
|
"/fil/hello/1.0.0": {
|
||||||
|
RateIn: 100,
|
||||||
|
RateOut: 50,
|
||||||
|
TotalIn: 174000,
|
||||||
|
TotalOut: 12500,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
maddr, err := multiaddr.NewMultiaddr("/ip4/52.36.61.156/tcp/1347/p2p/12D3KooWFETiESTf1v4PGUvtnxMAcEFMzLZbJGg4tjWfGEimYior")
|
maddr, err := multiaddr.NewMultiaddr("/ip4/52.36.61.156/tcp/1347/p2p/12D3KooWFETiESTf1v4PGUvtnxMAcEFMzLZbJGg4tjWfGEimYior")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -334,7 +334,7 @@ loop:
|
|||||||
func waitDealPublished(t *testing.T, ctx context.Context, miner TestStorageNode, deal *cid.Cid) {
|
func waitDealPublished(t *testing.T, ctx context.Context, miner TestStorageNode, deal *cid.Cid) {
|
||||||
subCtx, cancel := context.WithCancel(ctx)
|
subCtx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
updates, err := miner.MarketGetDealUpdates(subCtx, *deal)
|
updates, err := miner.MarketGetDealUpdates(subCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -343,18 +343,20 @@ func waitDealPublished(t *testing.T, ctx context.Context, miner TestStorageNode,
|
|||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
t.Fatal("context timeout")
|
t.Fatal("context timeout")
|
||||||
case di := <-updates:
|
case di := <-updates:
|
||||||
switch di.State {
|
if deal.Equals(di.ProposalCid) {
|
||||||
case storagemarket.StorageDealProposalRejected:
|
switch di.State {
|
||||||
t.Fatal("deal rejected")
|
case storagemarket.StorageDealProposalRejected:
|
||||||
case storagemarket.StorageDealFailing:
|
t.Fatal("deal rejected")
|
||||||
t.Fatal("deal failed")
|
case storagemarket.StorageDealFailing:
|
||||||
case storagemarket.StorageDealError:
|
t.Fatal("deal failed")
|
||||||
t.Fatal("deal errored", di.Message)
|
case storagemarket.StorageDealError:
|
||||||
case storagemarket.StorageDealFinalizing, storagemarket.StorageDealSealing, storagemarket.StorageDealActive:
|
t.Fatal("deal errored", di.Message)
|
||||||
fmt.Println("COMPLETE", di)
|
case storagemarket.StorageDealFinalizing, storagemarket.StorageDealSealing, storagemarket.StorageDealActive:
|
||||||
return
|
fmt.Println("COMPLETE", di)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println("Deal state: ", storagemarket.DealStates[di.State])
|
||||||
}
|
}
|
||||||
fmt.Println("Deal state: ", storagemarket.DealStates[di.State])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,18 +96,24 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
if vouch1.Voucher == nil {
|
||||||
|
t.Fatal(fmt.Errorf("Not enough funds to create voucher: missing %d", vouch1.Shortfall))
|
||||||
|
}
|
||||||
vouch2, err := paymentCreator.PaychVoucherCreate(ctx, channel, abi.NewTokenAmount(2000), lane)
|
vouch2, err := paymentCreator.PaychVoucherCreate(ctx, channel, abi.NewTokenAmount(2000), lane)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
delta1, err := paymentReceiver.PaychVoucherAdd(ctx, channel, vouch1, nil, abi.NewTokenAmount(1000))
|
if vouch2.Voucher == nil {
|
||||||
|
t.Fatal(fmt.Errorf("Not enough funds to create voucher: missing %d", vouch2.Shortfall))
|
||||||
|
}
|
||||||
|
delta1, err := paymentReceiver.PaychVoucherAdd(ctx, channel, vouch1.Voucher, nil, abi.NewTokenAmount(1000))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !delta1.Equals(abi.NewTokenAmount(1000)) {
|
if !delta1.Equals(abi.NewTokenAmount(1000)) {
|
||||||
t.Fatal("voucher didn't have the right amount")
|
t.Fatal("voucher didn't have the right amount")
|
||||||
}
|
}
|
||||||
delta2, err := paymentReceiver.PaychVoucherAdd(ctx, channel, vouch2, nil, abi.NewTokenAmount(1000))
|
delta2, err := paymentReceiver.PaychVoucherAdd(ctx, channel, vouch2.Voucher, nil, abi.NewTokenAmount(1000))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,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.5.7"
|
const BuildVersion = "0.5.10"
|
||||||
|
|
||||||
func UserVersion() string {
|
func UserVersion() string {
|
||||||
return BuildVersion + buildType() + CurrentCommit
|
return BuildVersion + buildType() + CurrentCommit
|
||||||
|
@ -221,37 +221,36 @@ func collectChainSegment(
|
|||||||
func gatherMessages(cs *store.ChainStore, ts *types.TipSet) ([]*types.Message, [][]uint64, []*types.SignedMessage, [][]uint64, error) {
|
func gatherMessages(cs *store.ChainStore, ts *types.TipSet) ([]*types.Message, [][]uint64, []*types.SignedMessage, [][]uint64, error) {
|
||||||
blsmsgmap := make(map[cid.Cid]uint64)
|
blsmsgmap := make(map[cid.Cid]uint64)
|
||||||
secpkmsgmap := make(map[cid.Cid]uint64)
|
secpkmsgmap := make(map[cid.Cid]uint64)
|
||||||
var secpkmsgs []*types.SignedMessage
|
|
||||||
var blsmsgs []*types.Message
|
|
||||||
var secpkincl, blsincl [][]uint64
|
var secpkincl, blsincl [][]uint64
|
||||||
|
|
||||||
|
var blscids, secpkcids []cid.Cid
|
||||||
for _, block := range ts.Blocks() {
|
for _, block := range ts.Blocks() {
|
||||||
bmsgs, smsgs, err := cs.MessagesForBlock(block)
|
bc, sc, err := cs.ReadMsgMetaCids(block.Messages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, nil, err
|
return nil, nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: DRY. Use `chain.Message` interface.
|
// FIXME: DRY. Use `chain.Message` interface.
|
||||||
bmi := make([]uint64, 0, len(bmsgs))
|
bmi := make([]uint64, 0, len(bc))
|
||||||
for _, m := range bmsgs {
|
for _, m := range bc {
|
||||||
i, ok := blsmsgmap[m.Cid()]
|
i, ok := blsmsgmap[m]
|
||||||
if !ok {
|
if !ok {
|
||||||
i = uint64(len(blsmsgs))
|
i = uint64(len(blscids))
|
||||||
blsmsgs = append(blsmsgs, m)
|
blscids = append(blscids, m)
|
||||||
blsmsgmap[m.Cid()] = i
|
blsmsgmap[m] = i
|
||||||
}
|
}
|
||||||
|
|
||||||
bmi = append(bmi, i)
|
bmi = append(bmi, i)
|
||||||
}
|
}
|
||||||
blsincl = append(blsincl, bmi)
|
blsincl = append(blsincl, bmi)
|
||||||
|
|
||||||
smi := make([]uint64, 0, len(smsgs))
|
smi := make([]uint64, 0, len(sc))
|
||||||
for _, m := range smsgs {
|
for _, m := range sc {
|
||||||
i, ok := secpkmsgmap[m.Cid()]
|
i, ok := secpkmsgmap[m]
|
||||||
if !ok {
|
if !ok {
|
||||||
i = uint64(len(secpkmsgs))
|
i = uint64(len(secpkcids))
|
||||||
secpkmsgs = append(secpkmsgs, m)
|
secpkcids = append(secpkcids, m)
|
||||||
secpkmsgmap[m.Cid()] = i
|
secpkmsgmap[m] = i
|
||||||
}
|
}
|
||||||
|
|
||||||
smi = append(smi, i)
|
smi = append(smi, i)
|
||||||
@ -259,5 +258,15 @@ func gatherMessages(cs *store.ChainStore, ts *types.TipSet) ([]*types.Message, [
|
|||||||
secpkincl = append(secpkincl, smi)
|
secpkincl = append(secpkincl, smi)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blsmsgs, err := cs.LoadMessagesFromCids(blscids)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
secpkmsgs, err := cs.LoadSignedMessagesFromCids(secpkcids)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return blsmsgs, blsincl, secpkmsgs, secpkincl, nil
|
return blsmsgs, blsincl, secpkmsgs, secpkincl, nil
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,8 @@ var minimumBaseFee = types.NewInt(uint64(build.MinimumBaseFee))
|
|||||||
|
|
||||||
var MaxActorPendingMessages = 1000
|
var MaxActorPendingMessages = 1000
|
||||||
|
|
||||||
|
var MaxNonceGap = uint64(4)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrMessageTooBig = errors.New("message too big")
|
ErrMessageTooBig = errors.New("message too big")
|
||||||
|
|
||||||
@ -69,6 +71,7 @@ var (
|
|||||||
ErrSoftValidationFailure = errors.New("validation failure")
|
ErrSoftValidationFailure = errors.New("validation failure")
|
||||||
ErrRBFTooLowPremium = errors.New("replace by fee has too low GasPremium")
|
ErrRBFTooLowPremium = errors.New("replace by fee has too low GasPremium")
|
||||||
ErrTooManyPendingMessages = errors.New("too many pending messages for actor")
|
ErrTooManyPendingMessages = errors.New("too many pending messages for actor")
|
||||||
|
ErrNonceGap = errors.New("unfulfilled nonce gap")
|
||||||
|
|
||||||
ErrTryAgain = errors.New("state inconsistency while pushing message; please try again")
|
ErrTryAgain = errors.New("state inconsistency while pushing message; please try again")
|
||||||
)
|
)
|
||||||
@ -154,19 +157,39 @@ type msgSet struct {
|
|||||||
requiredFunds *stdbig.Int
|
requiredFunds *stdbig.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMsgSet() *msgSet {
|
func newMsgSet(nonce uint64) *msgSet {
|
||||||
return &msgSet{
|
return &msgSet{
|
||||||
msgs: make(map[uint64]*types.SignedMessage),
|
msgs: make(map[uint64]*types.SignedMessage),
|
||||||
|
nextNonce: nonce,
|
||||||
requiredFunds: stdbig.NewInt(0),
|
requiredFunds: stdbig.NewInt(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, limit bool) (bool, error) {
|
func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, strict bool) (bool, error) {
|
||||||
if len(ms.msgs) == 0 || m.Message.Nonce >= ms.nextNonce {
|
nextNonce := ms.nextNonce
|
||||||
ms.nextNonce = m.Message.Nonce + 1
|
nonceGap := false
|
||||||
|
switch {
|
||||||
|
case m.Message.Nonce == nextNonce:
|
||||||
|
nextNonce++
|
||||||
|
// advance if we are filling a gap
|
||||||
|
for _, fillGap := ms.msgs[nextNonce]; fillGap; _, fillGap = ms.msgs[nextNonce] {
|
||||||
|
nextNonce++
|
||||||
|
}
|
||||||
|
|
||||||
|
case strict && m.Message.Nonce > nextNonce+MaxNonceGap:
|
||||||
|
return false, xerrors.Errorf("message nonce has too big a gap from expected nonce (Nonce: %d, nextNonce: %d): %w", m.Message.Nonce, nextNonce, ErrNonceGap)
|
||||||
|
|
||||||
|
case m.Message.Nonce > nextNonce:
|
||||||
|
nonceGap = true
|
||||||
}
|
}
|
||||||
|
|
||||||
exms, has := ms.msgs[m.Message.Nonce]
|
exms, has := ms.msgs[m.Message.Nonce]
|
||||||
if has {
|
if has {
|
||||||
|
// refuse RBF if we have a gap
|
||||||
|
if strict && nonceGap {
|
||||||
|
return false, xerrors.Errorf("rejecting replace by fee because of nonce gap (Nonce: %d, nextNonce: %d): %w", m.Message.Nonce, nextNonce, ErrNonceGap)
|
||||||
|
}
|
||||||
|
|
||||||
if m.Cid() != exms.Cid() {
|
if m.Cid() != exms.Cid() {
|
||||||
// check if RBF passes
|
// check if RBF passes
|
||||||
minPrice := exms.Message.GasPremium
|
minPrice := exms.Message.GasPremium
|
||||||
@ -182,17 +205,26 @@ func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, limit bool) (bool
|
|||||||
m.Message.From, m.Message.Nonce, minPrice, m.Message.GasPremium,
|
m.Message.From, m.Message.Nonce, minPrice, m.Message.GasPremium,
|
||||||
ErrRBFTooLowPremium)
|
ErrRBFTooLowPremium)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return false, xerrors.Errorf("message from %s with nonce %d already in mpool: %w",
|
||||||
|
m.Message.From, m.Message.Nonce, ErrSoftValidationFailure)
|
||||||
}
|
}
|
||||||
|
|
||||||
ms.requiredFunds.Sub(ms.requiredFunds, exms.Message.RequiredFunds().Int)
|
ms.requiredFunds.Sub(ms.requiredFunds, exms.Message.RequiredFunds().Int)
|
||||||
//ms.requiredFunds.Sub(ms.requiredFunds, exms.Message.Value.Int)
|
//ms.requiredFunds.Sub(ms.requiredFunds, exms.Message.Value.Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !has && limit && len(ms.msgs) > MaxActorPendingMessages {
|
if !has && strict && len(ms.msgs) > MaxActorPendingMessages {
|
||||||
log.Errorf("too many pending messages from actor %s", m.Message.From)
|
log.Errorf("too many pending messages from actor %s", m.Message.From)
|
||||||
return false, ErrTooManyPendingMessages
|
return false, ErrTooManyPendingMessages
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if strict && nonceGap {
|
||||||
|
log.Warnf("adding nonce-gapped message from %s (nonce: %d, nextNonce: %d)",
|
||||||
|
m.Message.From, m.Message.Nonce, nextNonce)
|
||||||
|
}
|
||||||
|
|
||||||
|
ms.nextNonce = nextNonce
|
||||||
ms.msgs[m.Message.Nonce] = m
|
ms.msgs[m.Message.Nonce] = m
|
||||||
ms.requiredFunds.Add(ms.requiredFunds, m.Message.RequiredFunds().Int)
|
ms.requiredFunds.Add(ms.requiredFunds, m.Message.RequiredFunds().Int)
|
||||||
//ms.requiredFunds.Add(ms.requiredFunds, m.Message.Value.Int)
|
//ms.requiredFunds.Add(ms.requiredFunds, m.Message.Value.Int)
|
||||||
@ -200,12 +232,38 @@ func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, limit bool) (bool
|
|||||||
return !has, nil
|
return !has, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *msgSet) rm(nonce uint64) {
|
func (ms *msgSet) rm(nonce uint64, applied bool) {
|
||||||
m, has := ms.msgs[nonce]
|
m, has := ms.msgs[nonce]
|
||||||
if has {
|
if !has {
|
||||||
ms.requiredFunds.Sub(ms.requiredFunds, m.Message.RequiredFunds().Int)
|
if applied && nonce >= ms.nextNonce {
|
||||||
//ms.requiredFunds.Sub(ms.requiredFunds, m.Message.Value.Int)
|
// we removed a message we did not know about because it was applied
|
||||||
delete(ms.msgs, nonce)
|
// we need to adjust the nonce and check if we filled a gap
|
||||||
|
ms.nextNonce = nonce + 1
|
||||||
|
for _, fillGap := ms.msgs[ms.nextNonce]; fillGap; _, fillGap = ms.msgs[ms.nextNonce] {
|
||||||
|
ms.nextNonce++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ms.requiredFunds.Sub(ms.requiredFunds, m.Message.RequiredFunds().Int)
|
||||||
|
//ms.requiredFunds.Sub(ms.requiredFunds, m.Message.Value.Int)
|
||||||
|
delete(ms.msgs, nonce)
|
||||||
|
|
||||||
|
// adjust next nonce
|
||||||
|
if applied {
|
||||||
|
// we removed a (known) message because it was applied in a tipset
|
||||||
|
// we can't possibly have filled a gap in this case
|
||||||
|
if nonce >= ms.nextNonce {
|
||||||
|
ms.nextNonce = nonce + 1
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// we removed a message because it was pruned
|
||||||
|
// we have to adjust the nonce if it creates a gap or rewinds state
|
||||||
|
if nonce < ms.nextNonce {
|
||||||
|
ms.nextNonce = nonce
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,6 +564,40 @@ func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet) error
|
|||||||
return mp.addLocked(m, true)
|
return mp.addLocked(m, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mp *MessagePool) addLoaded(m *types.SignedMessage) error {
|
||||||
|
err := mp.checkMessage(m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mp.curTsLk.Lock()
|
||||||
|
defer mp.curTsLk.Unlock()
|
||||||
|
|
||||||
|
curTs := mp.curTs
|
||||||
|
|
||||||
|
snonce, err := mp.getStateNonce(m.Message.From, curTs)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to look up actor state nonce: %s: %w", err, ErrSoftValidationFailure)
|
||||||
|
}
|
||||||
|
|
||||||
|
if snonce > m.Message.Nonce {
|
||||||
|
return xerrors.Errorf("minimum expected nonce is %d: %w", snonce, ErrNonceTooLow)
|
||||||
|
}
|
||||||
|
|
||||||
|
mp.lk.Lock()
|
||||||
|
defer mp.lk.Unlock()
|
||||||
|
|
||||||
|
if err := mp.verifyMsgBeforeAdd(m, curTs.Height()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := mp.checkBalance(m, curTs); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return mp.addLocked(m, false)
|
||||||
|
}
|
||||||
|
|
||||||
func (mp *MessagePool) addSkipChecks(m *types.SignedMessage) error {
|
func (mp *MessagePool) addSkipChecks(m *types.SignedMessage) error {
|
||||||
mp.lk.Lock()
|
mp.lk.Lock()
|
||||||
defer mp.lk.Unlock()
|
defer mp.lk.Unlock()
|
||||||
@ -513,7 +605,7 @@ func (mp *MessagePool) addSkipChecks(m *types.SignedMessage) error {
|
|||||||
return mp.addLocked(m, false)
|
return mp.addLocked(m, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *MessagePool) addLocked(m *types.SignedMessage, limit bool) error {
|
func (mp *MessagePool) addLocked(m *types.SignedMessage, strict bool) error {
|
||||||
log.Debugf("mpooladd: %s %d", m.Message.From, m.Message.Nonce)
|
log.Debugf("mpooladd: %s %d", m.Message.From, m.Message.Nonce)
|
||||||
if m.Signature.Type == crypto.SigTypeBLS {
|
if m.Signature.Type == crypto.SigTypeBLS {
|
||||||
mp.blsSigCache.Add(m.Cid(), m.Signature)
|
mp.blsSigCache.Add(m.Cid(), m.Signature)
|
||||||
@ -531,11 +623,16 @@ func (mp *MessagePool) addLocked(m *types.SignedMessage, limit bool) error {
|
|||||||
|
|
||||||
mset, ok := mp.pending[m.Message.From]
|
mset, ok := mp.pending[m.Message.From]
|
||||||
if !ok {
|
if !ok {
|
||||||
mset = newMsgSet()
|
nonce, err := mp.getStateNonce(m.Message.From, mp.curTs)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to get initial actor nonce: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mset = newMsgSet(nonce)
|
||||||
mp.pending[m.Message.From] = mset
|
mp.pending[m.Message.From] = mset
|
||||||
}
|
}
|
||||||
|
|
||||||
incr, err := mset.add(m, mp, limit)
|
incr, err := mset.add(m, mp, strict)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Info(err)
|
log.Info(err)
|
||||||
return err
|
return err
|
||||||
@ -702,14 +799,14 @@ func (mp *MessagePool) PushWithNonce(ctx context.Context, addr address.Address,
|
|||||||
return msg, mp.api.PubSubPublish(build.MessagesTopic(mp.netName), msgb)
|
return msg, mp.api.PubSubPublish(build.MessagesTopic(mp.netName), msgb)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *MessagePool) Remove(from address.Address, nonce uint64) {
|
func (mp *MessagePool) Remove(from address.Address, nonce uint64, applied bool) {
|
||||||
mp.lk.Lock()
|
mp.lk.Lock()
|
||||||
defer mp.lk.Unlock()
|
defer mp.lk.Unlock()
|
||||||
|
|
||||||
mp.remove(from, nonce)
|
mp.remove(from, nonce, applied)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *MessagePool) remove(from address.Address, nonce uint64) {
|
func (mp *MessagePool) remove(from address.Address, nonce uint64, applied bool) {
|
||||||
mset, ok := mp.pending[from]
|
mset, ok := mp.pending[from]
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
@ -732,22 +829,10 @@ func (mp *MessagePool) remove(from address.Address, nonce uint64) {
|
|||||||
|
|
||||||
// NB: This deletes any message with the given nonce. This makes sense
|
// NB: This deletes any message with the given nonce. This makes sense
|
||||||
// as two messages with the same sender cannot have the same nonce
|
// as two messages with the same sender cannot have the same nonce
|
||||||
mset.rm(nonce)
|
mset.rm(nonce, applied)
|
||||||
|
|
||||||
if len(mset.msgs) == 0 {
|
if len(mset.msgs) == 0 {
|
||||||
delete(mp.pending, from)
|
delete(mp.pending, from)
|
||||||
} else {
|
|
||||||
var max uint64
|
|
||||||
for nonce := range mset.msgs {
|
|
||||||
if max < nonce {
|
|
||||||
max = nonce
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if max < nonce {
|
|
||||||
max = nonce // we could have not seen the removed message before
|
|
||||||
}
|
|
||||||
|
|
||||||
mset.nextNonce = max + 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -815,7 +900,7 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet)
|
|||||||
rm := func(from address.Address, nonce uint64) {
|
rm := func(from address.Address, nonce uint64) {
|
||||||
s, ok := rmsgs[from]
|
s, ok := rmsgs[from]
|
||||||
if !ok {
|
if !ok {
|
||||||
mp.Remove(from, nonce)
|
mp.Remove(from, nonce, true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -824,7 +909,7 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
mp.Remove(from, nonce)
|
mp.Remove(from, nonce, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
maybeRepub := func(cid cid.Cid) {
|
maybeRepub := func(cid cid.Cid) {
|
||||||
@ -1126,7 +1211,7 @@ func (mp *MessagePool) loadLocal() error {
|
|||||||
return xerrors.Errorf("unmarshaling local message: %w", err)
|
return xerrors.Errorf("unmarshaling local message: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := mp.Add(&sm); err != nil {
|
if err := mp.addLoaded(&sm); err != nil {
|
||||||
if xerrors.Is(err, ErrNonceTooLow) {
|
if xerrors.Is(err, ErrNonceTooLow) {
|
||||||
continue // todo: drop the message from local cache (if above certain confidence threshold)
|
continue // todo: drop the message from local cache (if above certain confidence threshold)
|
||||||
}
|
}
|
||||||
|
@ -352,6 +352,12 @@ func TestRevertMessages(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPruningSimple(t *testing.T) {
|
func TestPruningSimple(t *testing.T) {
|
||||||
|
oldMaxNonceGap := MaxNonceGap
|
||||||
|
MaxNonceGap = 1000
|
||||||
|
defer func() {
|
||||||
|
MaxNonceGap = oldMaxNonceGap
|
||||||
|
}()
|
||||||
|
|
||||||
tma := newTestMpoolAPI()
|
tma := newTestMpoolAPI()
|
||||||
|
|
||||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||||
|
@ -98,7 +98,7 @@ keepLoop:
|
|||||||
// and remove all messages that are still in pruneMsgs after processing the chains
|
// and remove all messages that are still in pruneMsgs after processing the chains
|
||||||
log.Infof("Pruning %d messages", len(pruneMsgs))
|
log.Infof("Pruning %d messages", len(pruneMsgs))
|
||||||
for _, m := range pruneMsgs {
|
for _, m := range pruneMsgs {
|
||||||
mp.remove(m.Message.From, m.Message.Nonce)
|
mp.remove(m.Message.From, m.Message.Nonce, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -3,6 +3,7 @@ package messagepool
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"sort"
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
@ -16,6 +17,8 @@ import (
|
|||||||
|
|
||||||
const repubMsgLimit = 30
|
const repubMsgLimit = 30
|
||||||
|
|
||||||
|
var RepublishBatchDelay = 200 * time.Millisecond
|
||||||
|
|
||||||
func (mp *MessagePool) republishPendingMessages() error {
|
func (mp *MessagePool) republishPendingMessages() error {
|
||||||
mp.curTsLk.Lock()
|
mp.curTsLk.Lock()
|
||||||
ts := mp.curTs
|
ts := mp.curTs
|
||||||
@ -132,6 +135,12 @@ func (mp *MessagePool) republishPendingMessages() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
count++
|
count++
|
||||||
|
|
||||||
|
if count < len(msgs) {
|
||||||
|
// this delay is here to encourage the pubsub subsystem to process the messages serially
|
||||||
|
// and avoid creating nonce gaps because of concurrent validation.
|
||||||
|
time.Sleep(RepublishBatchDelay)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(msgs) > 0 {
|
if len(msgs) > 0 {
|
||||||
|
@ -12,6 +12,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestRepubMessages(t *testing.T) {
|
func TestRepubMessages(t *testing.T) {
|
||||||
|
oldRepublishBatchDelay := RepublishBatchDelay
|
||||||
|
RepublishBatchDelay = time.Microsecond
|
||||||
|
defer func() {
|
||||||
|
RepublishBatchDelay = oldRepublishBatchDelay
|
||||||
|
}()
|
||||||
|
|
||||||
tma := newTestMpoolAPI()
|
tma := newTestMpoolAPI()
|
||||||
ds := datastore.NewMapDatastore()
|
ds := datastore.NewMapDatastore()
|
||||||
|
|
||||||
|
@ -585,16 +585,18 @@ func (mp *MessagePool) getPendingMessages(curTs, ts *types.TipSet) (map[address.
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *MessagePool) getGasReward(msg *types.SignedMessage, baseFee types.BigInt, ts *types.TipSet) *big.Int {
|
func (*MessagePool) getGasReward(msg *types.SignedMessage, baseFee types.BigInt) *big.Int {
|
||||||
maxPremium := types.BigSub(msg.Message.GasFeeCap, baseFee)
|
maxPremium := types.BigSub(msg.Message.GasFeeCap, baseFee)
|
||||||
if types.BigCmp(maxPremium, msg.Message.GasPremium) < 0 {
|
|
||||||
|
if types.BigCmp(maxPremium, msg.Message.GasPremium) > 0 {
|
||||||
maxPremium = msg.Message.GasPremium
|
maxPremium = msg.Message.GasPremium
|
||||||
}
|
}
|
||||||
|
|
||||||
gasReward := abig.Mul(maxPremium, types.NewInt(uint64(msg.Message.GasLimit)))
|
gasReward := abig.Mul(maxPremium, types.NewInt(uint64(msg.Message.GasLimit)))
|
||||||
return gasReward.Int
|
return gasReward.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *MessagePool) getGasPerf(gasReward *big.Int, gasLimit int64) float64 {
|
func (*MessagePool) getGasPerf(gasReward *big.Int, gasLimit int64) float64 {
|
||||||
// gasPerf = gasReward * build.BlockGasLimit / gasLimit
|
// gasPerf = gasReward * build.BlockGasLimit / gasLimit
|
||||||
a := new(big.Rat).SetInt(new(big.Int).Mul(gasReward, bigBlockGasLimit))
|
a := new(big.Rat).SetInt(new(big.Int).Mul(gasReward, bigBlockGasLimit))
|
||||||
b := big.NewRat(1, gasLimit)
|
b := big.NewRat(1, gasLimit)
|
||||||
@ -672,7 +674,7 @@ func (mp *MessagePool) createMessageChains(actor address.Address, mset map[uint6
|
|||||||
balance = new(big.Int).Sub(balance, value)
|
balance = new(big.Int).Sub(balance, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
gasReward := mp.getGasReward(m, baseFee, ts)
|
gasReward := mp.getGasReward(m, baseFee)
|
||||||
rewards = append(rewards, gasReward)
|
rewards = append(rewards, gasReward)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -776,7 +778,7 @@ func (mc *msgChain) Before(other *msgChain) bool {
|
|||||||
func (mc *msgChain) Trim(gasLimit int64, mp *MessagePool, baseFee types.BigInt, ts *types.TipSet) {
|
func (mc *msgChain) Trim(gasLimit int64, mp *MessagePool, baseFee types.BigInt, ts *types.TipSet) {
|
||||||
i := len(mc.msgs) - 1
|
i := len(mc.msgs) - 1
|
||||||
for i >= 0 && (mc.gasLimit > gasLimit || mc.gasPerf < 0) {
|
for i >= 0 && (mc.gasLimit > gasLimit || mc.gasPerf < 0) {
|
||||||
gasReward := mp.getGasReward(mc.msgs[i], baseFee, ts)
|
gasReward := mp.getGasReward(mc.msgs[i], baseFee)
|
||||||
mc.gasReward = new(big.Int).Sub(mc.gasReward, gasReward)
|
mc.gasReward = new(big.Int).Sub(mc.gasReward, gasReward)
|
||||||
mc.gasLimit -= mc.msgs[i].Message.GasLimit
|
mc.gasLimit -= mc.msgs[i].Message.GasLimit
|
||||||
if mc.gasLimit > 0 {
|
if mc.gasLimit > 0 {
|
||||||
|
@ -2,6 +2,7 @@ package messagepool
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@ -369,6 +370,12 @@ func TestMessageChainSkipping(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBasicMessageSelection(t *testing.T) {
|
func TestBasicMessageSelection(t *testing.T) {
|
||||||
|
oldMaxNonceGap := MaxNonceGap
|
||||||
|
MaxNonceGap = 1000
|
||||||
|
defer func() {
|
||||||
|
MaxNonceGap = oldMaxNonceGap
|
||||||
|
}()
|
||||||
|
|
||||||
mp, tma := makeTestMpool()
|
mp, tma := makeTestMpool()
|
||||||
|
|
||||||
// the actors
|
// the actors
|
||||||
@ -1055,17 +1062,17 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu
|
|||||||
|
|
||||||
greedyReward := big.NewInt(0)
|
greedyReward := big.NewInt(0)
|
||||||
for _, m := range greedyMsgs {
|
for _, m := range greedyMsgs {
|
||||||
greedyReward.Add(greedyReward, mp.getGasReward(m, baseFee, ts))
|
greedyReward.Add(greedyReward, mp.getGasReward(m, baseFee))
|
||||||
}
|
}
|
||||||
|
|
||||||
optReward := big.NewInt(0)
|
optReward := big.NewInt(0)
|
||||||
for _, m := range optMsgs {
|
for _, m := range optMsgs {
|
||||||
optReward.Add(optReward, mp.getGasReward(m, baseFee, ts))
|
optReward.Add(optReward, mp.getGasReward(m, baseFee))
|
||||||
}
|
}
|
||||||
|
|
||||||
bestTqReward := big.NewInt(0)
|
bestTqReward := big.NewInt(0)
|
||||||
for _, m := range bestMsgs {
|
for _, m := range bestMsgs {
|
||||||
bestTqReward.Add(bestTqReward, mp.getGasReward(m, baseFee, ts))
|
bestTqReward.Add(bestTqReward, mp.getGasReward(m, baseFee))
|
||||||
}
|
}
|
||||||
|
|
||||||
totalBestTQReward += float64(bestTqReward.Uint64())
|
totalBestTQReward += float64(bestTqReward.Uint64())
|
||||||
@ -1146,3 +1153,35 @@ func TestCompetitiveMessageSelectionZipf(t *testing.T) {
|
|||||||
t.Logf("Average reward boost across all seeds: %f", rewardBoost)
|
t.Logf("Average reward boost across all seeds: %f", rewardBoost)
|
||||||
t.Logf("Average reward of best ticket across all seeds: %f", tqReward)
|
t.Logf("Average reward of best ticket across all seeds: %f", tqReward)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGasReward(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
Premium uint64
|
||||||
|
FeeCap uint64
|
||||||
|
BaseFee uint64
|
||||||
|
GasReward int64
|
||||||
|
}{
|
||||||
|
{Premium: 100, FeeCap: 200, BaseFee: 100, GasReward: 100},
|
||||||
|
{Premium: 100, FeeCap: 200, BaseFee: 210, GasReward: -10},
|
||||||
|
{Premium: 200, FeeCap: 250, BaseFee: 210, GasReward: 40},
|
||||||
|
{Premium: 200, FeeCap: 250, BaseFee: 2000, GasReward: -1750},
|
||||||
|
}
|
||||||
|
|
||||||
|
mp := new(MessagePool)
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(fmt.Sprintf("%v", test), func(t *testing.T) {
|
||||||
|
msg := &types.SignedMessage{
|
||||||
|
Message: types.Message{
|
||||||
|
GasLimit: 10,
|
||||||
|
GasFeeCap: types.NewInt(test.FeeCap),
|
||||||
|
GasPremium: types.NewInt(test.Premium),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
rew := mp.getGasReward(msg, types.NewInt(test.BaseFee))
|
||||||
|
if rew.Cmp(big.NewInt(test.GasReward*10)) != 0 {
|
||||||
|
t.Errorf("bad reward: expected %d, got %s", test.GasReward*10, rew)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -49,6 +49,7 @@ var chainHeadKey = dstore.NewKey("head")
|
|||||||
var blockValidationCacheKeyPrefix = dstore.NewKey("blockValidation")
|
var blockValidationCacheKeyPrefix = dstore.NewKey("blockValidation")
|
||||||
|
|
||||||
var DefaultTipSetCacheSize = 8192
|
var DefaultTipSetCacheSize = 8192
|
||||||
|
var DefaultMsgMetaCacheSize = 2048
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
if s := os.Getenv("LOTUS_CHAIN_TIPSET_CACHE"); s != "" {
|
if s := os.Getenv("LOTUS_CHAIN_TIPSET_CACHE"); s != "" {
|
||||||
@ -58,6 +59,14 @@ func init() {
|
|||||||
}
|
}
|
||||||
DefaultTipSetCacheSize = tscs
|
DefaultTipSetCacheSize = tscs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s := os.Getenv("LOTUS_CHAIN_MSGMETA_CACHE"); s != "" {
|
||||||
|
mmcs, err := strconv.Atoi(s)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to parse 'LOTUS_CHAIN_MSGMETA_CACHE' env var: %s", err)
|
||||||
|
}
|
||||||
|
DefaultMsgMetaCacheSize = mmcs
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReorgNotifee represents a callback that gets called upon reorgs.
|
// ReorgNotifee represents a callback that gets called upon reorgs.
|
||||||
@ -113,7 +122,7 @@ type ChainStore struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls vm.SyscallBuilder) *ChainStore {
|
func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls vm.SyscallBuilder) *ChainStore {
|
||||||
c, _ := lru.NewARC(2048)
|
c, _ := lru.NewARC(DefaultMsgMetaCacheSize)
|
||||||
tsc, _ := lru.NewARC(DefaultTipSetCacheSize)
|
tsc, _ := lru.NewARC(DefaultTipSetCacheSize)
|
||||||
cs := &ChainStore{
|
cs := &ChainStore{
|
||||||
bs: bs,
|
bs: bs,
|
||||||
@ -857,7 +866,7 @@ type mmCids struct {
|
|||||||
secpk []cid.Cid
|
secpk []cid.Cid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *ChainStore) readMsgMetaCids(mmc cid.Cid) ([]cid.Cid, []cid.Cid, error) {
|
func (cs *ChainStore) ReadMsgMetaCids(mmc cid.Cid) ([]cid.Cid, []cid.Cid, error) {
|
||||||
o, ok := cs.mmCache.Get(mmc)
|
o, ok := cs.mmCache.Get(mmc)
|
||||||
if ok {
|
if ok {
|
||||||
mmcids := o.(*mmCids)
|
mmcids := o.(*mmCids)
|
||||||
@ -913,7 +922,7 @@ func (cs *ChainStore) GetPath(ctx context.Context, from types.TipSetKey, to type
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cs *ChainStore) MessagesForBlock(b *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) {
|
func (cs *ChainStore) MessagesForBlock(b *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) {
|
||||||
blscids, secpkcids, err := cs.readMsgMetaCids(b.Messages)
|
blscids, secpkcids, err := cs.ReadMsgMetaCids(b.Messages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -555,6 +555,8 @@ func (mv *MessageValidator) Validate(ctx context.Context, pid peer.ID, msg *pubs
|
|||||||
fallthrough
|
fallthrough
|
||||||
case xerrors.Is(err, messagepool.ErrTooManyPendingMessages):
|
case xerrors.Is(err, messagepool.ErrTooManyPendingMessages):
|
||||||
fallthrough
|
fallthrough
|
||||||
|
case xerrors.Is(err, messagepool.ErrNonceGap):
|
||||||
|
fallthrough
|
||||||
case xerrors.Is(err, messagepool.ErrNonceTooLow):
|
case xerrors.Is(err, messagepool.ErrNonceTooLow):
|
||||||
return pubsub.ValidationIgnore
|
return pubsub.ValidationIgnore
|
||||||
default:
|
default:
|
||||||
|
108
cli/net.go
108
cli/net.go
@ -6,9 +6,12 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"text/tabwriter"
|
||||||
|
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
protocol "github.com/libp2p/go-libp2p-core/protocol"
|
||||||
|
|
||||||
|
"github.com/dustin/go-humanize"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/lib/addrutil"
|
"github.com/filecoin-project/lotus/lib/addrutil"
|
||||||
@ -25,12 +28,20 @@ var netCmd = &cli.Command{
|
|||||||
netFindPeer,
|
netFindPeer,
|
||||||
netScores,
|
netScores,
|
||||||
NetReachability,
|
NetReachability,
|
||||||
|
NetBandwidthCmd,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var NetPeers = &cli.Command{
|
var NetPeers = &cli.Command{
|
||||||
Name: "peers",
|
Name: "peers",
|
||||||
Usage: "Print peers",
|
Usage: "Print peers",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "agent",
|
||||||
|
Aliases: []string{"a"},
|
||||||
|
Usage: "Print agent name",
|
||||||
|
},
|
||||||
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
api, closer, err := GetAPI(cctx)
|
api, closer, err := GetAPI(cctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -48,7 +59,17 @@ var NetPeers = &cli.Command{
|
|||||||
})
|
})
|
||||||
|
|
||||||
for _, peer := range peers {
|
for _, peer := range peers {
|
||||||
fmt.Printf("%s, %s\n", peer.ID, peer.Addrs)
|
var agent string
|
||||||
|
if cctx.Bool("agent") {
|
||||||
|
agent, err = api.NetAgentVersion(ctx, peer.ID)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("getting agent version: %s", err)
|
||||||
|
} else {
|
||||||
|
agent = ", " + agent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%s, %s%s\n", peer.ID, peer.Addrs, agent)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -228,3 +249,88 @@ var NetReachability = &cli.Command{
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var NetBandwidthCmd = &cli.Command{
|
||||||
|
Name: "bandwidth",
|
||||||
|
Usage: "Print bandwidth usage information",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "by-peer",
|
||||||
|
Usage: "list bandwidth usage by peer",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "by-protocol",
|
||||||
|
Usage: "list bandwidth usage by protocol",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
api, closer, err := GetAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
|
||||||
|
ctx := ReqContext(cctx)
|
||||||
|
|
||||||
|
bypeer := cctx.Bool("by-peer")
|
||||||
|
byproto := cctx.Bool("by-protocol")
|
||||||
|
|
||||||
|
tw := tabwriter.NewWriter(os.Stdout, 4, 4, 2, ' ', 0)
|
||||||
|
|
||||||
|
fmt.Fprintf(tw, "Segment\tTotalIn\tTotalOut\tRateIn\tRateOut\n")
|
||||||
|
|
||||||
|
if bypeer {
|
||||||
|
bw, err := api.NetBandwidthStatsByPeer(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var peers []string
|
||||||
|
for p := range bw {
|
||||||
|
peers = append(peers, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(peers, func(i, j int) bool {
|
||||||
|
return peers[i] < peers[j]
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, p := range peers {
|
||||||
|
s := bw[p]
|
||||||
|
fmt.Fprintf(tw, "%s\t%s\t%s\t%s/s\t%s/s\n", p, humanize.Bytes(uint64(s.TotalIn)), humanize.Bytes(uint64(s.TotalOut)), humanize.Bytes(uint64(s.RateIn)), humanize.Bytes(uint64(s.RateOut)))
|
||||||
|
}
|
||||||
|
} else if byproto {
|
||||||
|
bw, err := api.NetBandwidthStatsByProtocol(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var protos []protocol.ID
|
||||||
|
for p := range bw {
|
||||||
|
protos = append(protos, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(protos, func(i, j int) bool {
|
||||||
|
return protos[i] < protos[j]
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, p := range protos {
|
||||||
|
s := bw[p]
|
||||||
|
if p == "" {
|
||||||
|
p = "<unknown>"
|
||||||
|
}
|
||||||
|
fmt.Fprintf(tw, "%s\t%s\t%s\t%s/s\t%s/s\n", p, humanize.Bytes(uint64(s.TotalIn)), humanize.Bytes(uint64(s.TotalOut)), humanize.Bytes(uint64(s.RateIn)), humanize.Bytes(uint64(s.RateOut)))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
s, err := api.NetBandwidthStats(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(tw, "Total\t%s\t%s\t%s/s\t%s/s\n", humanize.Bytes(uint64(s.TotalIn)), humanize.Bytes(uint64(s.TotalOut)), humanize.Bytes(uint64(s.RateIn)), humanize.Bytes(uint64(s.RateOut)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return tw.Flush()
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
107
cli/paych.go
107
cli/paych.go
@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/paychmgr"
|
"github.com/filecoin-project/lotus/paychmgr"
|
||||||
|
|
||||||
@ -21,7 +22,7 @@ var paychCmd = &cli.Command{
|
|||||||
Name: "paych",
|
Name: "paych",
|
||||||
Usage: "Manage payment channels",
|
Usage: "Manage payment channels",
|
||||||
Subcommands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
paychGetCmd,
|
paychAddFundsCmd,
|
||||||
paychListCmd,
|
paychListCmd,
|
||||||
paychVoucherCmd,
|
paychVoucherCmd,
|
||||||
paychSettleCmd,
|
paychSettleCmd,
|
||||||
@ -29,9 +30,9 @@ var paychCmd = &cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var paychGetCmd = &cli.Command{
|
var paychAddFundsCmd = &cli.Command{
|
||||||
Name: "get",
|
Name: "add-funds",
|
||||||
Usage: "Create a new payment channel or get existing one and add amount to it",
|
Usage: "Add funds to the payment channel between fromAddress and toAddress. Creates the payment channel if it doesn't already exist.",
|
||||||
ArgsUsage: "[fromAddress toAddress amount]",
|
ArgsUsage: "[fromAddress toAddress amount]",
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
if cctx.Args().Len() != 3 {
|
if cctx.Args().Len() != 3 {
|
||||||
@ -79,6 +80,92 @@ var paychGetCmd = &cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var paychStatusCmd = &cli.Command{
|
||||||
|
Name: "status",
|
||||||
|
Usage: "Show the status of an outbound payment channel between fromAddress and toAddress",
|
||||||
|
ArgsUsage: "[fromAddress toAddress]",
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
if cctx.Args().Len() != 2 {
|
||||||
|
return ShowHelp(cctx, fmt.Errorf("must pass two arguments: <from> <to>"))
|
||||||
|
}
|
||||||
|
|
||||||
|
from, err := address.NewFromString(cctx.Args().Get(0))
|
||||||
|
if err != nil {
|
||||||
|
return ShowHelp(cctx, fmt.Errorf("failed to parse from address: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
to, err := address.NewFromString(cctx.Args().Get(1))
|
||||||
|
if err != nil {
|
||||||
|
return ShowHelp(cctx, fmt.Errorf("failed to parse to address: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
api, closer, err := GetFullNodeAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
|
||||||
|
avail, err := api.PaychAvailableFunds(from, to)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if avail.Channel == nil {
|
||||||
|
if avail.PendingWaitSentinel != nil {
|
||||||
|
fmt.Fprint(cctx.App.Writer, "Creating channel\n")
|
||||||
|
fmt.Fprintf(cctx.App.Writer, " From: %s\n", from)
|
||||||
|
fmt.Fprintf(cctx.App.Writer, " To: %s\n", to)
|
||||||
|
fmt.Fprintf(cctx.App.Writer, " Pending Amt: %d\n", avail.PendingAmt)
|
||||||
|
fmt.Fprintf(cctx.App.Writer, " Wait Sentinel: %s\n", avail.PendingWaitSentinel)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
fmt.Fprint(cctx.App.Writer, "Channel does not exist\n")
|
||||||
|
fmt.Fprintf(cctx.App.Writer, " From: %s\n", from)
|
||||||
|
fmt.Fprintf(cctx.App.Writer, " To: %s\n", to)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if avail.PendingWaitSentinel != nil {
|
||||||
|
fmt.Fprint(cctx.App.Writer, "Adding Funds to channel\n")
|
||||||
|
} else {
|
||||||
|
fmt.Fprint(cctx.App.Writer, "Channel exists\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
nameValues := [][]string{
|
||||||
|
{"Channel", avail.Channel.String()},
|
||||||
|
{"From", from.String()},
|
||||||
|
{"To", to.String()},
|
||||||
|
{"Confirmed Amt", fmt.Sprintf("%d", avail.ConfirmedAmt)},
|
||||||
|
{"Pending Amt", fmt.Sprintf("%d", avail.PendingAmt)},
|
||||||
|
{"Queued Amt", fmt.Sprintf("%d", avail.QueuedAmt)},
|
||||||
|
{"Voucher Redeemed Amt", fmt.Sprintf("%d", avail.VoucherReedeemedAmt)},
|
||||||
|
}
|
||||||
|
if avail.PendingWaitSentinel != nil {
|
||||||
|
nameValues = append(nameValues, []string{
|
||||||
|
"Add Funds Wait Sentinel",
|
||||||
|
avail.PendingWaitSentinel.String(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fmt.Fprint(cctx.App.Writer, formatNameValues(nameValues))
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatNameValues(nameValues [][]string) string {
|
||||||
|
maxLen := 0
|
||||||
|
for _, nv := range nameValues {
|
||||||
|
if len(nv[0]) > maxLen {
|
||||||
|
maxLen = len(nv[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out := make([]string, len(nameValues))
|
||||||
|
for i, nv := range nameValues {
|
||||||
|
namePad := strings.Repeat(" ", maxLen-len(nv[0]))
|
||||||
|
out[i] = " " + nv[0] + ": " + namePad + nv[1]
|
||||||
|
}
|
||||||
|
return strings.Join(out, "\n") + "\n"
|
||||||
|
}
|
||||||
|
|
||||||
var paychListCmd = &cli.Command{
|
var paychListCmd = &cli.Command{
|
||||||
Name: "list",
|
Name: "list",
|
||||||
Usage: "List all locally registered payment channels",
|
Usage: "List all locally registered payment channels",
|
||||||
@ -217,9 +304,9 @@ var paychVoucherCreateCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
amt, err := types.BigFromString(cctx.Args().Get(1))
|
amt, err := types.ParseFIL(cctx.Args().Get(1))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return ShowHelp(cctx, fmt.Errorf("parsing amount failed: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
lane := cctx.Int("lane")
|
lane := cctx.Int("lane")
|
||||||
@ -232,12 +319,16 @@ var paychVoucherCreateCmd = &cli.Command{
|
|||||||
|
|
||||||
ctx := ReqContext(cctx)
|
ctx := ReqContext(cctx)
|
||||||
|
|
||||||
sv, err := api.PaychVoucherCreate(ctx, ch, amt, uint64(lane))
|
v, err := api.PaychVoucherCreate(ctx, ch, types.BigInt(amt), uint64(lane))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
enc, err := EncodedString(sv)
|
if v.Voucher == nil {
|
||||||
|
return fmt.Errorf("Could not create voucher: insufficient funds in channel, shortfall: %d", v.Shortfall)
|
||||||
|
}
|
||||||
|
|
||||||
|
enc, err := EncodedString(v.Voucher)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,14 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||||
saminer "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
saminer "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||||
@ -52,7 +55,7 @@ func TestPaymentChannels(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
nodes, addrs := startTwoNodesOneMiner(ctx, t, blocktime)
|
nodes, addrs := startTwoNodesOneMiner(ctx, t, blocktime)
|
||||||
paymentCreator := nodes[0]
|
paymentCreator := nodes[0]
|
||||||
paymentReceiver := nodes[0]
|
paymentReceiver := nodes[1]
|
||||||
creatorAddr := addrs[0]
|
creatorAddr := addrs[0]
|
||||||
receiverAddr := addrs[1]
|
receiverAddr := addrs[1]
|
||||||
|
|
||||||
@ -61,10 +64,10 @@ func TestPaymentChannels(t *testing.T) {
|
|||||||
creatorCLI := mockCLI.client(paymentCreator.ListenAddr)
|
creatorCLI := mockCLI.client(paymentCreator.ListenAddr)
|
||||||
receiverCLI := mockCLI.client(paymentReceiver.ListenAddr)
|
receiverCLI := mockCLI.client(paymentReceiver.ListenAddr)
|
||||||
|
|
||||||
// creator: paych get <creator> <receiver> <amount>
|
// creator: paych add-funds <creator> <receiver> <amount>
|
||||||
channelAmt := "100000"
|
channelAmt := "100000"
|
||||||
cmd := []string{creatorAddr.String(), receiverAddr.String(), channelAmt}
|
cmd := []string{creatorAddr.String(), receiverAddr.String(), channelAmt}
|
||||||
chstr := creatorCLI.runCmd(paychGetCmd, cmd)
|
chstr := creatorCLI.runCmd(paychAddFundsCmd, cmd)
|
||||||
|
|
||||||
chAddr, err := address.NewFromString(chstr)
|
chAddr, err := address.NewFromString(chstr)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -98,6 +101,83 @@ type voucherSpec struct {
|
|||||||
lane int
|
lane int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestPaymentChannelStatus tests the payment channel status CLI command
|
||||||
|
func TestPaymentChannelStatus(t *testing.T) {
|
||||||
|
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||||
|
|
||||||
|
blocktime := 5 * time.Millisecond
|
||||||
|
ctx := context.Background()
|
||||||
|
nodes, addrs := startTwoNodesOneMiner(ctx, t, blocktime)
|
||||||
|
paymentCreator := nodes[0]
|
||||||
|
creatorAddr := addrs[0]
|
||||||
|
receiverAddr := addrs[1]
|
||||||
|
|
||||||
|
// Create mock CLI
|
||||||
|
mockCLI := newMockCLI(t)
|
||||||
|
creatorCLI := mockCLI.client(paymentCreator.ListenAddr)
|
||||||
|
|
||||||
|
cmd := []string{creatorAddr.String(), receiverAddr.String()}
|
||||||
|
out := creatorCLI.runCmd(paychStatusCmd, cmd)
|
||||||
|
fmt.Println(out)
|
||||||
|
noChannelState := "Channel does not exist"
|
||||||
|
require.Regexp(t, regexp.MustCompile(noChannelState), out)
|
||||||
|
|
||||||
|
channelAmt := uint64(100)
|
||||||
|
create := make(chan string)
|
||||||
|
go func() {
|
||||||
|
// creator: paych get <creator> <receiver> <amount>
|
||||||
|
cmd = []string{creatorAddr.String(), receiverAddr.String(), fmt.Sprintf("%d", channelAmt)}
|
||||||
|
create <- creatorCLI.runCmd(paychGetCmd, cmd)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Wait for the output to stop being "Channel does not exist"
|
||||||
|
for regexp.MustCompile(noChannelState).MatchString(out) {
|
||||||
|
cmd = []string{creatorAddr.String(), receiverAddr.String()}
|
||||||
|
out = creatorCLI.runCmd(paychStatusCmd, cmd)
|
||||||
|
}
|
||||||
|
fmt.Println(out)
|
||||||
|
|
||||||
|
// The next state should be creating channel or channel created, depending
|
||||||
|
// on timing
|
||||||
|
stateCreating := regexp.MustCompile("Creating channel").MatchString(out)
|
||||||
|
stateCreated := regexp.MustCompile("Channel exists").MatchString(out)
|
||||||
|
require.True(t, stateCreating || stateCreated)
|
||||||
|
|
||||||
|
channelAmtAtto := types.BigMul(types.NewInt(channelAmt), types.NewInt(build.FilecoinPrecision))
|
||||||
|
channelAmtStr := fmt.Sprintf("%d", channelAmtAtto)
|
||||||
|
if stateCreating {
|
||||||
|
// If we're in the creating state (most likely) the amount should be pending
|
||||||
|
require.Regexp(t, regexp.MustCompile("Pending.*"+channelAmtStr), out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for create channel to complete
|
||||||
|
chstr := <-create
|
||||||
|
|
||||||
|
cmd = []string{creatorAddr.String(), receiverAddr.String()}
|
||||||
|
out = creatorCLI.runCmd(paychStatusCmd, cmd)
|
||||||
|
fmt.Println(out)
|
||||||
|
// Output should have the channel address
|
||||||
|
require.Regexp(t, regexp.MustCompile("Channel.*"+chstr), out)
|
||||||
|
// Output should have confirmed amount
|
||||||
|
require.Regexp(t, regexp.MustCompile("Confirmed.*"+channelAmtStr), out)
|
||||||
|
|
||||||
|
chAddr, err := address.NewFromString(chstr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// creator: paych voucher create <channel> <amount>
|
||||||
|
voucherAmt := uint64(10)
|
||||||
|
cmd = []string{chAddr.String(), fmt.Sprintf("%d", voucherAmt)}
|
||||||
|
creatorCLI.runCmd(paychVoucherCreateCmd, cmd)
|
||||||
|
|
||||||
|
cmd = []string{creatorAddr.String(), receiverAddr.String()}
|
||||||
|
out = creatorCLI.runCmd(paychStatusCmd, cmd)
|
||||||
|
fmt.Println(out)
|
||||||
|
voucherAmtAtto := types.BigMul(types.NewInt(voucherAmt), types.NewInt(build.FilecoinPrecision))
|
||||||
|
voucherAmtStr := fmt.Sprintf("%d", voucherAmtAtto)
|
||||||
|
// Output should include voucher amount
|
||||||
|
require.Regexp(t, regexp.MustCompile("Voucher.*"+voucherAmtStr), out)
|
||||||
|
}
|
||||||
|
|
||||||
// TestPaymentChannelVouchers does a basic test to exercise some payment
|
// TestPaymentChannelVouchers does a basic test to exercise some payment
|
||||||
// channel voucher commands
|
// channel voucher commands
|
||||||
func TestPaymentChannelVouchers(t *testing.T) {
|
func TestPaymentChannelVouchers(t *testing.T) {
|
||||||
@ -116,10 +196,10 @@ func TestPaymentChannelVouchers(t *testing.T) {
|
|||||||
creatorCLI := mockCLI.client(paymentCreator.ListenAddr)
|
creatorCLI := mockCLI.client(paymentCreator.ListenAddr)
|
||||||
receiverCLI := mockCLI.client(paymentReceiver.ListenAddr)
|
receiverCLI := mockCLI.client(paymentReceiver.ListenAddr)
|
||||||
|
|
||||||
// creator: paych get <creator> <receiver> <amount>
|
// creator: paych add-funds <creator> <receiver> <amount>
|
||||||
channelAmt := "100000"
|
channelAmt := "100000"
|
||||||
cmd := []string{creatorAddr.String(), receiverAddr.String(), channelAmt}
|
cmd := []string{creatorAddr.String(), receiverAddr.String(), channelAmt}
|
||||||
chstr := creatorCLI.runCmd(paychGetCmd, cmd)
|
chstr := creatorCLI.runCmd(paychAddFundsCmd, cmd)
|
||||||
|
|
||||||
chAddr, err := address.NewFromString(chstr)
|
chAddr, err := address.NewFromString(chstr)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -248,6 +328,50 @@ func TestPaymentChannelVouchers(t *testing.T) {
|
|||||||
checkVoucherOutput(t, bestSpendable, bestVouchers)
|
checkVoucherOutput(t, bestSpendable, bestVouchers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestPaymentChannelVoucherCreateShortfall verifies that if a voucher amount
|
||||||
|
// is greater than what's left in the channel, voucher create fails
|
||||||
|
func TestPaymentChannelVoucherCreateShortfall(t *testing.T) {
|
||||||
|
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||||
|
|
||||||
|
blocktime := 5 * time.Millisecond
|
||||||
|
ctx := context.Background()
|
||||||
|
nodes, addrs := startTwoNodesOneMiner(ctx, t, blocktime)
|
||||||
|
paymentCreator := nodes[0]
|
||||||
|
creatorAddr := addrs[0]
|
||||||
|
receiverAddr := addrs[1]
|
||||||
|
|
||||||
|
// Create mock CLI
|
||||||
|
mockCLI := newMockCLI(t)
|
||||||
|
creatorCLI := mockCLI.client(paymentCreator.ListenAddr)
|
||||||
|
|
||||||
|
// creator: paych get <creator> <receiver> <amount>
|
||||||
|
channelAmt := 100
|
||||||
|
cmd := []string{creatorAddr.String(), receiverAddr.String(), fmt.Sprintf("%d", channelAmt)}
|
||||||
|
chstr := creatorCLI.runCmd(paychGetCmd, cmd)
|
||||||
|
|
||||||
|
chAddr, err := address.NewFromString(chstr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// creator: paych voucher create <channel> <amount> --lane=1
|
||||||
|
voucherAmt1 := 60
|
||||||
|
lane1 := "--lane=1"
|
||||||
|
cmd = []string{lane1, chAddr.String(), strconv.Itoa(voucherAmt1)}
|
||||||
|
voucher1 := creatorCLI.runCmd(paychVoucherCreateCmd, cmd)
|
||||||
|
fmt.Println(voucher1)
|
||||||
|
|
||||||
|
// creator: paych voucher create <channel> <amount> --lane=2
|
||||||
|
lane2 := "--lane=2"
|
||||||
|
voucherAmt2 := 70
|
||||||
|
cmd = []string{lane2, chAddr.String(), strconv.Itoa(voucherAmt2)}
|
||||||
|
_, err = creatorCLI.runCmdRaw(paychVoucherCreateCmd, cmd)
|
||||||
|
|
||||||
|
// Should fail because channel doesn't have required amount
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
shortfall := voucherAmt1 + voucherAmt2 - channelAmt
|
||||||
|
require.Regexp(t, regexp.MustCompile(fmt.Sprintf("shortfall: %d", shortfall)), err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
func checkVoucherOutput(t *testing.T, list string, vouchers []voucherSpec) {
|
func checkVoucherOutput(t *testing.T, list string, vouchers []voucherSpec) {
|
||||||
lines := strings.Split(list, "\n")
|
lines := strings.Split(list, "\n")
|
||||||
listVouchers := make(map[string]string)
|
listVouchers := make(map[string]string)
|
||||||
@ -350,6 +474,13 @@ type mockCLIClient struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *mockCLIClient) runCmd(cmd *cli.Command, input []string) string {
|
func (c *mockCLIClient) runCmd(cmd *cli.Command, input []string) string {
|
||||||
|
out, err := c.runCmdRaw(cmd, input)
|
||||||
|
require.NoError(c.t, err)
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *mockCLIClient) runCmdRaw(cmd *cli.Command, input []string) (string, error) {
|
||||||
// prepend --api=<node api listener address>
|
// prepend --api=<node api listener address>
|
||||||
apiFlag := "--api=" + c.addr.String()
|
apiFlag := "--api=" + c.addr.String()
|
||||||
input = append([]string{apiFlag}, input...)
|
input = append([]string{apiFlag}, input...)
|
||||||
@ -359,12 +490,11 @@ func (c *mockCLIClient) runCmd(cmd *cli.Command, input []string) string {
|
|||||||
require.NoError(c.t, err)
|
require.NoError(c.t, err)
|
||||||
|
|
||||||
err = cmd.Action(cli.NewContext(c.cctx.App, fs, c.cctx))
|
err = cmd.Action(cli.NewContext(c.cctx.App, fs, c.cctx))
|
||||||
require.NoError(c.t, err)
|
|
||||||
|
|
||||||
// Get the output
|
// Get the output
|
||||||
str := strings.TrimSpace(c.out.String())
|
str := strings.TrimSpace(c.out.String())
|
||||||
c.out.Reset()
|
c.out.Reset()
|
||||||
return str
|
return str, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *mockCLIClient) flagSet(cmd *cli.Command) *flag.FlagSet {
|
func (c *mockCLIClient) flagSet(cmd *cli.Command) *flag.FlagSet {
|
||||||
|
54
cli/state.go
54
cli/state.go
@ -26,11 +26,7 @@ import (
|
|||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
"github.com/filecoin-project/specs-actors/actors/builtin/exported"
|
||||||
miner2 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
@ -568,25 +564,7 @@ var stateGetActorCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var strtype string
|
strtype := builtin.ActorNameByCode(a.Code)
|
||||||
switch a.Code {
|
|
||||||
case builtin.AccountActorCodeID:
|
|
||||||
strtype = "account"
|
|
||||||
case builtin.MultisigActorCodeID:
|
|
||||||
strtype = "multisig"
|
|
||||||
case builtin.CronActorCodeID:
|
|
||||||
strtype = "cron"
|
|
||||||
case builtin.InitActorCodeID:
|
|
||||||
strtype = "init"
|
|
||||||
case builtin.StorageMinerActorCodeID:
|
|
||||||
strtype = "miner"
|
|
||||||
case builtin.StorageMarketActorCodeID:
|
|
||||||
strtype = "market"
|
|
||||||
case builtin.StoragePowerActorCodeID:
|
|
||||||
strtype = "power"
|
|
||||||
default:
|
|
||||||
strtype = "unknown"
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Address:\t%s\n", addr)
|
fmt.Printf("Address:\t%s\n", addr)
|
||||||
fmt.Printf("Balance:\t%s\n", types.FIL(a.Balance))
|
fmt.Printf("Balance:\t%s\n", types.FIL(a.Balance))
|
||||||
@ -1460,21 +1438,21 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var f interface{}
|
var target abi.Invokee
|
||||||
switch act {
|
for _, actor := range exported.BuiltinActors() {
|
||||||
case builtin.StorageMarketActorCodeID:
|
if actor.Code() == act {
|
||||||
f = market.Actor{}.Exports()[method]
|
target = actor
|
||||||
case builtin.StorageMinerActorCodeID:
|
}
|
||||||
f = miner2.Actor{}.Exports()[method]
|
|
||||||
case builtin.StoragePowerActorCodeID:
|
|
||||||
f = power.Actor{}.Exports()[method]
|
|
||||||
case builtin.MultisigActorCodeID:
|
|
||||||
f = multisig.Actor{}.Exports()[method]
|
|
||||||
case builtin.PaymentChannelActorCodeID:
|
|
||||||
f = paych.Actor{}.Exports()[method]
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("the lazy devs didnt add support for that actor to this call yet")
|
|
||||||
}
|
}
|
||||||
|
if target == nil {
|
||||||
|
return nil, fmt.Errorf("unknown actor %s", act)
|
||||||
|
}
|
||||||
|
methods := target.Exports()
|
||||||
|
if uint64(len(methods)) <= method || methods[method] == nil {
|
||||||
|
return nil, fmt.Errorf("unknown method %d for actor %s", method, act)
|
||||||
|
}
|
||||||
|
|
||||||
|
f := methods[method]
|
||||||
|
|
||||||
rf := reflect.TypeOf(f)
|
rf := reflect.TypeOf(f)
|
||||||
if rf.NumIn() != 3 {
|
if rf.NumIn() != 3 {
|
||||||
|
@ -180,11 +180,13 @@ func SyncWait(ctx context.Context, napi api.FullNode) error {
|
|||||||
ss := state.ActiveSyncs[working]
|
ss := state.ActiveSyncs[working]
|
||||||
|
|
||||||
var target []cid.Cid
|
var target []cid.Cid
|
||||||
|
var theight abi.ChainEpoch
|
||||||
if ss.Target != nil {
|
if ss.Target != nil {
|
||||||
target = ss.Target.Cids()
|
target = ss.Target.Cids()
|
||||||
|
theight = ss.Target.Height()
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("\r\x1b[2KWorker %d: Target: %s\tState: %s\tHeight: %d", working, target, chain.SyncStageString(ss.Stage), ss.Height)
|
fmt.Printf("\r\x1b[2KWorker %d: Target Height: %d\tTarget: %s\tState: %s\tHeight: %d", working, theight, target, chain.SyncStageString(ss.Stage), ss.Height)
|
||||||
|
|
||||||
if time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs) {
|
if time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs) {
|
||||||
fmt.Println("\nDone!")
|
fmt.Println("\nDone!")
|
||||||
|
@ -254,7 +254,9 @@ func (p *Processor) fetchMessages(ctx context.Context, blocks map[cid.Cid]*types
|
|||||||
parmap.Par(50, parmap.MapArr(blocks), func(header *types.BlockHeader) {
|
parmap.Par(50, parmap.MapArr(blocks), func(header *types.BlockHeader) {
|
||||||
msgs, err := p.node.ChainGetBlockMessages(ctx, header.Cid())
|
msgs, err := p.node.ChainGetBlockMessages(ctx, header.Cid())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
log.Error(err)
|
||||||
|
log.Debugw("ChainGetBlockMessages", "header_cid", header.Cid())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
vmm := make([]*types.Message, 0, len(msgs.Cids))
|
vmm := make([]*types.Message, 0, len(msgs.Cids))
|
||||||
@ -290,11 +292,15 @@ func (p *Processor) fetchParentReceipts(ctx context.Context, toSync map[cid.Cid]
|
|||||||
parmap.Par(50, parmap.MapArr(toSync), func(header *types.BlockHeader) {
|
parmap.Par(50, parmap.MapArr(toSync), func(header *types.BlockHeader) {
|
||||||
recs, err := p.node.ChainGetParentReceipts(ctx, header.Cid())
|
recs, err := p.node.ChainGetParentReceipts(ctx, header.Cid())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
log.Error(err)
|
||||||
|
log.Debugw("ChainGetParentReceipts", "header_cid", header.Cid())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
msgs, err := p.node.ChainGetParentMessages(ctx, header.Cid())
|
msgs, err := p.node.ChainGetParentMessages(ctx, header.Cid())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
log.Error(err)
|
||||||
|
log.Debugw("ChainGetParentMessages", "header_cid", header.Cid())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
lk.Lock()
|
lk.Lock()
|
||||||
|
@ -246,7 +246,8 @@ func (p *Processor) collectActorChanges(ctx context.Context, toProcess map[cid.C
|
|||||||
|
|
||||||
pts, err := p.node.ChainGetTipSet(ctx, types.NewTipSetKey(bh.Parents...))
|
pts, err := p.node.ChainGetTipSet(ctx, types.NewTipSetKey(bh.Parents...))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
log.Error(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if pts.ParentState().Equals(bh.ParentStateRoot) {
|
if pts.ParentState().Equals(bh.ParentStateRoot) {
|
||||||
@ -260,7 +261,9 @@ func (p *Processor) collectActorChanges(ctx context.Context, toProcess map[cid.C
|
|||||||
// a separate strategy for deleted actors
|
// a separate strategy for deleted actors
|
||||||
changes, err = p.node.StateChangedActors(ctx, pts.ParentState(), bh.ParentStateRoot)
|
changes, err = p.node.StateChangedActors(ctx, pts.ParentState(), bh.ParentStateRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
log.Error(err)
|
||||||
|
log.Debugw("StateChangedActors", "grandparent_state", pts.ParentState(), "parent_state", bh.ParentStateRoot)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// record the state of all actors that have changed
|
// record the state of all actors that have changed
|
||||||
@ -271,7 +274,9 @@ func (p *Processor) collectActorChanges(ctx context.Context, toProcess map[cid.C
|
|||||||
// ignore actors that were deleted.
|
// ignore actors that were deleted.
|
||||||
has, err := p.node.ChainHasObj(ctx, act.Head)
|
has, err := p.node.ChainHasObj(ctx, act.Head)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Error(err)
|
||||||
|
log.Debugw("ChanHasObj", "actor_head", act.Head)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if !has {
|
if !has {
|
||||||
continue
|
continue
|
||||||
@ -279,19 +284,24 @@ func (p *Processor) collectActorChanges(ctx context.Context, toProcess map[cid.C
|
|||||||
|
|
||||||
addr, err := address.NewFromString(a)
|
addr, err := address.NewFromString(a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err.Error())
|
log.Error(err)
|
||||||
|
log.Debugw("NewFromString", "address_string", a)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ast, err := p.node.StateReadState(ctx, addr, pts.Key())
|
ast, err := p.node.StateReadState(ctx, addr, pts.Key())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err.Error())
|
log.Error(err)
|
||||||
|
log.Debugw("StateReadState", "address_string", a, "parent_tipset_key", pts.Key())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO look here for an empty state, maybe thats a sign the actor was deleted?
|
// TODO look here for an empty state, maybe thats a sign the actor was deleted?
|
||||||
|
|
||||||
state, err := json.Marshal(ast.State)
|
state, err := json.Marshal(ast.State)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
log.Error(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
outMu.Lock()
|
outMu.Lock()
|
||||||
@ -324,10 +334,10 @@ func (p *Processor) unprocessedBlocks(ctx context.Context, batch int) (map[cid.C
|
|||||||
}()
|
}()
|
||||||
rows, err := p.db.Query(`
|
rows, err := p.db.Query(`
|
||||||
with toProcess as (
|
with toProcess as (
|
||||||
select blocks.cid, blocks.height, rank() over (order by height) as rnk
|
select b.cid, b.height, rank() over (order by height) as rnk
|
||||||
from blocks
|
from blocks_synced bs
|
||||||
left join blocks_synced bs on blocks.cid = bs.cid
|
left join blocks b on bs.cid = b.cid
|
||||||
where bs.processed_at is null and blocks.height > 0
|
where bs.processed_at is null and b.height > 0
|
||||||
)
|
)
|
||||||
select cid
|
select cid
|
||||||
from toProcess
|
from toProcess
|
||||||
|
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
@ -345,6 +346,10 @@ var dealsListCmd = &cli.Command{
|
|||||||
Name: "verbose",
|
Name: "verbose",
|
||||||
Aliases: []string{"v"},
|
Aliases: []string{"v"},
|
||||||
},
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "watch",
|
||||||
|
Usage: "watch deal updates in real-time, rather than a one time list",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
api, closer, err := lcli.GetStorageMinerAPI(cctx)
|
api, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||||
@ -360,42 +365,83 @@ var dealsListCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(deals, func(i, j int) bool {
|
|
||||||
return deals[i].CreationTime.Time().Before(deals[j].CreationTime.Time())
|
|
||||||
})
|
|
||||||
|
|
||||||
w := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0)
|
|
||||||
|
|
||||||
verbose := cctx.Bool("verbose")
|
verbose := cctx.Bool("verbose")
|
||||||
|
watch := cctx.Bool("watch")
|
||||||
|
|
||||||
|
if watch {
|
||||||
|
updates, err := api.MarketGetDealUpdates(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
tm.Clear()
|
||||||
|
tm.MoveCursor(1, 1)
|
||||||
|
|
||||||
|
err = outputStorageDeals(tm.Output, deals, verbose)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tm.Flush()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil
|
||||||
|
case updated := <-updates:
|
||||||
|
var found bool
|
||||||
|
for i, existing := range deals {
|
||||||
|
if existing.ProposalCid.Equals(updated.ProposalCid) {
|
||||||
|
deals[i] = updated
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
deals = append(deals, updated)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputStorageDeals(os.Stdout, deals, verbose)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func outputStorageDeals(out io.Writer, deals []storagemarket.MinerDeal, verbose bool) error {
|
||||||
|
sort.Slice(deals, func(i, j int) bool {
|
||||||
|
return deals[i].CreationTime.Time().Before(deals[j].CreationTime.Time())
|
||||||
|
})
|
||||||
|
|
||||||
|
w := tabwriter.NewWriter(out, 2, 4, 2, ' ', 0)
|
||||||
|
|
||||||
|
if verbose {
|
||||||
|
_, _ = fmt.Fprintf(w, "Creation\tProposalCid\tDealId\tState\tClient\tSize\tPrice\tDuration\tMessage\n")
|
||||||
|
} else {
|
||||||
|
_, _ = fmt.Fprintf(w, "ProposalCid\tDealId\tState\tClient\tSize\tPrice\tDuration\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, deal := range deals {
|
||||||
|
propcid := deal.ProposalCid.String()
|
||||||
|
if !verbose {
|
||||||
|
propcid = "..." + propcid[len(propcid)-8:]
|
||||||
|
}
|
||||||
|
|
||||||
|
fil := types.FIL(types.BigMul(deal.Proposal.StoragePricePerEpoch, types.NewInt(uint64(deal.Proposal.Duration()))))
|
||||||
|
|
||||||
if verbose {
|
if verbose {
|
||||||
_, _ = fmt.Fprintf(w, "Creation\tProposalCid\tDealId\tState\tClient\tSize\tPrice\tDuration\tMessage\n")
|
_, _ = fmt.Fprintf(w, "%s\t", deal.CreationTime.Time().Format(time.Stamp))
|
||||||
} else {
|
|
||||||
_, _ = fmt.Fprintf(w, "ProposalCid\tDealId\tState\tClient\tSize\tPrice\tDuration\n")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, deal := range deals {
|
_, _ = fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\t%s\t%s", propcid, deal.DealID, storagemarket.DealStates[deal.State], deal.Proposal.Client, units.BytesSize(float64(deal.Proposal.PieceSize)), fil, deal.Proposal.Duration())
|
||||||
propcid := deal.ProposalCid.String()
|
if verbose {
|
||||||
if !verbose {
|
_, _ = fmt.Fprintf(w, "\t%s", deal.Message)
|
||||||
propcid = "..." + propcid[len(propcid)-8:]
|
|
||||||
}
|
|
||||||
|
|
||||||
fil := types.FIL(types.BigMul(deal.Proposal.StoragePricePerEpoch, types.NewInt(uint64(deal.Proposal.Duration()))))
|
|
||||||
|
|
||||||
if verbose {
|
|
||||||
_, _ = fmt.Fprintf(w, "%s\t", deal.CreationTime.Time().Format(time.Stamp))
|
|
||||||
}
|
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\t%s\t%s", propcid, deal.DealID, storagemarket.DealStates[deal.State], deal.Proposal.Client, units.BytesSize(float64(deal.Proposal.PieceSize)), fil, deal.Proposal.Duration())
|
|
||||||
if verbose {
|
|
||||||
_, _ = fmt.Fprintf(w, "\t%s", deal.Message)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, _ = fmt.Fprintln(w)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return w.Flush()
|
_, _ = fmt.Fprintln(w)
|
||||||
},
|
}
|
||||||
|
|
||||||
|
return w.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
var getBlocklistCmd = &cli.Command{
|
var getBlocklistCmd = &cli.Command{
|
||||||
|
@ -2,7 +2,8 @@ package conformance
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
@ -12,7 +13,6 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/lib/blockstore"
|
"github.com/filecoin-project/lotus/lib/blockstore"
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
"github.com/filecoin-project/specs-actors/actors/puppet"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/test-vectors/chaos"
|
"github.com/filecoin-project/test-vectors/chaos"
|
||||||
"github.com/filecoin-project/test-vectors/schema"
|
"github.com/filecoin-project/test-vectors/schema"
|
||||||
@ -80,11 +80,14 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, preroot
|
|||||||
}
|
}
|
||||||
switch msg.From.Protocol() {
|
switch msg.From.Protocol() {
|
||||||
case address.SECP256K1:
|
case address.SECP256K1:
|
||||||
sb.SecpkMessages = append(sb.SecpkMessages, msg)
|
sb.SecpkMessages = append(sb.SecpkMessages, toChainMsg(msg))
|
||||||
case address.BLS:
|
case address.BLS:
|
||||||
sb.BlsMessages = append(sb.BlsMessages, msg)
|
sb.BlsMessages = append(sb.BlsMessages, toChainMsg(msg))
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("from account is not secpk nor bls: %s", msg.From)
|
// sneak in messages originating from other addresses as both kinds.
|
||||||
|
// these should fail, as they are actually invalid senders.
|
||||||
|
sb.SecpkMessages = append(sb.SecpkMessages, msg)
|
||||||
|
sb.BlsMessages = append(sb.BlsMessages, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
blocks = append(blocks, sb)
|
blocks = append(blocks, sb)
|
||||||
@ -133,17 +136,14 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, preroot cid.Cid, epoch
|
|||||||
|
|
||||||
invoker := vm.NewInvoker()
|
invoker := vm.NewInvoker()
|
||||||
|
|
||||||
// add support for the puppet and chaos actors.
|
// register the chaos actor if required by the vector.
|
||||||
if puppetOn, ok := d.selector["puppet_actor"]; ok && puppetOn == "true" {
|
|
||||||
invoker.Register(puppet.PuppetActorCodeID, puppet.Actor{}, puppet.State{})
|
|
||||||
}
|
|
||||||
if chaosOn, ok := d.selector["chaos_actor"]; ok && chaosOn == "true" {
|
if chaosOn, ok := d.selector["chaos_actor"]; ok && chaosOn == "true" {
|
||||||
invoker.Register(chaos.ChaosActorCodeCID, chaos.Actor{}, chaos.State{})
|
invoker.Register(chaos.ChaosActorCodeCID, chaos.Actor{}, chaos.State{})
|
||||||
}
|
}
|
||||||
|
|
||||||
lvm.SetInvoker(invoker)
|
lvm.SetInvoker(invoker)
|
||||||
|
|
||||||
ret, err := lvm.ApplyMessage(d.ctx, msg)
|
ret, err := lvm.ApplyMessage(d.ctx, toChainMsg(msg))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, cid.Undef, err
|
return nil, cid.Undef, err
|
||||||
}
|
}
|
||||||
@ -151,3 +151,22 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, preroot cid.Cid, epoch
|
|||||||
root, err := lvm.Flush(d.ctx)
|
root, err := lvm.Flush(d.ctx)
|
||||||
return ret, root, err
|
return ret, root, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// toChainMsg injects a synthetic 0-filled signature of the right length to
|
||||||
|
// messages that originate from secp256k senders, leaving all
|
||||||
|
// others untouched.
|
||||||
|
// TODO: generate a signature in the DSL so that it's encoded in
|
||||||
|
// the test vector.
|
||||||
|
func toChainMsg(msg *types.Message) (ret types.ChainMsg) {
|
||||||
|
ret = msg
|
||||||
|
if msg.From.Protocol() == address.SECP256K1 {
|
||||||
|
ret = &types.SignedMessage{
|
||||||
|
Message: *msg,
|
||||||
|
Signature: crypto.Signature{
|
||||||
|
Type: crypto.SigTypeSecp256k1,
|
||||||
|
Data: make([]byte, 65),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
@ -84,7 +84,11 @@
|
|||||||
* [MsigSwapPropose](#MsigSwapPropose)
|
* [MsigSwapPropose](#MsigSwapPropose)
|
||||||
* [Net](#Net)
|
* [Net](#Net)
|
||||||
* [NetAddrsListen](#NetAddrsListen)
|
* [NetAddrsListen](#NetAddrsListen)
|
||||||
|
* [NetAgentVersion](#NetAgentVersion)
|
||||||
* [NetAutoNatStatus](#NetAutoNatStatus)
|
* [NetAutoNatStatus](#NetAutoNatStatus)
|
||||||
|
* [NetBandwidthStats](#NetBandwidthStats)
|
||||||
|
* [NetBandwidthStatsByPeer](#NetBandwidthStatsByPeer)
|
||||||
|
* [NetBandwidthStatsByProtocol](#NetBandwidthStatsByProtocol)
|
||||||
* [NetConnect](#NetConnect)
|
* [NetConnect](#NetConnect)
|
||||||
* [NetConnectedness](#NetConnectedness)
|
* [NetConnectedness](#NetConnectedness)
|
||||||
* [NetDisconnect](#NetDisconnect)
|
* [NetDisconnect](#NetDisconnect)
|
||||||
@ -93,6 +97,7 @@
|
|||||||
* [NetPubsubScores](#NetPubsubScores)
|
* [NetPubsubScores](#NetPubsubScores)
|
||||||
* [Paych](#Paych)
|
* [Paych](#Paych)
|
||||||
* [PaychAllocateLane](#PaychAllocateLane)
|
* [PaychAllocateLane](#PaychAllocateLane)
|
||||||
|
* [PaychAvailableFunds](#PaychAvailableFunds)
|
||||||
* [PaychCollect](#PaychCollect)
|
* [PaychCollect](#PaychCollect)
|
||||||
* [PaychGet](#PaychGet)
|
* [PaychGet](#PaychGet)
|
||||||
* [PaychGetWaitReady](#PaychGetWaitReady)
|
* [PaychGetWaitReady](#PaychGetWaitReady)
|
||||||
@ -2044,6 +2049,20 @@ Response:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### NetAgentVersion
|
||||||
|
|
||||||
|
|
||||||
|
Perms: read
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
"12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf"
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Response: `"string value"`
|
||||||
|
|
||||||
### NetAutoNatStatus
|
### NetAutoNatStatus
|
||||||
|
|
||||||
|
|
||||||
@ -2059,6 +2078,61 @@ Response:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### NetBandwidthStats
|
||||||
|
|
||||||
|
|
||||||
|
Perms: read
|
||||||
|
|
||||||
|
Inputs: `null`
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"TotalIn": 9,
|
||||||
|
"TotalOut": 9,
|
||||||
|
"RateIn": 12.3,
|
||||||
|
"RateOut": 12.3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### NetBandwidthStatsByPeer
|
||||||
|
|
||||||
|
|
||||||
|
Perms: read
|
||||||
|
|
||||||
|
Inputs: `null`
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"12D3KooWSXmXLJmBR1M7i9RW9GQPNUhZSzXKzxDHWtAgNuJAbyEJ": {
|
||||||
|
"TotalIn": 174000,
|
||||||
|
"TotalOut": 12500,
|
||||||
|
"RateIn": 100,
|
||||||
|
"RateOut": 50
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### NetBandwidthStatsByProtocol
|
||||||
|
|
||||||
|
|
||||||
|
Perms: read
|
||||||
|
|
||||||
|
Inputs: `null`
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"/fil/hello/1.0.0": {
|
||||||
|
"TotalIn": 174000,
|
||||||
|
"TotalOut": 12500,
|
||||||
|
"RateIn": 100,
|
||||||
|
"RateOut": 50
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### NetConnect
|
### NetConnect
|
||||||
|
|
||||||
|
|
||||||
@ -2160,6 +2234,30 @@ Inputs:
|
|||||||
|
|
||||||
Response: `42`
|
Response: `42`
|
||||||
|
|
||||||
|
### PaychAvailableFunds
|
||||||
|
There are not yet any comments for this method.
|
||||||
|
|
||||||
|
Perms: sign
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
"t01234"
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Channel": "\u003cempty\u003e",
|
||||||
|
"ConfirmedAmt": "0",
|
||||||
|
"PendingAmt": "0",
|
||||||
|
"PendingWaitSentinel": null,
|
||||||
|
"QueuedAmt": "0",
|
||||||
|
"VoucherReedeemedAmt": "0"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### PaychCollect
|
### PaychCollect
|
||||||
There are not yet any comments for this method.
|
There are not yet any comments for this method.
|
||||||
|
|
||||||
@ -2415,24 +2513,27 @@ Inputs:
|
|||||||
Response:
|
Response:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"ChannelAddr": "t01234",
|
"Voucher": {
|
||||||
"TimeLockMin": 10101,
|
"ChannelAddr": "t01234",
|
||||||
"TimeLockMax": 10101,
|
"TimeLockMin": 10101,
|
||||||
"SecretPreimage": "Ynl0ZSBhcnJheQ==",
|
"TimeLockMax": 10101,
|
||||||
"Extra": {
|
"SecretPreimage": "Ynl0ZSBhcnJheQ==",
|
||||||
"Actor": "t01234",
|
"Extra": {
|
||||||
"Method": 1,
|
"Actor": "t01234",
|
||||||
"Data": "Ynl0ZSBhcnJheQ=="
|
"Method": 1,
|
||||||
|
"Data": "Ynl0ZSBhcnJheQ=="
|
||||||
|
},
|
||||||
|
"Lane": 42,
|
||||||
|
"Nonce": 42,
|
||||||
|
"Amount": "0",
|
||||||
|
"MinSettleHeight": 10101,
|
||||||
|
"Merges": null,
|
||||||
|
"Signature": {
|
||||||
|
"Type": 2,
|
||||||
|
"Data": "Ynl0ZSBhcnJheQ=="
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Lane": 42,
|
"Shortfall": "0"
|
||||||
"Nonce": 42,
|
|
||||||
"Amount": "0",
|
|
||||||
"MinSettleHeight": 10101,
|
|
||||||
"Merges": null,
|
|
||||||
"Signature": {
|
|
||||||
"Type": 2,
|
|
||||||
"Data": "Ynl0ZSBhcnJheQ=="
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ Note that payment channels and vouchers can be used for any situation in which t
|
|||||||
For example a client creates a payment channel to a provider with value 10 FIL.
|
For example a client creates a payment channel to a provider with value 10 FIL.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ lotus paych get <client addr> <provider addr> 10
|
$ lotus paych add-funds <client addr> <provider addr> 10
|
||||||
<channel addr>
|
<channel addr>
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -51,10 +51,10 @@ $ lotus paych voucher create <channel addr> 4
|
|||||||
The client sends the voucher to the provider and the provider adds the voucher and sends back more data.
|
The client sends the voucher to the provider and the provider adds the voucher and sends back more data.
|
||||||
etc.
|
etc.
|
||||||
|
|
||||||
The client can add value to the channel after it has been created by calling `paych get` with the same client and provider addresses.
|
The client can add value to the channel after it has been created by calling `paych add-funds` with the same client and provider addresses.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ lotus paych get <client addr> <provider addr> 5
|
$ lotus paych add-funds <client addr> <provider addr> 5
|
||||||
<channel addr> # Same address as above. Channel now has 15
|
<channel addr> # Same address as above. Channel now has 15
|
||||||
```
|
```
|
||||||
|
|
||||||
|
2
extern/test-vectors
vendored
2
extern/test-vectors
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 9806d09b005dbaa0d08a6944aca67dd5ad2cd3b3
|
Subproject commit 84da0a5ea1256a6e66bcbf73542c93e4916d6356
|
7
go.mod
7
go.mod
@ -2,7 +2,7 @@ module github.com/filecoin-project/lotus
|
|||||||
|
|
||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
replace github.com/supranational/blst => github.com/filecoin-project/blst v0.1.2-adx
|
replace github.com/supranational/blst => github.com/supranational/blst v0.1.2-alpha.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
contrib.go.opencensus.io/exporter/jaeger v0.1.0
|
contrib.go.opencensus.io/exporter/jaeger v0.1.0
|
||||||
@ -18,6 +18,7 @@ require (
|
|||||||
github.com/docker/go-units v0.4.0
|
github.com/docker/go-units v0.4.0
|
||||||
github.com/drand/drand v1.0.3-0.20200714175734-29705eaf09d4
|
github.com/drand/drand v1.0.3-0.20200714175734-29705eaf09d4
|
||||||
github.com/drand/kyber v1.1.1
|
github.com/drand/kyber v1.1.1
|
||||||
|
github.com/dustin/go-humanize v1.0.0
|
||||||
github.com/elastic/go-sysinfo v1.3.0
|
github.com/elastic/go-sysinfo v1.3.0
|
||||||
github.com/fatih/color v1.8.0
|
github.com/fatih/color v1.8.0
|
||||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef
|
github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef
|
||||||
@ -28,7 +29,7 @@ require (
|
|||||||
github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03
|
github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03
|
||||||
github.com/filecoin-project/go-data-transfer v0.6.3
|
github.com/filecoin-project/go-data-transfer v0.6.3
|
||||||
github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f
|
github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f
|
||||||
github.com/filecoin-project/go-fil-markets v0.5.8
|
github.com/filecoin-project/go-fil-markets v0.5.9
|
||||||
github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52
|
github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52
|
||||||
github.com/filecoin-project/go-multistore v0.0.3
|
github.com/filecoin-project/go-multistore v0.0.3
|
||||||
github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6
|
github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6
|
||||||
@ -39,7 +40,7 @@ require (
|
|||||||
github.com/filecoin-project/specs-actors v0.9.3
|
github.com/filecoin-project/specs-actors v0.9.3
|
||||||
github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401
|
github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401
|
||||||
github.com/filecoin-project/statediff v0.0.1
|
github.com/filecoin-project/statediff v0.0.1
|
||||||
github.com/filecoin-project/test-vectors v0.0.0-20200902131127-9806d09b005d
|
github.com/filecoin-project/test-vectors v0.0.0-20200903223506-84da0a5ea125
|
||||||
github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1
|
github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1
|
||||||
github.com/go-kit/kit v0.10.0
|
github.com/go-kit/kit v0.10.0
|
||||||
github.com/google/uuid v1.1.1
|
github.com/google/uuid v1.1.1
|
||||||
|
14
go.sum
14
go.sum
@ -215,8 +215,6 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
|
|||||||
github.com/fatih/color v1.8.0 h1:5bzFgL+oy7JITMTxUPJ00n7VxmYd/PdMp5mHFX40/RY=
|
github.com/fatih/color v1.8.0 h1:5bzFgL+oy7JITMTxUPJ00n7VxmYd/PdMp5mHFX40/RY=
|
||||||
github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8=
|
github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8=
|
||||||
github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E=
|
github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E=
|
||||||
github.com/filecoin-project/blst v0.1.2-adx h1:qyirtiGFTN/C17y4xlCFAblgw2OXhW8+wtnLwV27/cM=
|
|
||||||
github.com/filecoin-project/blst v0.1.2-adx/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
|
|
||||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef h1:MtQRSnJLsQOOlmsd/Ua5KWXimpxcaa715h6FUh/eJPY=
|
github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef h1:MtQRSnJLsQOOlmsd/Ua5KWXimpxcaa715h6FUh/eJPY=
|
||||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef/go.mod h1:SMj5VK1pYgqC8FXVEtOBRTc+9AIrYu+C+K3tAXi2Rk8=
|
github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef/go.mod h1:SMj5VK1pYgqC8FXVEtOBRTc+9AIrYu+C+K3tAXi2Rk8=
|
||||||
github.com/filecoin-project/go-address v0.0.0-20200107215422-da8eea2842b5/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0=
|
github.com/filecoin-project/go-address v0.0.0-20200107215422-da8eea2842b5/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0=
|
||||||
@ -248,6 +246,8 @@ github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go
|
|||||||
github.com/filecoin-project/go-fil-markets v0.5.6-0.20200814234959-80b1788108ac/go.mod h1:umicPCaN99ysHTiYOmwhuLxTFbOwcsI+mdw/t96vvM4=
|
github.com/filecoin-project/go-fil-markets v0.5.6-0.20200814234959-80b1788108ac/go.mod h1:umicPCaN99ysHTiYOmwhuLxTFbOwcsI+mdw/t96vvM4=
|
||||||
github.com/filecoin-project/go-fil-markets v0.5.8 h1:uwl0QNUVmmSlUQfxshpj21Dmhh6WKTQNhnb1GMfdp18=
|
github.com/filecoin-project/go-fil-markets v0.5.8 h1:uwl0QNUVmmSlUQfxshpj21Dmhh6WKTQNhnb1GMfdp18=
|
||||||
github.com/filecoin-project/go-fil-markets v0.5.8/go.mod h1:6ZX1vbZbnukbVQ8tCB/MmEizuW/bmRX7SpGAltU3KVg=
|
github.com/filecoin-project/go-fil-markets v0.5.8/go.mod h1:6ZX1vbZbnukbVQ8tCB/MmEizuW/bmRX7SpGAltU3KVg=
|
||||||
|
github.com/filecoin-project/go-fil-markets v0.5.9 h1:iIO17UfIjUCiB37TRwgiBwAyfJJwHb8e8uAfu7F37gc=
|
||||||
|
github.com/filecoin-project/go-fil-markets v0.5.9/go.mod h1:/cb1IoaiHhwFEWyIAPm9yN6Z+MiPujFZBT8BGH7LwB8=
|
||||||
github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200817153016-2ea5cbaf5ec0/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4=
|
github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200817153016-2ea5cbaf5ec0/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4=
|
||||||
github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 h1:FXtCp0ybqdQL9knb3OGDpkNTaBbPxgkqPeWKotUwkH0=
|
github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 h1:FXtCp0ybqdQL9knb3OGDpkNTaBbPxgkqPeWKotUwkH0=
|
||||||
github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4=
|
github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4=
|
||||||
@ -268,7 +268,7 @@ github.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZO
|
|||||||
github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b h1:fkRZSPrYpk42PV3/lIXiL0LHetxde7vyYYvSsttQtfg=
|
github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b h1:fkRZSPrYpk42PV3/lIXiL0LHetxde7vyYYvSsttQtfg=
|
||||||
github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8=
|
github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8=
|
||||||
github.com/filecoin-project/lotus v0.4.3-0.20200820203717-d1718369a182/go.mod h1:biFZPQ/YyQGfkHUmHMiaNf2hnD6zm1+OAXPQYQ61Zkg=
|
github.com/filecoin-project/lotus v0.4.3-0.20200820203717-d1718369a182/go.mod h1:biFZPQ/YyQGfkHUmHMiaNf2hnD6zm1+OAXPQYQ61Zkg=
|
||||||
github.com/filecoin-project/lotus v0.5.8-0.20200902130912-0962292f920e/go.mod h1:OkZ5aUqs+fFnJOq9243WJDsTa9c3/Ae67NIAwVhAB+0=
|
github.com/filecoin-project/lotus v0.5.8-0.20200903221953-ada5e6ae68cf/go.mod h1:wxuzS4ozpCFThia18G+J5P0Jp/DSiq9ezzJF1yvZuP4=
|
||||||
github.com/filecoin-project/sector-storage v0.0.0-20200712023225-1d67dcfa3c15/go.mod h1:salgVdX7qeXFo/xaiEQE29J4pPkjn71T0kt0n+VDBzo=
|
github.com/filecoin-project/sector-storage v0.0.0-20200712023225-1d67dcfa3c15/go.mod h1:salgVdX7qeXFo/xaiEQE29J4pPkjn71T0kt0n+VDBzo=
|
||||||
github.com/filecoin-project/sector-storage v0.0.0-20200730050024-3ee28c3b6d9a/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA=
|
github.com/filecoin-project/sector-storage v0.0.0-20200730050024-3ee28c3b6d9a/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA=
|
||||||
github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0 h1:E1fZ27fhKK05bhZItfTwqr1i05vXnEZJznQFEYwEEUU=
|
github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0 h1:E1fZ27fhKK05bhZItfTwqr1i05vXnEZJznQFEYwEEUU=
|
||||||
@ -687,6 +687,8 @@ github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9
|
|||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
github.com/jonboulle/clockwork v0.1.1-0.20190114141812-62fb9bc030d1 h1:qBCV/RLV02TSfQa7tFmxTihnG+u+7JXByOkhlkR5rmQ=
|
github.com/jonboulle/clockwork v0.1.1-0.20190114141812-62fb9bc030d1 h1:qBCV/RLV02TSfQa7tFmxTihnG+u+7JXByOkhlkR5rmQ=
|
||||||
github.com/jonboulle/clockwork v0.1.1-0.20190114141812-62fb9bc030d1/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.1-0.20190114141812-62fb9bc030d1/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
|
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
|
||||||
|
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||||
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
|
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
|
||||||
github.com/jsimonetti/rtnetlink v0.0.0-20190830100107-3784a6c7c552/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
|
github.com/jsimonetti/rtnetlink v0.0.0-20190830100107-3784a6c7c552/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
|
||||||
@ -824,6 +826,7 @@ github.com/libp2p/go-libp2p-core v0.6.1 h1:XS+Goh+QegCDojUZp00CaPMfiEADCrLjNZskW
|
|||||||
github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
|
github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
|
||||||
github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE=
|
github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE=
|
||||||
github.com/libp2p/go-libp2p-crypto v0.0.2/go.mod h1:eETI5OUfBnvARGOHrJz2eWNyTUxEGZnBxMcbUjfIj4I=
|
github.com/libp2p/go-libp2p-crypto v0.0.2/go.mod h1:eETI5OUfBnvARGOHrJz2eWNyTUxEGZnBxMcbUjfIj4I=
|
||||||
|
github.com/libp2p/go-libp2p-crypto v0.1.0 h1:k9MFy+o2zGDNGsaoZl0MA3iZ75qXxr9OOoAZF+sD5OQ=
|
||||||
github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI=
|
github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI=
|
||||||
github.com/libp2p/go-libp2p-daemon v0.2.2/go.mod h1:kyrpsLB2JeNYR2rvXSVWyY0iZuRIMhqzWR3im9BV6NQ=
|
github.com/libp2p/go-libp2p-daemon v0.2.2/go.mod h1:kyrpsLB2JeNYR2rvXSVWyY0iZuRIMhqzWR3im9BV6NQ=
|
||||||
github.com/libp2p/go-libp2p-discovery v0.0.1/go.mod h1:ZkkF9xIFRLA1xCc7bstYFkd80gBGK8Fc1JqGoU2i+zI=
|
github.com/libp2p/go-libp2p-discovery v0.0.1/go.mod h1:ZkkF9xIFRLA1xCc7bstYFkd80gBGK8Fc1JqGoU2i+zI=
|
||||||
@ -849,6 +852,7 @@ github.com/libp2p/go-libp2p-kbucket v0.4.2/go.mod h1:7sCeZx2GkNK1S6lQnGUW5JYZCFP
|
|||||||
github.com/libp2p/go-libp2p-loggables v0.0.1/go.mod h1:lDipDlBNYbpyqyPX/KcoO+eq0sJYEVR2JgOexcivchg=
|
github.com/libp2p/go-libp2p-loggables v0.0.1/go.mod h1:lDipDlBNYbpyqyPX/KcoO+eq0sJYEVR2JgOexcivchg=
|
||||||
github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8=
|
github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8=
|
||||||
github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90=
|
github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90=
|
||||||
|
github.com/libp2p/go-libp2p-metrics v0.0.1 h1:yumdPC/P2VzINdmcKZd0pciSUCpou+s0lwYCjBbzQZU=
|
||||||
github.com/libp2p/go-libp2p-metrics v0.0.1/go.mod h1:jQJ95SXXA/K1VZi13h52WZMa9ja78zjyy5rspMsC/08=
|
github.com/libp2p/go-libp2p-metrics v0.0.1/go.mod h1:jQJ95SXXA/K1VZi13h52WZMa9ja78zjyy5rspMsC/08=
|
||||||
github.com/libp2p/go-libp2p-mplex v0.1.1/go.mod h1:KUQWpGkCzfV7UIpi8SKsAVxyBgz1c9R5EvxgnwLsb/I=
|
github.com/libp2p/go-libp2p-mplex v0.1.1/go.mod h1:KUQWpGkCzfV7UIpi8SKsAVxyBgz1c9R5EvxgnwLsb/I=
|
||||||
github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo=
|
github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo=
|
||||||
@ -871,6 +875,7 @@ github.com/libp2p/go-libp2p-noise v0.1.1 h1:vqYQWvnIcHpIoWJKC7Al4D6Hgj0H012TuXRh
|
|||||||
github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM=
|
github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM=
|
||||||
github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo=
|
github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo=
|
||||||
github.com/libp2p/go-libp2p-peer v0.1.1/go.mod h1:jkF12jGB4Gk/IOo+yomm+7oLWxF278F7UnrYUQ1Q8es=
|
github.com/libp2p/go-libp2p-peer v0.1.1/go.mod h1:jkF12jGB4Gk/IOo+yomm+7oLWxF278F7UnrYUQ1Q8es=
|
||||||
|
github.com/libp2p/go-libp2p-peer v0.2.0 h1:EQ8kMjaCUwt/Y5uLgjT8iY2qg0mGUT0N1zUjer50DsY=
|
||||||
github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY=
|
github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY=
|
||||||
github.com/libp2p/go-libp2p-peerstore v0.0.1/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20=
|
github.com/libp2p/go-libp2p-peerstore v0.0.1/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20=
|
||||||
github.com/libp2p/go-libp2p-peerstore v0.0.6/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20=
|
github.com/libp2p/go-libp2p-peerstore v0.0.6/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20=
|
||||||
@ -887,6 +892,7 @@ github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuD
|
|||||||
github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k=
|
github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k=
|
||||||
github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA=
|
github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA=
|
||||||
github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s=
|
github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s=
|
||||||
|
github.com/libp2p/go-libp2p-protocol v0.1.0 h1:HdqhEyhg0ToCaxgMhnOmUO8snQtt/kQlcjVk3UoJU3c=
|
||||||
github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk=
|
github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk=
|
||||||
github.com/libp2p/go-libp2p-pubsub v0.1.1/go.mod h1:ZwlKzRSe1eGvSIdU5bD7+8RZN/Uzw0t1Bp9R1znpR/Q=
|
github.com/libp2p/go-libp2p-pubsub v0.1.1/go.mod h1:ZwlKzRSe1eGvSIdU5bD7+8RZN/Uzw0t1Bp9R1znpR/Q=
|
||||||
github.com/libp2p/go-libp2p-pubsub v0.3.2-0.20200527132641-c0712c6e92cf/go.mod h1:TxPOBuo1FPdsTjFnv+FGZbNbWYsp74Culx+4ViQpato=
|
github.com/libp2p/go-libp2p-pubsub v0.3.2-0.20200527132641-c0712c6e92cf/go.mod h1:TxPOBuo1FPdsTjFnv+FGZbNbWYsp74Culx+4ViQpato=
|
||||||
@ -1370,6 +1376,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
|||||||
github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/supranational/blst v0.1.2-alpha.1 h1:v0UqVlvbRNZIaSeMPr+T01kvTUq1h0EZuZ6gnDR1Mlg=
|
||||||
|
github.com/supranational/blst v0.1.2-alpha.1/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
|
||||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||||
|
@ -3,11 +3,14 @@ package retrievaladapter
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||||
"github.com/filecoin-project/go-fil-markets/shared"
|
"github.com/filecoin-project/go-fil-markets/shared"
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/multiformats/go-multiaddr"
|
"github.com/multiformats/go-multiaddr"
|
||||||
|
|
||||||
@ -56,7 +59,10 @@ func (rcn *retrievalClientNode) CreatePaymentVoucher(ctx context.Context, paymen
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return voucher, nil
|
if voucher.Voucher == nil {
|
||||||
|
return nil, xerrors.Errorf("Could not create voucher - shortfall: %d", voucher.Shortfall)
|
||||||
|
}
|
||||||
|
return voucher.Voucher, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rcn *retrievalClientNode) GetChainHead(ctx context.Context) (shared.TipSetToken, abi.ChainEpoch, error) {
|
func (rcn *retrievalClientNode) GetChainHead(ctx context.Context) (shared.TipSetToken, abi.ChainEpoch, error) {
|
||||||
|
@ -87,6 +87,7 @@ var (
|
|||||||
NatPortMapKey = special{8} // Libp2p option
|
NatPortMapKey = special{8} // Libp2p option
|
||||||
ConnectionManagerKey = special{9} // Libp2p option
|
ConnectionManagerKey = special{9} // Libp2p option
|
||||||
AutoNATSvcKey = special{10} // Libp2p option
|
AutoNATSvcKey = special{10} // Libp2p option
|
||||||
|
BandwidthReporterKey = special{11} // Libp2p option
|
||||||
)
|
)
|
||||||
|
|
||||||
type invoke int
|
type invoke int
|
||||||
@ -192,6 +193,7 @@ func libp2p() Option {
|
|||||||
Override(new(routing.Routing), lp2p.Routing),
|
Override(new(routing.Routing), lp2p.Routing),
|
||||||
|
|
||||||
Override(NatPortMapKey, lp2p.NatPortMap),
|
Override(NatPortMapKey, lp2p.NatPortMap),
|
||||||
|
Override(BandwidthReporterKey, lp2p.BandwidthCounter),
|
||||||
|
|
||||||
Override(ConnectionManagerKey, lp2p.ConnectionManager(50, 200, 20*time.Second, nil)),
|
Override(ConnectionManagerKey, lp2p.ConnectionManager(50, 200, 20*time.Second, nil)),
|
||||||
Override(AutoNATSvcKey, lp2p.AutoNATService),
|
Override(AutoNATSvcKey, lp2p.AutoNATService),
|
||||||
|
@ -9,8 +9,10 @@ import (
|
|||||||
|
|
||||||
"github.com/gbrlsnchs/jwt/v3"
|
"github.com/gbrlsnchs/jwt/v3"
|
||||||
"github.com/libp2p/go-libp2p-core/host"
|
"github.com/libp2p/go-libp2p-core/host"
|
||||||
|
metrics "github.com/libp2p/go-libp2p-core/metrics"
|
||||||
"github.com/libp2p/go-libp2p-core/network"
|
"github.com/libp2p/go-libp2p-core/network"
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
protocol "github.com/libp2p/go-libp2p-core/protocol"
|
||||||
swarm "github.com/libp2p/go-libp2p-swarm"
|
swarm "github.com/libp2p/go-libp2p-swarm"
|
||||||
basichost "github.com/libp2p/go-libp2p/p2p/host/basic"
|
basichost "github.com/libp2p/go-libp2p/p2p/host/basic"
|
||||||
ma "github.com/multiformats/go-multiaddr"
|
ma "github.com/multiformats/go-multiaddr"
|
||||||
@ -32,6 +34,7 @@ type CommonAPI struct {
|
|||||||
RawHost lp2p.RawHost
|
RawHost lp2p.RawHost
|
||||||
Host host.Host
|
Host host.Host
|
||||||
Router lp2p.BaseIpfsRouting
|
Router lp2p.BaseIpfsRouting
|
||||||
|
Reporter metrics.Reporter
|
||||||
Sk *dtypes.ScoreKeeper
|
Sk *dtypes.ScoreKeeper
|
||||||
ShutdownChan dtypes.ShutdownChan
|
ShutdownChan dtypes.ShutdownChan
|
||||||
}
|
}
|
||||||
@ -133,6 +136,35 @@ func (a *CommonAPI) NetAutoNatStatus(ctx context.Context) (i api.NatInfo, err er
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *CommonAPI) NetAgentVersion(ctx context.Context, p peer.ID) (string, error) {
|
||||||
|
ag, err := a.Host.Peerstore().Get(p, "AgentVersion")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ag == nil {
|
||||||
|
return "unknown", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return ag.(string), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *CommonAPI) NetBandwidthStats(ctx context.Context) (metrics.Stats, error) {
|
||||||
|
return a.Reporter.GetBandwidthTotals(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *CommonAPI) NetBandwidthStatsByPeer(ctx context.Context) (map[string]metrics.Stats, error) {
|
||||||
|
out := make(map[string]metrics.Stats)
|
||||||
|
for p, s := range a.Reporter.GetBandwidthByPeer() {
|
||||||
|
out[p.String()] = s
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *CommonAPI) NetBandwidthStatsByProtocol(ctx context.Context) (map[protocol.ID]metrics.Stats, error) {
|
||||||
|
return a.Reporter.GetBandwidthByProtocol(), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *CommonAPI) ID(context.Context) (peer.ID, error) {
|
func (a *CommonAPI) ID(context.Context) (peer.ID, error) {
|
||||||
return a.Host.ID(), nil
|
return a.Host.ID(), nil
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package full
|
package full
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -503,7 +504,11 @@ func (a *ChainAPI) ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk t
|
|||||||
out := make(chan []byte)
|
out := make(chan []byte)
|
||||||
go func() {
|
go func() {
|
||||||
defer w.Close() //nolint:errcheck // it is a pipe
|
defer w.Close() //nolint:errcheck // it is a pipe
|
||||||
if err := a.Chain.Export(ctx, ts, nroots, w); err != nil {
|
|
||||||
|
bw := bufio.NewWriterSize(w, 1<<20)
|
||||||
|
defer bw.Flush() //nolint:errcheck // it is a write to a pipe
|
||||||
|
|
||||||
|
if err := a.Chain.Export(ctx, ts, nroots, bw); err != nil {
|
||||||
log.Errorf("chain export call failed: %s", err)
|
log.Errorf("chain export call failed: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -512,7 +517,7 @@ func (a *ChainAPI) ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk t
|
|||||||
go func() {
|
go func() {
|
||||||
defer close(out)
|
defer close(out)
|
||||||
for {
|
for {
|
||||||
buf := make([]byte, 4096)
|
buf := make([]byte, 1<<20)
|
||||||
n, err := r.Read(buf)
|
n, err := r.Read(buf)
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
log.Errorf("chain export pipe read failed: %s", err)
|
log.Errorf("chain export pipe read failed: %s", err)
|
||||||
@ -522,6 +527,7 @@ func (a *ChainAPI) ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk t
|
|||||||
case out <- buf[:n]:
|
case out <- buf[:n]:
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
log.Warnf("export writer failed: %s", ctx.Err())
|
log.Warnf("export writer failed: %s", ctx.Err())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
return
|
return
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
||||||
@ -36,28 +37,11 @@ func (a *GasAPI) GasEstimateFeeCap(ctx context.Context, msg *types.Message, maxq
|
|||||||
tsk types.TipSetKey) (types.BigInt, error) {
|
tsk types.TipSetKey) (types.BigInt, error) {
|
||||||
ts := a.Chain.GetHeaviestTipSet()
|
ts := a.Chain.GetHeaviestTipSet()
|
||||||
|
|
||||||
var act types.Actor
|
|
||||||
err := a.Stmgr.WithParentState(ts, a.Stmgr.WithActor(msg.From, stmgr.GetActor(&act)))
|
|
||||||
if err != nil {
|
|
||||||
return types.NewInt(0), xerrors.Errorf("getting actor: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
parentBaseFee := ts.Blocks()[0].ParentBaseFee
|
parentBaseFee := ts.Blocks()[0].ParentBaseFee
|
||||||
increaseFactor := math.Pow(1.+1./float64(build.BaseFeeMaxChangeDenom), float64(maxqueueblks))
|
increaseFactor := math.Pow(1.+1./float64(build.BaseFeeMaxChangeDenom), float64(maxqueueblks))
|
||||||
|
|
||||||
feeInFuture := types.BigMul(parentBaseFee, types.NewInt(uint64(increaseFactor*(1<<8))))
|
feeInFuture := types.BigMul(parentBaseFee, types.NewInt(uint64(increaseFactor*(1<<8))))
|
||||||
feeInFuture = types.BigDiv(feeInFuture, types.NewInt(1<<8))
|
out := types.BigDiv(feeInFuture, types.NewInt(1<<8))
|
||||||
|
|
||||||
gasLimitBig := types.NewInt(uint64(msg.GasLimit))
|
|
||||||
maxAccepted := types.BigDiv(act.Balance, types.NewInt(MaxSpendOnFeeDenom))
|
|
||||||
expectedFee := types.BigMul(feeInFuture, gasLimitBig)
|
|
||||||
|
|
||||||
out := feeInFuture
|
|
||||||
if types.BigCmp(expectedFee, maxAccepted) > 0 {
|
|
||||||
log.Warnf("Expected fee for message higher than tolerance: %s > %s, setting to tolerance",
|
|
||||||
types.FIL(expectedFee), types.FIL(maxAccepted))
|
|
||||||
out = types.BigDiv(maxAccepted, gasLimitBig)
|
|
||||||
}
|
|
||||||
|
|
||||||
if msg.GasPremium != types.EmptyInt {
|
if msg.GasPremium != types.EmptyInt {
|
||||||
out = types.BigAdd(out, msg.GasPremium)
|
out = types.BigAdd(out, msg.GasPremium)
|
||||||
@ -225,3 +209,24 @@ func (a *GasAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message,
|
|||||||
|
|
||||||
return msg, nil
|
return msg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func capGasFee(msg *types.Message, maxFee abi.TokenAmount) {
|
||||||
|
if maxFee.Equals(big.Zero()) {
|
||||||
|
maxFee = types.NewInt(build.FilecoinPrecision / 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
gl := types.NewInt(uint64(msg.GasLimit))
|
||||||
|
totalFee := types.BigMul(msg.GasFeeCap, gl)
|
||||||
|
minerFee := types.BigMul(msg.GasPremium, gl)
|
||||||
|
|
||||||
|
if totalFee.LessThanEqual(maxFee) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// scale chain/miner fee down proportionally to fit in our budget
|
||||||
|
// TODO: there are probably smarter things we can do here to optimize
|
||||||
|
// message inclusion latency
|
||||||
|
|
||||||
|
msg.GasFeeCap = big.Div(maxFee, gl)
|
||||||
|
msg.GasPremium = big.Div(big.Div(big.Mul(minerFee, maxFee), totalFee), gl)
|
||||||
|
}
|
||||||
|
@ -8,9 +8,6 @@ import (
|
|||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/chain/messagepool"
|
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
@ -115,27 +112,6 @@ func (a *MpoolAPI) MpoolPush(ctx context.Context, smsg *types.SignedMessage) (ci
|
|||||||
return a.Mpool.Push(smsg)
|
return a.Mpool.Push(smsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func capGasFee(msg *types.Message, maxFee abi.TokenAmount) {
|
|
||||||
if maxFee.Equals(big.Zero()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
gl := types.NewInt(uint64(msg.GasLimit))
|
|
||||||
totalFee := types.BigMul(msg.GasFeeCap, gl)
|
|
||||||
minerFee := types.BigMul(msg.GasPremium, gl)
|
|
||||||
|
|
||||||
if totalFee.LessThanEqual(maxFee) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// scale chain/miner fee down proportionally to fit in our budget
|
|
||||||
// TODO: there are probably smarter things we can do here to optimize
|
|
||||||
// message inclusion latency
|
|
||||||
|
|
||||||
msg.GasFeeCap = big.Div(maxFee, gl)
|
|
||||||
msg.GasPremium = big.Div(big.Div(big.Mul(minerFee, maxFee), totalFee), gl)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec) (*types.SignedMessage, error) {
|
func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec) (*types.SignedMessage, error) {
|
||||||
{
|
{
|
||||||
fromA, err := a.Stmgr.ResolveToKeyAddress(ctx, msg.From, nil)
|
fromA, err := a.Stmgr.ResolveToKeyAddress(ctx, msg.From, nil)
|
||||||
|
@ -3,9 +3,10 @@ package paych
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
"golang.org/x/xerrors"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||||
@ -38,6 +39,10 @@ func (a *PaychAPI) PaychGet(ctx context.Context, from, to address.Address, amt t
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *PaychAPI) PaychAvailableFunds(from, to address.Address) (*api.ChannelAvailableFunds, error) {
|
||||||
|
return a.PaychMgr.AvailableFunds(from, to)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *PaychAPI) PaychGetWaitReady(ctx context.Context, sentinel cid.Cid) (address.Address, error) {
|
func (a *PaychAPI) PaychGetWaitReady(ctx context.Context, sentinel cid.Cid) (address.Address, error) {
|
||||||
return a.PaychMgr.GetPaychWaitReady(ctx, sentinel)
|
return a.PaychMgr.GetPaychWaitReady(ctx, sentinel)
|
||||||
}
|
}
|
||||||
@ -64,9 +69,7 @@ func (a *PaychAPI) PaychNewPayment(ctx context.Context, from, to address.Address
|
|||||||
svs := make([]*paych.SignedVoucher, len(vouchers))
|
svs := make([]*paych.SignedVoucher, len(vouchers))
|
||||||
|
|
||||||
for i, v := range vouchers {
|
for i, v := range vouchers {
|
||||||
sv, err := a.paychVoucherCreate(ctx, ch.Channel, paych.SignedVoucher{
|
sv, err := a.PaychMgr.CreateVoucher(ctx, ch.Channel, paych.SignedVoucher{
|
||||||
ChannelAddr: ch.Channel,
|
|
||||||
|
|
||||||
Amount: v.Amount,
|
Amount: v.Amount,
|
||||||
Lane: lane,
|
Lane: lane,
|
||||||
|
|
||||||
@ -78,8 +81,11 @@ func (a *PaychAPI) PaychNewPayment(ctx context.Context, from, to address.Address
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if sv.Voucher == nil {
|
||||||
|
return nil, xerrors.Errorf("Could not create voucher - shortfall of %d", sv.Shortfall)
|
||||||
|
}
|
||||||
|
|
||||||
svs[i] = sv
|
svs[i] = sv.Voucher
|
||||||
}
|
}
|
||||||
|
|
||||||
return &api.PaymentInfo{
|
return &api.PaymentInfo{
|
||||||
@ -129,41 +135,10 @@ func (a *PaychAPI) PaychVoucherAdd(ctx context.Context, ch address.Address, sv *
|
|||||||
// that will be used to create the voucher, so if previous vouchers exist, the
|
// that will be used to create the voucher, so if previous vouchers exist, the
|
||||||
// actual additional value of this voucher will only be the difference between
|
// actual additional value of this voucher will only be the difference between
|
||||||
// the two.
|
// the two.
|
||||||
func (a *PaychAPI) PaychVoucherCreate(ctx context.Context, pch address.Address, amt types.BigInt, lane uint64) (*paych.SignedVoucher, error) {
|
// If there are insufficient funds in the channel to create the voucher,
|
||||||
return a.paychVoucherCreate(ctx, pch, paych.SignedVoucher{ChannelAddr: pch, Amount: amt, Lane: lane})
|
// returns a nil voucher and the shortfall.
|
||||||
}
|
func (a *PaychAPI) PaychVoucherCreate(ctx context.Context, pch address.Address, amt types.BigInt, lane uint64) (*api.VoucherCreateResult, error) {
|
||||||
|
return a.PaychMgr.CreateVoucher(ctx, pch, paych.SignedVoucher{Amount: amt, Lane: lane})
|
||||||
func (a *PaychAPI) paychVoucherCreate(ctx context.Context, pch address.Address, voucher paych.SignedVoucher) (*paych.SignedVoucher, error) {
|
|
||||||
ci, err := a.PaychMgr.GetChannelInfo(pch)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("get channel info: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
nonce, err := a.PaychMgr.NextNonceForLane(ctx, pch, voucher.Lane)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("getting next nonce for lane: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sv := &voucher
|
|
||||||
sv.Nonce = nonce
|
|
||||||
|
|
||||||
vb, err := sv.SigningBytes()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
sig, err := a.WalletSign(ctx, ci.Control, vb)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
sv.Signature = sig
|
|
||||||
|
|
||||||
if _, err := a.PaychMgr.AddVoucherOutbound(ctx, pch, sv, nil, types.NewInt(0)); err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to persist voucher: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return sv, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *PaychAPI) PaychVoucherList(ctx context.Context, pch address.Address) ([]*paych.SignedVoucher, error) {
|
func (a *PaychAPI) PaychVoucherList(ctx context.Context, pch address.Address) ([]*paych.SignedVoucher, error) {
|
||||||
|
@ -320,14 +320,12 @@ func (sm *StorageMinerAPI) MarketListRetrievalDeals(ctx context.Context) ([]retr
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StorageMinerAPI) MarketGetDealUpdates(ctx context.Context, d cid.Cid) (<-chan storagemarket.MinerDeal, error) {
|
func (sm *StorageMinerAPI) MarketGetDealUpdates(ctx context.Context) (<-chan storagemarket.MinerDeal, error) {
|
||||||
results := make(chan storagemarket.MinerDeal)
|
results := make(chan storagemarket.MinerDeal)
|
||||||
unsub := sm.StorageProvider.SubscribeToEvents(func(evt storagemarket.ProviderEvent, deal storagemarket.MinerDeal) {
|
unsub := sm.StorageProvider.SubscribeToEvents(func(evt storagemarket.ProviderEvent, deal storagemarket.MinerDeal) {
|
||||||
if deal.ProposalCid.Equals(d) {
|
select {
|
||||||
select {
|
case results <- deal:
|
||||||
case results <- deal:
|
case <-ctx.Done():
|
||||||
case <-ctx.Done():
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -60,7 +60,7 @@ func (pm *Manager) accessorCacheKey(from address.Address, to address.Address) st
|
|||||||
// access a channel use the same lock (the lock on the accessor)
|
// access a channel use the same lock (the lock on the accessor)
|
||||||
func (pm *Manager) addAccessorToCache(from address.Address, to address.Address) *channelAccessor {
|
func (pm *Manager) addAccessorToCache(from address.Address, to address.Address) *channelAccessor {
|
||||||
key := pm.accessorCacheKey(from, to)
|
key := pm.accessorCacheKey(from, to)
|
||||||
ca := newChannelAccessor(pm)
|
ca := newChannelAccessor(pm, from, to)
|
||||||
// TODO: Use LRU
|
// TODO: Use LRU
|
||||||
pm.channels[key] = ca
|
pm.channels[key] = ca
|
||||||
return ca
|
return ca
|
||||||
|
@ -4,6 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/node/modules/helpers"
|
"github.com/filecoin-project/lotus/node/modules/helpers"
|
||||||
|
|
||||||
"github.com/ipfs/go-datastore"
|
"github.com/ipfs/go-datastore"
|
||||||
@ -49,6 +51,7 @@ type paychAPI interface {
|
|||||||
StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error)
|
StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error)
|
||||||
MpoolPushMessage(ctx context.Context, msg *types.Message, maxFee *api.MessageSendSpec) (*types.SignedMessage, error)
|
MpoolPushMessage(ctx context.Context, msg *types.Message, maxFee *api.MessageSendSpec) (*types.SignedMessage, error)
|
||||||
WalletHas(ctx context.Context, addr address.Address) (bool, error)
|
WalletHas(ctx context.Context, addr address.Address) (bool, error)
|
||||||
|
WalletSign(ctx context.Context, k address.Address, msg []byte) (*crypto.Signature, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// managerAPI defines all methods needed by the manager
|
// managerAPI defines all methods needed by the manager
|
||||||
@ -135,7 +138,16 @@ func (pm *Manager) GetPaych(ctx context.Context, from, to address.Address, amt t
|
|||||||
return address.Undef, cid.Undef, err
|
return address.Undef, cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return chanAccessor.getPaych(ctx, from, to, amt)
|
return chanAccessor.getPaych(ctx, amt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pm *Manager) AvailableFunds(from address.Address, to address.Address) (*api.ChannelAvailableFunds, error) {
|
||||||
|
chanAccessor, err := pm.accessorByFromTo(from, to)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return chanAccessor.availableFunds()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPaychWaitReady waits until the create channel / add funds message with the
|
// GetPaychWaitReady waits until the create channel / add funds message with the
|
||||||
@ -179,6 +191,15 @@ func (pm *Manager) GetChannelInfo(addr address.Address) (*ChannelInfo, error) {
|
|||||||
return ca.getChannelInfo(addr)
|
return ca.getChannelInfo(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pm *Manager) CreateVoucher(ctx context.Context, ch address.Address, voucher paych.SignedVoucher) (*api.VoucherCreateResult, error) {
|
||||||
|
ca, err := pm.accessorByAddress(ch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ca.createVoucher(ctx, ch, voucher)
|
||||||
|
}
|
||||||
|
|
||||||
// CheckVoucherValid checks if the given voucher is valid (is or could become spendable at some point).
|
// CheckVoucherValid checks if the given voucher is valid (is or could become spendable at some point).
|
||||||
// If the channel is not in the store, fetches the channel from state (and checks that
|
// If the channel is not in the store, fetches the channel from state (and checks that
|
||||||
// the channel To address is owned by the wallet).
|
// the channel To address is owned by the wallet).
|
||||||
@ -309,14 +330,6 @@ func (pm *Manager) ListVouchers(ctx context.Context, ch address.Address) ([]*Vou
|
|||||||
return ca.listVouchers(ctx, ch)
|
return ca.listVouchers(ctx, ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *Manager) NextNonceForLane(ctx context.Context, ch address.Address, lane uint64) (uint64, error) {
|
|
||||||
ca, err := pm.accessorByAddress(ch)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return ca.nextNonceForLane(ctx, ch, lane)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pm *Manager) Settle(ctx context.Context, addr address.Address) (cid.Cid, error) {
|
func (pm *Manager) Settle(ctx context.Context, addr address.Address) (cid.Cid, error) {
|
||||||
ca, err := pm.accessorByAddress(addr)
|
ca, err := pm.accessorByAddress(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -5,6 +5,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/lib/sigs"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||||
|
|
||||||
cbornode "github.com/ipfs/go-ipld-cbor"
|
cbornode "github.com/ipfs/go-ipld-cbor"
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
@ -132,6 +136,7 @@ type mockPaychAPI struct {
|
|||||||
waitingCalls map[cid.Cid]*waitingCall
|
waitingCalls map[cid.Cid]*waitingCall
|
||||||
waitingResponses map[cid.Cid]*waitingResponse
|
waitingResponses map[cid.Cid]*waitingResponse
|
||||||
wallet map[address.Address]struct{}
|
wallet map[address.Address]struct{}
|
||||||
|
signingKey []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMockPaychAPI() *mockPaychAPI {
|
func newMockPaychAPI() *mockPaychAPI {
|
||||||
@ -240,3 +245,17 @@ func (pchapi *mockPaychAPI) addWalletAddress(addr address.Address) {
|
|||||||
|
|
||||||
pchapi.wallet[addr] = struct{}{}
|
pchapi.wallet[addr] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pchapi *mockPaychAPI) WalletSign(ctx context.Context, k address.Address, msg []byte) (*crypto.Signature, error) {
|
||||||
|
pchapi.lk.Lock()
|
||||||
|
defer pchapi.lk.Unlock()
|
||||||
|
|
||||||
|
return sigs.Sign(crypto.SigTypeSecp256k1, pchapi.signingKey, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pchapi *mockPaychAPI) addSigningKey(key []byte) {
|
||||||
|
pchapi.lk.Lock()
|
||||||
|
defer pchapi.lk.Unlock()
|
||||||
|
|
||||||
|
pchapi.signingKey = key
|
||||||
|
}
|
||||||
|
@ -5,6 +5,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
@ -21,11 +23,36 @@ import (
|
|||||||
xerrors "golang.org/x/xerrors"
|
xerrors "golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// insufficientFundsErr indicates that there are not enough funds in the
|
||||||
|
// channel to create a voucher
|
||||||
|
type insufficientFundsErr interface {
|
||||||
|
Shortfall() types.BigInt
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrInsufficientFunds struct {
|
||||||
|
shortfall types.BigInt
|
||||||
|
}
|
||||||
|
|
||||||
|
func newErrInsufficientFunds(shortfall types.BigInt) *ErrInsufficientFunds {
|
||||||
|
return &ErrInsufficientFunds{shortfall: shortfall}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ErrInsufficientFunds) Error() string {
|
||||||
|
return fmt.Sprintf("not enough funds in channel to cover voucher - shortfall: %d", e.shortfall)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ErrInsufficientFunds) Shortfall() types.BigInt {
|
||||||
|
return e.shortfall
|
||||||
|
}
|
||||||
|
|
||||||
// channelAccessor is used to simplify locking when accessing a channel
|
// channelAccessor is used to simplify locking when accessing a channel
|
||||||
type channelAccessor struct {
|
type channelAccessor struct {
|
||||||
// waitCtx is used by processes that wait for things to be confirmed
|
from address.Address
|
||||||
// on chain
|
to address.Address
|
||||||
waitCtx context.Context
|
|
||||||
|
// chctx is used by background processes (eg when waiting for things to be
|
||||||
|
// confirmed on chain)
|
||||||
|
chctx context.Context
|
||||||
sa *stateAccessor
|
sa *stateAccessor
|
||||||
api managerAPI
|
api managerAPI
|
||||||
store *Store
|
store *Store
|
||||||
@ -34,14 +61,16 @@ type channelAccessor struct {
|
|||||||
msgListeners msgListeners
|
msgListeners msgListeners
|
||||||
}
|
}
|
||||||
|
|
||||||
func newChannelAccessor(pm *Manager) *channelAccessor {
|
func newChannelAccessor(pm *Manager, from address.Address, to address.Address) *channelAccessor {
|
||||||
return &channelAccessor{
|
return &channelAccessor{
|
||||||
lk: &channelLock{globalLock: &pm.lk},
|
from: from,
|
||||||
|
to: to,
|
||||||
|
chctx: pm.ctx,
|
||||||
sa: pm.sa,
|
sa: pm.sa,
|
||||||
api: pm.pchapi,
|
api: pm.pchapi,
|
||||||
store: pm.store,
|
store: pm.store,
|
||||||
|
lk: &channelLock{globalLock: &pm.lk},
|
||||||
msgListeners: newMsgListeners(),
|
msgListeners: newMsgListeners(),
|
||||||
waitCtx: pm.ctx,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,6 +81,69 @@ func (ca *channelAccessor) getChannelInfo(addr address.Address) (*ChannelInfo, e
|
|||||||
return ca.store.ByAddress(addr)
|
return ca.store.ByAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createVoucher creates a voucher with the given specification, setting its
|
||||||
|
// nonce, signing the voucher and storing it in the local datastore.
|
||||||
|
// If there are not enough funds in the channel to create the voucher, returns
|
||||||
|
// the shortfall in funds.
|
||||||
|
func (ca *channelAccessor) createVoucher(ctx context.Context, ch address.Address, voucher paych.SignedVoucher) (*api.VoucherCreateResult, error) {
|
||||||
|
ca.lk.Lock()
|
||||||
|
defer ca.lk.Unlock()
|
||||||
|
|
||||||
|
// Find the channel for the voucher
|
||||||
|
ci, err := ca.store.ByAddress(ch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to get channel info by address: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the voucher channel
|
||||||
|
sv := &voucher
|
||||||
|
sv.ChannelAddr = ch
|
||||||
|
|
||||||
|
// Get the next nonce on the given lane
|
||||||
|
sv.Nonce = ca.nextNonceForLane(ci, voucher.Lane)
|
||||||
|
|
||||||
|
// Sign the voucher
|
||||||
|
vb, err := sv.SigningBytes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to get voucher signing bytes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sig, err := ca.api.WalletSign(ctx, ci.Control, vb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to sign voucher: %w", err)
|
||||||
|
}
|
||||||
|
sv.Signature = sig
|
||||||
|
|
||||||
|
// Store the voucher
|
||||||
|
if _, err := ca.addVoucherUnlocked(ctx, ch, sv, nil, types.NewInt(0)); err != nil {
|
||||||
|
// If there are not enough funds in the channel to cover the voucher,
|
||||||
|
// return a voucher create result with the shortfall
|
||||||
|
var ife insufficientFundsErr
|
||||||
|
if xerrors.As(err, &ife) {
|
||||||
|
return &api.VoucherCreateResult{
|
||||||
|
Shortfall: ife.Shortfall(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, xerrors.Errorf("failed to persist voucher: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &api.VoucherCreateResult{Voucher: sv, Shortfall: types.NewInt(0)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ca *channelAccessor) nextNonceForLane(ci *ChannelInfo, lane uint64) uint64 {
|
||||||
|
var maxnonce uint64
|
||||||
|
for _, v := range ci.Vouchers {
|
||||||
|
if v.Voucher.Lane == lane {
|
||||||
|
if v.Voucher.Nonce > maxnonce {
|
||||||
|
maxnonce = v.Voucher.Nonce
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxnonce + 1
|
||||||
|
}
|
||||||
|
|
||||||
func (ca *channelAccessor) checkVoucherValid(ctx context.Context, ch address.Address, sv *paych.SignedVoucher) (map[uint64]*paych.LaneState, error) {
|
func (ca *channelAccessor) checkVoucherValid(ctx context.Context, ch address.Address, sv *paych.SignedVoucher) (map[uint64]*paych.LaneState, error) {
|
||||||
ca.lk.Lock()
|
ca.lk.Lock()
|
||||||
defer ca.lk.Unlock()
|
defer ca.lk.Unlock()
|
||||||
@ -133,7 +225,7 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add
|
|||||||
// Must not exceed actor balance
|
// Must not exceed actor balance
|
||||||
newTotal := types.BigAdd(totalRedeemed, pchState.ToSend)
|
newTotal := types.BigAdd(totalRedeemed, pchState.ToSend)
|
||||||
if act.Balance.LessThan(newTotal) {
|
if act.Balance.LessThan(newTotal) {
|
||||||
return nil, fmt.Errorf("not enough funds in channel to cover voucher")
|
return nil, newErrInsufficientFunds(types.BigSub(newTotal, act.Balance))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(sv.Merges) != 0 {
|
if len(sv.Merges) != 0 {
|
||||||
@ -221,6 +313,10 @@ func (ca *channelAccessor) addVoucher(ctx context.Context, ch address.Address, s
|
|||||||
ca.lk.Lock()
|
ca.lk.Lock()
|
||||||
defer ca.lk.Unlock()
|
defer ca.lk.Unlock()
|
||||||
|
|
||||||
|
return ca.addVoucherUnlocked(ctx, ch, sv, proof, minDelta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ca *channelAccessor) addVoucherUnlocked(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) {
|
||||||
ci, err := ca.store.ByAddress(ch)
|
ci, err := ca.store.ByAddress(ch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.BigInt{}, err
|
return types.BigInt{}, err
|
||||||
@ -382,28 +478,6 @@ func (ca *channelAccessor) listVouchers(ctx context.Context, ch address.Address)
|
|||||||
return ca.store.VouchersForPaych(ch)
|
return ca.store.VouchersForPaych(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ca *channelAccessor) nextNonceForLane(ctx context.Context, ch address.Address, lane uint64) (uint64, error) {
|
|
||||||
ca.lk.Lock()
|
|
||||||
defer ca.lk.Unlock()
|
|
||||||
|
|
||||||
// TODO: should this take into account lane state?
|
|
||||||
vouchers, err := ca.store.VouchersForPaych(ch)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var maxnonce uint64
|
|
||||||
for _, v := range vouchers {
|
|
||||||
if v.Voucher.Lane == lane {
|
|
||||||
if v.Voucher.Nonce > maxnonce {
|
|
||||||
maxnonce = v.Voucher.Nonce
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return maxnonce + 1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// laneState gets the LaneStates from chain, then applies all vouchers in
|
// laneState gets the LaneStates from chain, then applies all vouchers in
|
||||||
// the data store over the chain state
|
// the data store over the chain state
|
||||||
func (ca *channelAccessor) laneState(ctx context.Context, state *paych.State, ch address.Address) (map[uint64]*paych.LaneState, error) {
|
func (ca *channelAccessor) laneState(ctx context.Context, state *paych.State, ch address.Address) (map[uint64]*paych.LaneState, error) {
|
||||||
@ -479,7 +553,7 @@ func (ca *channelAccessor) totalRedeemedWithVoucher(laneStates map[uint64]*paych
|
|||||||
lane, ok := laneStates[sv.Lane]
|
lane, ok := laneStates[sv.Lane]
|
||||||
if ok {
|
if ok {
|
||||||
// If the voucher is for an existing lane, and the voucher nonce
|
// If the voucher is for an existing lane, and the voucher nonce
|
||||||
// and is higher than the lane nonce
|
// is higher than the lane nonce
|
||||||
if sv.Nonce > lane.Nonce {
|
if sv.Nonce > lane.Nonce {
|
||||||
// Add the delta between the redeemed amount and the voucher
|
// Add the delta between the redeemed amount and the voucher
|
||||||
// amount to the total
|
// amount to the total
|
||||||
|
@ -381,11 +381,76 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateVoucher(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
// Set up a manager with a single payment channel
|
||||||
|
s := testSetupMgrWithChannel(ctx, t)
|
||||||
|
|
||||||
|
// Create a voucher in lane 1
|
||||||
|
voucherLane1Amt := big.NewInt(5)
|
||||||
|
voucher := paych.SignedVoucher{
|
||||||
|
Lane: 1,
|
||||||
|
Amount: voucherLane1Amt,
|
||||||
|
}
|
||||||
|
res, err := s.mgr.CreateVoucher(ctx, s.ch, voucher)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, res.Voucher)
|
||||||
|
require.Equal(t, s.ch, res.Voucher.ChannelAddr)
|
||||||
|
require.Equal(t, voucherLane1Amt, res.Voucher.Amount)
|
||||||
|
require.EqualValues(t, 0, res.Shortfall.Int64())
|
||||||
|
|
||||||
|
nonce := res.Voucher.Nonce
|
||||||
|
|
||||||
|
// Create a voucher in lane 1 again, with a higher amount
|
||||||
|
voucherLane1Amt = big.NewInt(8)
|
||||||
|
voucher = paych.SignedVoucher{
|
||||||
|
Lane: 1,
|
||||||
|
Amount: voucherLane1Amt,
|
||||||
|
}
|
||||||
|
res, err = s.mgr.CreateVoucher(ctx, s.ch, voucher)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, res.Voucher)
|
||||||
|
require.Equal(t, s.ch, res.Voucher.ChannelAddr)
|
||||||
|
require.Equal(t, voucherLane1Amt, res.Voucher.Amount)
|
||||||
|
require.EqualValues(t, 0, res.Shortfall.Int64())
|
||||||
|
require.Equal(t, nonce+1, res.Voucher.Nonce)
|
||||||
|
|
||||||
|
// Create a voucher in lane 2 that covers all the remaining funds
|
||||||
|
// in the channel
|
||||||
|
voucherLane2Amt := big.Sub(s.amt, voucherLane1Amt)
|
||||||
|
voucher = paych.SignedVoucher{
|
||||||
|
Lane: 2,
|
||||||
|
Amount: voucherLane2Amt,
|
||||||
|
}
|
||||||
|
res, err = s.mgr.CreateVoucher(ctx, s.ch, voucher)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, res.Voucher)
|
||||||
|
require.Equal(t, s.ch, res.Voucher.ChannelAddr)
|
||||||
|
require.Equal(t, voucherLane2Amt, res.Voucher.Amount)
|
||||||
|
require.EqualValues(t, 0, res.Shortfall.Int64())
|
||||||
|
|
||||||
|
// Create a voucher in lane 2 that exceeds the remaining funds in the
|
||||||
|
// channel
|
||||||
|
voucherLane2Amt = big.Add(voucherLane2Amt, big.NewInt(1))
|
||||||
|
voucher = paych.SignedVoucher{
|
||||||
|
Lane: 2,
|
||||||
|
Amount: voucherLane2Amt,
|
||||||
|
}
|
||||||
|
res, err = s.mgr.CreateVoucher(ctx, s.ch, voucher)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Expect a shortfall value equal to the amount required to add the voucher
|
||||||
|
// to the channel
|
||||||
|
require.Nil(t, res.Voucher)
|
||||||
|
require.EqualValues(t, 1, res.Shortfall.Int64())
|
||||||
|
}
|
||||||
|
|
||||||
func TestAddVoucherDelta(t *testing.T) {
|
func TestAddVoucherDelta(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
// Set up a manager with a single payment channel
|
// Set up a manager with a single payment channel
|
||||||
mgr, _, ch, fromKeyPrivate := testSetupMgrWithChannel(ctx, t)
|
s := testSetupMgrWithChannel(ctx, t)
|
||||||
|
|
||||||
voucherLane := uint64(1)
|
voucherLane := uint64(1)
|
||||||
|
|
||||||
@ -393,23 +458,23 @@ func TestAddVoucherDelta(t *testing.T) {
|
|||||||
minDelta := big.NewInt(2)
|
minDelta := big.NewInt(2)
|
||||||
nonce := uint64(1)
|
nonce := uint64(1)
|
||||||
voucherAmount := big.NewInt(1)
|
voucherAmount := big.NewInt(1)
|
||||||
sv := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
sv := createTestVoucher(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate)
|
||||||
_, err := mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
_, err := s.mgr.AddVoucherOutbound(ctx, s.ch, sv, nil, minDelta)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
// Expect success when adding a voucher whose amount is equal to minDelta
|
// Expect success when adding a voucher whose amount is equal to minDelta
|
||||||
nonce++
|
nonce++
|
||||||
voucherAmount = big.NewInt(2)
|
voucherAmount = big.NewInt(2)
|
||||||
sv = createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
sv = createTestVoucher(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate)
|
||||||
delta, err := mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
delta, err := s.mgr.AddVoucherOutbound(ctx, s.ch, sv, nil, minDelta)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.EqualValues(t, delta.Int64(), 2)
|
require.EqualValues(t, delta.Int64(), 2)
|
||||||
|
|
||||||
// Check that delta is correct when there's an existing voucher
|
// Check that delta is correct when there's an existing voucher
|
||||||
nonce++
|
nonce++
|
||||||
voucherAmount = big.NewInt(5)
|
voucherAmount = big.NewInt(5)
|
||||||
sv = createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
sv = createTestVoucher(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate)
|
||||||
delta, err = mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
delta, err = s.mgr.AddVoucherOutbound(ctx, s.ch, sv, nil, minDelta)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.EqualValues(t, delta.Int64(), 3)
|
require.EqualValues(t, delta.Int64(), 3)
|
||||||
|
|
||||||
@ -417,8 +482,8 @@ func TestAddVoucherDelta(t *testing.T) {
|
|||||||
nonce = uint64(1)
|
nonce = uint64(1)
|
||||||
voucherAmount = big.NewInt(6)
|
voucherAmount = big.NewInt(6)
|
||||||
voucherLane = uint64(2)
|
voucherLane = uint64(2)
|
||||||
sv = createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
sv = createTestVoucher(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate)
|
||||||
delta, err = mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
delta, err = s.mgr.AddVoucherOutbound(ctx, s.ch, sv, nil, minDelta)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.EqualValues(t, delta.Int64(), 6)
|
require.EqualValues(t, delta.Int64(), 6)
|
||||||
}
|
}
|
||||||
@ -427,7 +492,7 @@ func TestAddVoucherNextLane(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
// Set up a manager with a single payment channel
|
// Set up a manager with a single payment channel
|
||||||
mgr, _, ch, fromKeyPrivate := testSetupMgrWithChannel(ctx, t)
|
s := testSetupMgrWithChannel(ctx, t)
|
||||||
|
|
||||||
minDelta := big.NewInt(0)
|
minDelta := big.NewInt(0)
|
||||||
voucherAmount := big.NewInt(2)
|
voucherAmount := big.NewInt(2)
|
||||||
@ -435,40 +500,40 @@ func TestAddVoucherNextLane(t *testing.T) {
|
|||||||
// Add a voucher in lane 2
|
// Add a voucher in lane 2
|
||||||
nonce := uint64(1)
|
nonce := uint64(1)
|
||||||
voucherLane := uint64(2)
|
voucherLane := uint64(2)
|
||||||
sv := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
sv := createTestVoucher(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate)
|
||||||
_, err := mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
_, err := s.mgr.AddVoucherOutbound(ctx, s.ch, sv, nil, minDelta)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
ci, err := mgr.GetChannelInfo(ch)
|
ci, err := s.mgr.GetChannelInfo(s.ch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.EqualValues(t, ci.NextLane, 3)
|
require.EqualValues(t, ci.NextLane, 3)
|
||||||
|
|
||||||
// Allocate a lane (should be lane 3)
|
// Allocate a lane (should be lane 3)
|
||||||
lane, err := mgr.AllocateLane(ch)
|
lane, err := s.mgr.AllocateLane(s.ch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.EqualValues(t, lane, 3)
|
require.EqualValues(t, lane, 3)
|
||||||
|
|
||||||
ci, err = mgr.GetChannelInfo(ch)
|
ci, err = s.mgr.GetChannelInfo(s.ch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.EqualValues(t, ci.NextLane, 4)
|
require.EqualValues(t, ci.NextLane, 4)
|
||||||
|
|
||||||
// Add a voucher in lane 1
|
// Add a voucher in lane 1
|
||||||
voucherLane = uint64(1)
|
voucherLane = uint64(1)
|
||||||
sv = createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
sv = createTestVoucher(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate)
|
||||||
_, err = mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
_, err = s.mgr.AddVoucherOutbound(ctx, s.ch, sv, nil, minDelta)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
ci, err = mgr.GetChannelInfo(ch)
|
ci, err = s.mgr.GetChannelInfo(s.ch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.EqualValues(t, ci.NextLane, 4)
|
require.EqualValues(t, ci.NextLane, 4)
|
||||||
|
|
||||||
// Add a voucher in lane 7
|
// Add a voucher in lane 7
|
||||||
voucherLane = uint64(7)
|
voucherLane = uint64(7)
|
||||||
sv = createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
sv = createTestVoucher(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate)
|
||||||
_, err = mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
_, err = s.mgr.AddVoucherOutbound(ctx, s.ch, sv, nil, minDelta)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
ci, err = mgr.GetChannelInfo(ch)
|
ci, err = s.mgr.GetChannelInfo(s.ch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.EqualValues(t, ci.NextLane, 8)
|
require.EqualValues(t, ci.NextLane, 8)
|
||||||
}
|
}
|
||||||
@ -477,15 +542,15 @@ func TestAllocateLane(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
// Set up a manager with a single payment channel
|
// Set up a manager with a single payment channel
|
||||||
mgr, _, ch, _ := testSetupMgrWithChannel(ctx, t)
|
s := testSetupMgrWithChannel(ctx, t)
|
||||||
|
|
||||||
// First lane should be 0
|
// First lane should be 0
|
||||||
lane, err := mgr.AllocateLane(ch)
|
lane, err := s.mgr.AllocateLane(s.ch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.EqualValues(t, lane, 0)
|
require.EqualValues(t, lane, 0)
|
||||||
|
|
||||||
// Next lane should be 1
|
// Next lane should be 1
|
||||||
lane, err = mgr.AllocateLane(ch)
|
lane, err = s.mgr.AllocateLane(s.ch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.EqualValues(t, lane, 1)
|
require.EqualValues(t, lane, 1)
|
||||||
}
|
}
|
||||||
@ -553,7 +618,7 @@ func TestAddVoucherProof(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
// Set up a manager with a single payment channel
|
// Set up a manager with a single payment channel
|
||||||
mgr, _, ch, fromKeyPrivate := testSetupMgrWithChannel(ctx, t)
|
s := testSetupMgrWithChannel(ctx, t)
|
||||||
|
|
||||||
nonce := uint64(1)
|
nonce := uint64(1)
|
||||||
voucherAmount := big.NewInt(1)
|
voucherAmount := big.NewInt(1)
|
||||||
@ -563,34 +628,34 @@ func TestAddVoucherProof(t *testing.T) {
|
|||||||
|
|
||||||
// Add a voucher with no proof
|
// Add a voucher with no proof
|
||||||
var proof []byte
|
var proof []byte
|
||||||
sv := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
sv := createTestVoucher(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate)
|
||||||
_, err := mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
_, err := s.mgr.AddVoucherOutbound(ctx, s.ch, sv, nil, minDelta)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Expect one voucher with no proof
|
// Expect one voucher with no proof
|
||||||
ci, err := mgr.GetChannelInfo(ch)
|
ci, err := s.mgr.GetChannelInfo(s.ch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, ci.Vouchers, 1)
|
require.Len(t, ci.Vouchers, 1)
|
||||||
require.Len(t, ci.Vouchers[0].Proof, 0)
|
require.Len(t, ci.Vouchers[0].Proof, 0)
|
||||||
|
|
||||||
// Add same voucher with no proof
|
// Add same voucher with no proof
|
||||||
voucherLane = uint64(1)
|
voucherLane = uint64(1)
|
||||||
_, err = mgr.AddVoucherOutbound(ctx, ch, sv, proof, minDelta)
|
_, err = s.mgr.AddVoucherOutbound(ctx, s.ch, sv, proof, minDelta)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Expect one voucher with no proof
|
// Expect one voucher with no proof
|
||||||
ci, err = mgr.GetChannelInfo(ch)
|
ci, err = s.mgr.GetChannelInfo(s.ch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, ci.Vouchers, 1)
|
require.Len(t, ci.Vouchers, 1)
|
||||||
require.Len(t, ci.Vouchers[0].Proof, 0)
|
require.Len(t, ci.Vouchers[0].Proof, 0)
|
||||||
|
|
||||||
// Add same voucher with proof
|
// Add same voucher with proof
|
||||||
proof = []byte{1}
|
proof = []byte{1}
|
||||||
_, err = mgr.AddVoucherOutbound(ctx, ch, sv, proof, minDelta)
|
_, err = s.mgr.AddVoucherOutbound(ctx, s.ch, sv, proof, minDelta)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Should add proof to existing voucher
|
// Should add proof to existing voucher
|
||||||
ci, err = mgr.GetChannelInfo(ch)
|
ci, err = s.mgr.GetChannelInfo(s.ch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, ci.Vouchers, 1)
|
require.Len(t, ci.Vouchers, 1)
|
||||||
require.Len(t, ci.Vouchers[0].Proof, 1)
|
require.Len(t, ci.Vouchers[0].Proof, 1)
|
||||||
@ -663,47 +728,47 @@ func TestBestSpendable(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
// Set up a manager with a single payment channel
|
// Set up a manager with a single payment channel
|
||||||
mgr, mock, ch, fromKeyPrivate := testSetupMgrWithChannel(ctx, t)
|
s := testSetupMgrWithChannel(ctx, t)
|
||||||
|
|
||||||
// Add vouchers to lane 1 with amounts: [1, 2, 3]
|
// Add vouchers to lane 1 with amounts: [1, 2, 3]
|
||||||
voucherLane := uint64(1)
|
voucherLane := uint64(1)
|
||||||
minDelta := big.NewInt(0)
|
minDelta := big.NewInt(0)
|
||||||
nonce := uint64(1)
|
nonce := uint64(1)
|
||||||
voucherAmount := big.NewInt(1)
|
voucherAmount := big.NewInt(1)
|
||||||
svL1V1 := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
svL1V1 := createTestVoucher(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate)
|
||||||
_, err := mgr.AddVoucherInbound(ctx, ch, svL1V1, nil, minDelta)
|
_, err := s.mgr.AddVoucherInbound(ctx, s.ch, svL1V1, nil, minDelta)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
nonce++
|
nonce++
|
||||||
voucherAmount = big.NewInt(2)
|
voucherAmount = big.NewInt(2)
|
||||||
svL1V2 := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
svL1V2 := createTestVoucher(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate)
|
||||||
_, err = mgr.AddVoucherInbound(ctx, ch, svL1V2, nil, minDelta)
|
_, err = s.mgr.AddVoucherInbound(ctx, s.ch, svL1V2, nil, minDelta)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
nonce++
|
nonce++
|
||||||
voucherAmount = big.NewInt(3)
|
voucherAmount = big.NewInt(3)
|
||||||
svL1V3 := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
svL1V3 := createTestVoucher(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate)
|
||||||
_, err = mgr.AddVoucherInbound(ctx, ch, svL1V3, nil, minDelta)
|
_, err = s.mgr.AddVoucherInbound(ctx, s.ch, svL1V3, nil, minDelta)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Add voucher to lane 2 with amounts: [2]
|
// Add voucher to lane 2 with amounts: [2]
|
||||||
voucherLane = uint64(2)
|
voucherLane = uint64(2)
|
||||||
nonce = uint64(1)
|
nonce = uint64(1)
|
||||||
voucherAmount = big.NewInt(2)
|
voucherAmount = big.NewInt(2)
|
||||||
svL2V1 := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
svL2V1 := createTestVoucher(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate)
|
||||||
_, err = mgr.AddVoucherInbound(ctx, ch, svL2V1, nil, minDelta)
|
_, err = s.mgr.AddVoucherInbound(ctx, s.ch, svL2V1, nil, minDelta)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Return success exit code from calls to check if voucher is spendable
|
// Return success exit code from calls to check if voucher is spendable
|
||||||
bsapi := newMockBestSpendableAPI(mgr)
|
bsapi := newMockBestSpendableAPI(s.mgr)
|
||||||
mock.setCallResponse(&api.InvocResult{
|
s.mock.setCallResponse(&api.InvocResult{
|
||||||
MsgRct: &types.MessageReceipt{
|
MsgRct: &types.MessageReceipt{
|
||||||
ExitCode: 0,
|
ExitCode: 0,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// Verify best spendable vouchers on each lane
|
// Verify best spendable vouchers on each lane
|
||||||
vouchers, err := BestSpendableByLane(ctx, bsapi, ch)
|
vouchers, err := BestSpendableByLane(ctx, bsapi, s.ch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, vouchers, 2)
|
require.Len(t, vouchers, 2)
|
||||||
|
|
||||||
@ -716,21 +781,21 @@ func TestBestSpendable(t *testing.T) {
|
|||||||
require.EqualValues(t, 2, vchr.Amount.Int64())
|
require.EqualValues(t, 2, vchr.Amount.Int64())
|
||||||
|
|
||||||
// Submit voucher from lane 2
|
// Submit voucher from lane 2
|
||||||
_, err = mgr.SubmitVoucher(ctx, ch, svL2V1, nil, nil)
|
_, err = s.mgr.SubmitVoucher(ctx, s.ch, svL2V1, nil, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Best spendable voucher should no longer include lane 2
|
// Best spendable voucher should no longer include lane 2
|
||||||
// (because voucher has not been submitted)
|
// (because voucher has not been submitted)
|
||||||
vouchers, err = BestSpendableByLane(ctx, bsapi, ch)
|
vouchers, err = BestSpendableByLane(ctx, bsapi, s.ch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, vouchers, 1)
|
require.Len(t, vouchers, 1)
|
||||||
|
|
||||||
// Submit first voucher from lane 1
|
// Submit first voucher from lane 1
|
||||||
_, err = mgr.SubmitVoucher(ctx, ch, svL1V1, nil, nil)
|
_, err = s.mgr.SubmitVoucher(ctx, s.ch, svL1V1, nil, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Best spendable voucher for lane 1 should still be highest value voucher
|
// Best spendable voucher for lane 1 should still be highest value voucher
|
||||||
vouchers, err = BestSpendableByLane(ctx, bsapi, ch)
|
vouchers, err = BestSpendableByLane(ctx, bsapi, s.ch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, vouchers, 1)
|
require.Len(t, vouchers, 1)
|
||||||
|
|
||||||
@ -743,18 +808,18 @@ func TestCheckSpendable(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
// Set up a manager with a single payment channel
|
// Set up a manager with a single payment channel
|
||||||
mgr, mock, ch, fromKeyPrivate := testSetupMgrWithChannel(ctx, t)
|
s := testSetupMgrWithChannel(ctx, t)
|
||||||
|
|
||||||
// Create voucher with Extra
|
// Create voucher with Extra
|
||||||
voucherLane := uint64(1)
|
voucherLane := uint64(1)
|
||||||
nonce := uint64(1)
|
nonce := uint64(1)
|
||||||
voucherAmount := big.NewInt(1)
|
voucherAmount := big.NewInt(1)
|
||||||
voucher := createTestVoucherWithExtra(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
voucher := createTestVoucherWithExtra(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate)
|
||||||
|
|
||||||
// Add voucher with proof
|
// Add voucher with proof
|
||||||
minDelta := big.NewInt(0)
|
minDelta := big.NewInt(0)
|
||||||
proof := []byte("proof")
|
proof := []byte("proof")
|
||||||
_, err := mgr.AddVoucherInbound(ctx, ch, voucher, proof, minDelta)
|
_, err := s.mgr.AddVoucherInbound(ctx, s.ch, voucher, proof, minDelta)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Return success exit code from VM call, which indicates that voucher is
|
// Return success exit code from VM call, which indicates that voucher is
|
||||||
@ -764,17 +829,17 @@ func TestCheckSpendable(t *testing.T) {
|
|||||||
ExitCode: 0,
|
ExitCode: 0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
mock.setCallResponse(successResponse)
|
s.mock.setCallResponse(successResponse)
|
||||||
|
|
||||||
// Check that spendable is true
|
// Check that spendable is true
|
||||||
secret := []byte("secret")
|
secret := []byte("secret")
|
||||||
otherProof := []byte("other proof")
|
otherProof := []byte("other proof")
|
||||||
spendable, err := mgr.CheckVoucherSpendable(ctx, ch, voucher, secret, otherProof)
|
spendable, err := s.mgr.CheckVoucherSpendable(ctx, s.ch, voucher, secret, otherProof)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, spendable)
|
require.True(t, spendable)
|
||||||
|
|
||||||
// Check that the secret and proof were passed through correctly
|
// Check that the secret and proof were passed through correctly
|
||||||
lastCall := mock.getLastCall()
|
lastCall := s.mock.getLastCall()
|
||||||
var p paych.UpdateChannelStateParams
|
var p paych.UpdateChannelStateParams
|
||||||
err = p.UnmarshalCBOR(bytes.NewReader(lastCall.Params))
|
err = p.UnmarshalCBOR(bytes.NewReader(lastCall.Params))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -784,11 +849,11 @@ func TestCheckSpendable(t *testing.T) {
|
|||||||
// Check that if no proof is supplied, the proof supplied to add voucher
|
// Check that if no proof is supplied, the proof supplied to add voucher
|
||||||
// above is used
|
// above is used
|
||||||
secret2 := []byte("secret2")
|
secret2 := []byte("secret2")
|
||||||
spendable, err = mgr.CheckVoucherSpendable(ctx, ch, voucher, secret2, nil)
|
spendable, err = s.mgr.CheckVoucherSpendable(ctx, s.ch, voucher, secret2, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, spendable)
|
require.True(t, spendable)
|
||||||
|
|
||||||
lastCall = mock.getLastCall()
|
lastCall = s.mock.getLastCall()
|
||||||
var p2 paych.UpdateChannelStateParams
|
var p2 paych.UpdateChannelStateParams
|
||||||
err = p2.UnmarshalCBOR(bytes.NewReader(lastCall.Params))
|
err = p2.UnmarshalCBOR(bytes.NewReader(lastCall.Params))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -796,26 +861,26 @@ func TestCheckSpendable(t *testing.T) {
|
|||||||
require.Equal(t, secret2, p2.Secret)
|
require.Equal(t, secret2, p2.Secret)
|
||||||
|
|
||||||
// Check that if VM call returns non-success exit code, spendable is false
|
// Check that if VM call returns non-success exit code, spendable is false
|
||||||
mock.setCallResponse(&api.InvocResult{
|
s.mock.setCallResponse(&api.InvocResult{
|
||||||
MsgRct: &types.MessageReceipt{
|
MsgRct: &types.MessageReceipt{
|
||||||
ExitCode: 1,
|
ExitCode: 1,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
spendable, err = mgr.CheckVoucherSpendable(ctx, ch, voucher, secret, nil)
|
spendable, err = s.mgr.CheckVoucherSpendable(ctx, s.ch, voucher, secret, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.False(t, spendable)
|
require.False(t, spendable)
|
||||||
|
|
||||||
// Return success exit code (indicating voucher is spendable)
|
// Return success exit code (indicating voucher is spendable)
|
||||||
mock.setCallResponse(successResponse)
|
s.mock.setCallResponse(successResponse)
|
||||||
spendable, err = mgr.CheckVoucherSpendable(ctx, ch, voucher, secret, nil)
|
spendable, err = s.mgr.CheckVoucherSpendable(ctx, s.ch, voucher, secret, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, spendable)
|
require.True(t, spendable)
|
||||||
|
|
||||||
// Check that voucher is no longer spendable once it has been submitted
|
// Check that voucher is no longer spendable once it has been submitted
|
||||||
_, err = mgr.SubmitVoucher(ctx, ch, voucher, nil, nil)
|
_, err = s.mgr.SubmitVoucher(ctx, s.ch, voucher, nil, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
spendable, err = mgr.CheckVoucherSpendable(ctx, ch, voucher, secret, nil)
|
spendable, err = s.mgr.CheckVoucherSpendable(ctx, s.ch, voucher, secret, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.False(t, spendable)
|
require.False(t, spendable)
|
||||||
}
|
}
|
||||||
@ -824,28 +889,28 @@ func TestSubmitVoucher(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
// Set up a manager with a single payment channel
|
// Set up a manager with a single payment channel
|
||||||
mgr, mock, ch, fromKeyPrivate := testSetupMgrWithChannel(ctx, t)
|
s := testSetupMgrWithChannel(ctx, t)
|
||||||
|
|
||||||
// Create voucher with Extra
|
// Create voucher with Extra
|
||||||
voucherLane := uint64(1)
|
voucherLane := uint64(1)
|
||||||
nonce := uint64(1)
|
nonce := uint64(1)
|
||||||
voucherAmount := big.NewInt(1)
|
voucherAmount := big.NewInt(1)
|
||||||
voucher := createTestVoucherWithExtra(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
voucher := createTestVoucherWithExtra(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate)
|
||||||
|
|
||||||
// Add voucher with proof
|
// Add voucher with proof
|
||||||
minDelta := big.NewInt(0)
|
minDelta := big.NewInt(0)
|
||||||
addVoucherProof := []byte("proof")
|
addVoucherProof := []byte("proof")
|
||||||
_, err := mgr.AddVoucherInbound(ctx, ch, voucher, addVoucherProof, minDelta)
|
_, err := s.mgr.AddVoucherInbound(ctx, s.ch, voucher, addVoucherProof, minDelta)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Submit voucher
|
// Submit voucher
|
||||||
secret := []byte("secret")
|
secret := []byte("secret")
|
||||||
submitProof := []byte("submit proof")
|
submitProof := []byte("submit proof")
|
||||||
submitCid, err := mgr.SubmitVoucher(ctx, ch, voucher, secret, submitProof)
|
submitCid, err := s.mgr.SubmitVoucher(ctx, s.ch, voucher, secret, submitProof)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Check that the secret and proof were passed through correctly
|
// Check that the secret and proof were passed through correctly
|
||||||
msg := mock.pushedMessages(submitCid)
|
msg := s.mock.pushedMessages(submitCid)
|
||||||
var p paych.UpdateChannelStateParams
|
var p paych.UpdateChannelStateParams
|
||||||
err = p.UnmarshalCBOR(bytes.NewReader(msg.Message.Params))
|
err = p.UnmarshalCBOR(bytes.NewReader(msg.Message.Params))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -858,14 +923,14 @@ func TestSubmitVoucher(t *testing.T) {
|
|||||||
voucherAmount = big.NewInt(2)
|
voucherAmount = big.NewInt(2)
|
||||||
addVoucherProof2 := []byte("proof2")
|
addVoucherProof2 := []byte("proof2")
|
||||||
secret2 := []byte("secret2")
|
secret2 := []byte("secret2")
|
||||||
voucher = createTestVoucherWithExtra(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
voucher = createTestVoucherWithExtra(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate)
|
||||||
_, err = mgr.AddVoucherInbound(ctx, ch, voucher, addVoucherProof2, minDelta)
|
_, err = s.mgr.AddVoucherInbound(ctx, s.ch, voucher, addVoucherProof2, minDelta)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
submitCid, err = mgr.SubmitVoucher(ctx, ch, voucher, secret2, nil)
|
submitCid, err = s.mgr.SubmitVoucher(ctx, s.ch, voucher, secret2, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
msg = mock.pushedMessages(submitCid)
|
msg = s.mock.pushedMessages(submitCid)
|
||||||
var p2 paych.UpdateChannelStateParams
|
var p2 paych.UpdateChannelStateParams
|
||||||
err = p2.UnmarshalCBOR(bytes.NewReader(msg.Message.Params))
|
err = p2.UnmarshalCBOR(bytes.NewReader(msg.Message.Params))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -877,11 +942,11 @@ func TestSubmitVoucher(t *testing.T) {
|
|||||||
voucherAmount = big.NewInt(3)
|
voucherAmount = big.NewInt(3)
|
||||||
secret3 := []byte("secret2")
|
secret3 := []byte("secret2")
|
||||||
proof3 := []byte("proof3")
|
proof3 := []byte("proof3")
|
||||||
voucher = createTestVoucherWithExtra(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
voucher = createTestVoucherWithExtra(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate)
|
||||||
submitCid, err = mgr.SubmitVoucher(ctx, ch, voucher, secret3, proof3)
|
submitCid, err = s.mgr.SubmitVoucher(ctx, s.ch, voucher, secret3, proof3)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
msg = mock.pushedMessages(submitCid)
|
msg = s.mock.pushedMessages(submitCid)
|
||||||
var p3 paych.UpdateChannelStateParams
|
var p3 paych.UpdateChannelStateParams
|
||||||
err = p3.UnmarshalCBOR(bytes.NewReader(msg.Message.Params))
|
err = p3.UnmarshalCBOR(bytes.NewReader(msg.Message.Params))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -889,7 +954,7 @@ func TestSubmitVoucher(t *testing.T) {
|
|||||||
require.Equal(t, secret3, p3.Secret)
|
require.Equal(t, secret3, p3.Secret)
|
||||||
|
|
||||||
// Verify that vouchers are marked as submitted
|
// Verify that vouchers are marked as submitted
|
||||||
vis, err := mgr.ListVouchers(ctx, ch)
|
vis, err := s.mgr.ListVouchers(ctx, s.ch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, vis, 3)
|
require.Len(t, vis, 3)
|
||||||
|
|
||||||
@ -898,55 +963,20 @@ func TestSubmitVoucher(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attempting to submit the same voucher again should fail
|
// Attempting to submit the same voucher again should fail
|
||||||
_, err = mgr.SubmitVoucher(ctx, ch, voucher, secret2, nil)
|
_, err = s.mgr.SubmitVoucher(ctx, s.ch, voucher, secret2, nil)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNextNonceForLane(t *testing.T) {
|
type testScaffold struct {
|
||||||
ctx := context.Background()
|
mgr *Manager
|
||||||
|
mock *mockManagerAPI
|
||||||
// Set up a manager with a single payment channel
|
ch address.Address
|
||||||
mgr, _, ch, key := testSetupMgrWithChannel(ctx, t)
|
amt big.Int
|
||||||
|
fromAcct address.Address
|
||||||
// Expect next nonce for non-existent lane to be 1
|
fromKeyPrivate []byte
|
||||||
next, err := mgr.NextNonceForLane(ctx, ch, 1)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.EqualValues(t, next, 1)
|
|
||||||
|
|
||||||
voucherAmount := big.NewInt(1)
|
|
||||||
minDelta := big.NewInt(0)
|
|
||||||
voucherAmount = big.NewInt(2)
|
|
||||||
|
|
||||||
// Add vouchers such that we have
|
|
||||||
// lane 1: nonce 2
|
|
||||||
// lane 1: nonce 4
|
|
||||||
voucherLane := uint64(1)
|
|
||||||
for _, nonce := range []uint64{2, 4} {
|
|
||||||
voucherAmount = big.Add(voucherAmount, big.NewInt(1))
|
|
||||||
sv := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, key)
|
|
||||||
_, err := mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// lane 2: nonce 7
|
|
||||||
voucherLane = uint64(2)
|
|
||||||
nonce := uint64(7)
|
|
||||||
sv := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, key)
|
|
||||||
_, err = mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Expect next nonce for lane 1 to be 5
|
|
||||||
next, err = mgr.NextNonceForLane(ctx, ch, 1)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.EqualValues(t, next, 5)
|
|
||||||
|
|
||||||
// Expect next nonce for lane 2 to be 8
|
|
||||||
next, err = mgr.NextNonceForLane(ctx, ch, 2)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.EqualValues(t, next, 8)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSetupMgrWithChannel(ctx context.Context, t *testing.T) (*Manager, *mockManagerAPI, address.Address, []byte) {
|
func testSetupMgrWithChannel(ctx context.Context, t *testing.T) *testScaffold {
|
||||||
fromKeyPrivate, fromKeyPublic := testGenerateKeyPair(t)
|
fromKeyPrivate, fromKeyPublic := testGenerateKeyPair(t)
|
||||||
|
|
||||||
ch := tutils.NewIDAddr(t, 100)
|
ch := tutils.NewIDAddr(t, 100)
|
||||||
@ -962,11 +992,12 @@ func testSetupMgrWithChannel(ctx context.Context, t *testing.T) (*Manager, *mock
|
|||||||
mock.setAccountState(toAcct, account.State{Address: to})
|
mock.setAccountState(toAcct, account.State{Address: to})
|
||||||
|
|
||||||
// Create channel in state
|
// Create channel in state
|
||||||
|
balance := big.NewInt(20)
|
||||||
act := &types.Actor{
|
act := &types.Actor{
|
||||||
Code: builtin.AccountActorCodeID,
|
Code: builtin.AccountActorCodeID,
|
||||||
Head: cid.Cid{},
|
Head: cid.Cid{},
|
||||||
Nonce: 0,
|
Nonce: 0,
|
||||||
Balance: big.NewInt(20),
|
Balance: balance,
|
||||||
}
|
}
|
||||||
mock.setPaychState(ch, act, paych.State{
|
mock.setPaychState(ch, act, paych.State{
|
||||||
From: fromAcct,
|
From: fromAcct,
|
||||||
@ -991,7 +1022,17 @@ func testSetupMgrWithChannel(ctx context.Context, t *testing.T) (*Manager, *mock
|
|||||||
err = mgr.store.putChannelInfo(ci)
|
err = mgr.store.putChannelInfo(ci)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
return mgr, mock, ch, fromKeyPrivate
|
// Add the from signing key to the wallet
|
||||||
|
mock.addSigningKey(fromKeyPrivate)
|
||||||
|
|
||||||
|
return &testScaffold{
|
||||||
|
mgr: mgr,
|
||||||
|
mock: mock,
|
||||||
|
ch: ch,
|
||||||
|
amt: balance,
|
||||||
|
fromAcct: fromAcct,
|
||||||
|
fromKeyPrivate: fromKeyPrivate,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGenerateKeyPair(t *testing.T) ([]byte, []byte) {
|
func testGenerateKeyPair(t *testing.T) ([]byte, []byte) {
|
||||||
|
@ -6,6 +6,12 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/builtin/account"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||||
|
|
||||||
cborrpc "github.com/filecoin-project/go-cbor-util"
|
cborrpc "github.com/filecoin-project/go-cbor-util"
|
||||||
|
|
||||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||||
@ -650,8 +656,6 @@ func TestPaychGetMergeAddFunds(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Queue up two add funds requests behind create channel
|
// Queue up two add funds requests behind create channel
|
||||||
//var addFundsQueuedUp sync.WaitGroup
|
|
||||||
//addFundsQueuedUp.Add(2)
|
|
||||||
var addFundsSent sync.WaitGroup
|
var addFundsSent sync.WaitGroup
|
||||||
addFundsSent.Add(2)
|
addFundsSent.Add(2)
|
||||||
|
|
||||||
@ -662,7 +666,6 @@ func TestPaychGetMergeAddFunds(t *testing.T) {
|
|||||||
var addFundsMcid1 cid.Cid
|
var addFundsMcid1 cid.Cid
|
||||||
var addFundsMcid2 cid.Cid
|
var addFundsMcid2 cid.Cid
|
||||||
go func() {
|
go func() {
|
||||||
//go addFundsQueuedUp.Done()
|
|
||||||
defer addFundsSent.Done()
|
defer addFundsSent.Done()
|
||||||
|
|
||||||
// Request add funds - should block until create channel has completed
|
// Request add funds - should block until create channel has completed
|
||||||
@ -671,7 +674,6 @@ func TestPaychGetMergeAddFunds(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
//go addFundsQueuedUp.Done()
|
|
||||||
defer addFundsSent.Done()
|
defer addFundsSent.Done()
|
||||||
|
|
||||||
// Request add funds again - should merge with waiting add funds request
|
// Request add funds again - should merge with waiting add funds request
|
||||||
@ -899,6 +901,168 @@ func TestPaychGetMergeAddFundsCtxCancelAll(t *testing.T) {
|
|||||||
require.Equal(t, createAmt, createMsg.Message.Value)
|
require.Equal(t, createAmt, createMsg.Message.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestPaychAvailableFunds tests that PaychAvailableFunds returns the correct
|
||||||
|
// channel state
|
||||||
|
func TestPaychAvailableFunds(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore()))
|
||||||
|
|
||||||
|
fromKeyPrivate, fromKeyPublic := testGenerateKeyPair(t)
|
||||||
|
ch := tutils.NewIDAddr(t, 100)
|
||||||
|
from := tutils.NewSECP256K1Addr(t, string(fromKeyPublic))
|
||||||
|
to := tutils.NewIDAddr(t, 102)
|
||||||
|
fromAcct := tutils.NewActorAddr(t, "fromAct")
|
||||||
|
toAcct := tutils.NewActorAddr(t, "toAct")
|
||||||
|
|
||||||
|
mock := newMockManagerAPI()
|
||||||
|
defer mock.close()
|
||||||
|
|
||||||
|
mgr, err := newManager(store, mock)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// No channel created yet so available funds should be all zeroes
|
||||||
|
av, err := mgr.AvailableFunds(from, to)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, av.Channel)
|
||||||
|
require.Nil(t, av.PendingWaitSentinel)
|
||||||
|
require.EqualValues(t, 0, av.ConfirmedAmt.Int64())
|
||||||
|
require.EqualValues(t, 0, av.PendingAmt.Int64())
|
||||||
|
require.EqualValues(t, 0, av.QueuedAmt.Int64())
|
||||||
|
require.EqualValues(t, 0, av.VoucherReedeemedAmt.Int64())
|
||||||
|
|
||||||
|
// Send create message for a channel with value 10
|
||||||
|
createAmt := big.NewInt(10)
|
||||||
|
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, createAmt)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Available funds should reflect create channel message sent
|
||||||
|
av, err = mgr.AvailableFunds(from, to)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, av.Channel)
|
||||||
|
require.EqualValues(t, 0, av.ConfirmedAmt.Int64())
|
||||||
|
require.EqualValues(t, createAmt, av.PendingAmt)
|
||||||
|
require.EqualValues(t, 0, av.QueuedAmt.Int64())
|
||||||
|
require.EqualValues(t, 0, av.VoucherReedeemedAmt.Int64())
|
||||||
|
// Should now have a pending wait sentinel
|
||||||
|
require.NotNil(t, av.PendingWaitSentinel)
|
||||||
|
|
||||||
|
// Queue up an add funds request behind create channel
|
||||||
|
var addFundsSent sync.WaitGroup
|
||||||
|
addFundsSent.Add(1)
|
||||||
|
|
||||||
|
addFundsAmt := big.NewInt(5)
|
||||||
|
var addFundsMcid cid.Cid
|
||||||
|
go func() {
|
||||||
|
defer addFundsSent.Done()
|
||||||
|
|
||||||
|
// Request add funds - should block until create channel has completed
|
||||||
|
_, addFundsMcid, err = mgr.GetPaych(ctx, from, to, addFundsAmt)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Wait for add funds request to be queued up
|
||||||
|
waitForQueueSize(t, mgr, from, to, 1)
|
||||||
|
|
||||||
|
// Available funds should now include queued funds
|
||||||
|
av, err = mgr.AvailableFunds(from, to)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, av.Channel)
|
||||||
|
require.NotNil(t, av.PendingWaitSentinel)
|
||||||
|
require.EqualValues(t, 0, av.ConfirmedAmt.Int64())
|
||||||
|
// create amount is still pending
|
||||||
|
require.EqualValues(t, createAmt, av.PendingAmt)
|
||||||
|
// queued amount now includes add funds amount
|
||||||
|
require.EqualValues(t, addFundsAmt, av.QueuedAmt)
|
||||||
|
require.EqualValues(t, 0, av.VoucherReedeemedAmt.Int64())
|
||||||
|
|
||||||
|
// Create channel in state
|
||||||
|
arr, err := adt.MakeEmptyArray(mock.store).Root()
|
||||||
|
require.NoError(t, err)
|
||||||
|
mock.setAccountState(fromAcct, account.State{Address: from})
|
||||||
|
mock.setAccountState(toAcct, account.State{Address: to})
|
||||||
|
act := &types.Actor{
|
||||||
|
Code: builtin.AccountActorCodeID,
|
||||||
|
Head: cid.Cid{},
|
||||||
|
Nonce: 0,
|
||||||
|
Balance: createAmt,
|
||||||
|
}
|
||||||
|
mock.setPaychState(ch, act, paych.State{
|
||||||
|
From: fromAcct,
|
||||||
|
To: toAcct,
|
||||||
|
ToSend: big.NewInt(0),
|
||||||
|
SettlingAt: abi.ChainEpoch(0),
|
||||||
|
MinSettleHeight: abi.ChainEpoch(0),
|
||||||
|
LaneStates: arr,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Send create channel response
|
||||||
|
response := testChannelResponse(t, ch)
|
||||||
|
mock.receiveMsgResponse(createMsgCid, response)
|
||||||
|
|
||||||
|
// Wait for create channel response
|
||||||
|
chres, err := mgr.GetPaychWaitReady(ctx, *av.PendingWaitSentinel)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, ch, chres)
|
||||||
|
|
||||||
|
// Wait for add funds request to be sent
|
||||||
|
addFundsSent.Wait()
|
||||||
|
|
||||||
|
// Available funds should now include the channel and also a wait sentinel
|
||||||
|
// for the add funds message
|
||||||
|
av, err = mgr.AvailableFunds(from, to)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, av.Channel)
|
||||||
|
require.NotNil(t, av.PendingWaitSentinel)
|
||||||
|
// create amount is now confirmed
|
||||||
|
require.EqualValues(t, createAmt, av.ConfirmedAmt)
|
||||||
|
// add funds amount it now pending
|
||||||
|
require.EqualValues(t, addFundsAmt, av.PendingAmt)
|
||||||
|
require.EqualValues(t, 0, av.QueuedAmt.Int64())
|
||||||
|
require.EqualValues(t, 0, av.VoucherReedeemedAmt.Int64())
|
||||||
|
|
||||||
|
// Send success add funds response
|
||||||
|
mock.receiveMsgResponse(addFundsMcid, types.MessageReceipt{
|
||||||
|
ExitCode: 0,
|
||||||
|
Return: []byte{},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Wait for add funds response
|
||||||
|
_, err = mgr.GetPaychWaitReady(ctx, *av.PendingWaitSentinel)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Available funds should no longer have a wait sentinel
|
||||||
|
av, err = mgr.AvailableFunds(from, to)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, av.Channel)
|
||||||
|
require.Nil(t, av.PendingWaitSentinel)
|
||||||
|
// confirmed amount now includes create and add funds amounts
|
||||||
|
require.EqualValues(t, types.BigAdd(createAmt, addFundsAmt), av.ConfirmedAmt)
|
||||||
|
require.EqualValues(t, 0, av.PendingAmt.Int64())
|
||||||
|
require.EqualValues(t, 0, av.QueuedAmt.Int64())
|
||||||
|
require.EqualValues(t, 0, av.VoucherReedeemedAmt.Int64())
|
||||||
|
|
||||||
|
// Add some vouchers
|
||||||
|
voucherAmt1 := types.NewInt(3)
|
||||||
|
voucher := createTestVoucher(t, ch, 1, 1, voucherAmt1, fromKeyPrivate)
|
||||||
|
_, err = mgr.AddVoucherOutbound(ctx, ch, voucher, nil, types.NewInt(0))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
voucherAmt2 := types.NewInt(2)
|
||||||
|
voucher = createTestVoucher(t, ch, 2, 1, voucherAmt2, fromKeyPrivate)
|
||||||
|
_, err = mgr.AddVoucherOutbound(ctx, ch, voucher, nil, types.NewInt(0))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
av, err = mgr.AvailableFunds(from, to)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, av.Channel)
|
||||||
|
require.Nil(t, av.PendingWaitSentinel)
|
||||||
|
require.EqualValues(t, types.BigAdd(createAmt, addFundsAmt), av.ConfirmedAmt)
|
||||||
|
require.EqualValues(t, 0, av.PendingAmt.Int64())
|
||||||
|
require.EqualValues(t, 0, av.QueuedAmt.Int64())
|
||||||
|
// voucher redeemed amount now includes vouchers
|
||||||
|
require.EqualValues(t, types.BigAdd(voucherAmt1, voucherAmt2), av.VoucherReedeemedAmt)
|
||||||
|
}
|
||||||
|
|
||||||
// waitForQueueSize waits for the funds request queue to be of the given size
|
// waitForQueueSize waits for the funds request queue to be of the given size
|
||||||
func waitForQueueSize(t *testing.T, mgr *Manager, from address.Address, to address.Address, size int) {
|
func waitForQueueSize(t *testing.T, mgr *Manager, from address.Address, to address.Address, size int) {
|
||||||
ca, err := mgr.accessorByFromTo(from, to)
|
ca, err := mgr.accessorByFromTo(from, to)
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||||
@ -34,8 +36,6 @@ type paychFundsRes struct {
|
|||||||
type fundsReq struct {
|
type fundsReq struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
promise chan *paychFundsRes
|
promise chan *paychFundsRes
|
||||||
from address.Address
|
|
||||||
to address.Address
|
|
||||||
amt types.BigInt
|
amt types.BigInt
|
||||||
|
|
||||||
lk sync.Mutex
|
lk sync.Mutex
|
||||||
@ -45,13 +45,11 @@ type fundsReq struct {
|
|||||||
active bool
|
active bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFundsReq(ctx context.Context, from address.Address, to address.Address, amt types.BigInt) *fundsReq {
|
func newFundsReq(ctx context.Context, amt types.BigInt) *fundsReq {
|
||||||
promise := make(chan *paychFundsRes)
|
promise := make(chan *paychFundsRes)
|
||||||
return &fundsReq{
|
return &fundsReq{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
promise: promise,
|
promise: promise,
|
||||||
from: from,
|
|
||||||
to: to,
|
|
||||||
amt: amt,
|
amt: amt,
|
||||||
active: true,
|
active: true,
|
||||||
}
|
}
|
||||||
@ -148,14 +146,6 @@ func (m *mergedFundsReq) onComplete(res *paychFundsRes) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mergedFundsReq) from() address.Address {
|
|
||||||
return m.reqs[0].from
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mergedFundsReq) to() address.Address {
|
|
||||||
return m.reqs[0].to
|
|
||||||
}
|
|
||||||
|
|
||||||
// sum is the sum of the amounts in all requests in the merge
|
// sum is the sum of the amounts in all requests in the merge
|
||||||
func (m *mergedFundsReq) sum() types.BigInt {
|
func (m *mergedFundsReq) sum() types.BigInt {
|
||||||
sum := types.NewInt(0)
|
sum := types.NewInt(0)
|
||||||
@ -178,9 +168,9 @@ func (m *mergedFundsReq) sum() types.BigInt {
|
|||||||
// address and the CID of the new add funds message.
|
// address and the CID of the new add funds message.
|
||||||
// If an operation returns an error, subsequent waiting operations will still
|
// If an operation returns an error, subsequent waiting operations will still
|
||||||
// be attempted.
|
// be attempted.
|
||||||
func (ca *channelAccessor) getPaych(ctx context.Context, from, to address.Address, amt types.BigInt) (address.Address, cid.Cid, error) {
|
func (ca *channelAccessor) getPaych(ctx context.Context, amt types.BigInt) (address.Address, cid.Cid, error) {
|
||||||
// Add the request to add funds to a queue and wait for the result
|
// Add the request to add funds to a queue and wait for the result
|
||||||
freq := newFundsReq(ctx, from, to, amt)
|
freq := newFundsReq(ctx, amt)
|
||||||
ca.enqueue(freq)
|
ca.enqueue(freq)
|
||||||
select {
|
select {
|
||||||
case res := <-freq.promise:
|
case res := <-freq.promise:
|
||||||
@ -191,17 +181,17 @@ func (ca *channelAccessor) getPaych(ctx context.Context, from, to address.Addres
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Queue up an add funds operations
|
// Queue up an add funds operation
|
||||||
func (ca *channelAccessor) enqueue(task *fundsReq) {
|
func (ca *channelAccessor) enqueue(task *fundsReq) {
|
||||||
ca.lk.Lock()
|
ca.lk.Lock()
|
||||||
defer ca.lk.Unlock()
|
defer ca.lk.Unlock()
|
||||||
|
|
||||||
ca.fundsReqQueue = append(ca.fundsReqQueue, task)
|
ca.fundsReqQueue = append(ca.fundsReqQueue, task)
|
||||||
go ca.processQueue()
|
go ca.processQueue() // nolint: errcheck
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the operations in the queue
|
// Run the operations in the queue
|
||||||
func (ca *channelAccessor) processQueue() {
|
func (ca *channelAccessor) processQueue() (*api.ChannelAvailableFunds, error) {
|
||||||
ca.lk.Lock()
|
ca.lk.Lock()
|
||||||
defer ca.lk.Unlock()
|
defer ca.lk.Unlock()
|
||||||
|
|
||||||
@ -210,7 +200,7 @@ func (ca *channelAccessor) processQueue() {
|
|||||||
|
|
||||||
// If there's nothing in the queue, bail out
|
// If there's nothing in the queue, bail out
|
||||||
if len(ca.fundsReqQueue) == 0 {
|
if len(ca.fundsReqQueue) == 0 {
|
||||||
return
|
return ca.currentAvailableFunds(types.NewInt(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge all pending requests into one.
|
// Merge all pending requests into one.
|
||||||
@ -221,17 +211,17 @@ func (ca *channelAccessor) processQueue() {
|
|||||||
if amt.IsZero() {
|
if amt.IsZero() {
|
||||||
// Note: The amount can be zero if requests are cancelled as we're
|
// Note: The amount can be zero if requests are cancelled as we're
|
||||||
// building the mergedFundsReq
|
// building the mergedFundsReq
|
||||||
return
|
return ca.currentAvailableFunds(amt)
|
||||||
}
|
}
|
||||||
|
|
||||||
res := ca.processTask(merged.ctx, merged.from(), merged.to(), amt)
|
res := ca.processTask(merged.ctx, amt)
|
||||||
|
|
||||||
// If the task is waiting on an external event (eg something to appear on
|
// If the task is waiting on an external event (eg something to appear on
|
||||||
// chain) it will return nil
|
// chain) it will return nil
|
||||||
if res == nil {
|
if res == nil {
|
||||||
// Stop processing the fundsReqQueue and wait. When the event occurs it will
|
// Stop processing the fundsReqQueue and wait. When the event occurs it will
|
||||||
// call processQueue() again
|
// call processQueue() again
|
||||||
return
|
return ca.currentAvailableFunds(amt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finished processing so clear the queue
|
// Finished processing so clear the queue
|
||||||
@ -239,6 +229,8 @@ func (ca *channelAccessor) processQueue() {
|
|||||||
|
|
||||||
// Call the task callback with its results
|
// Call the task callback with its results
|
||||||
merged.onComplete(res)
|
merged.onComplete(res)
|
||||||
|
|
||||||
|
return ca.currentAvailableFunds(types.NewInt(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
// filterQueue filters cancelled requests out of the queue
|
// filterQueue filters cancelled requests out of the queue
|
||||||
@ -291,32 +283,83 @@ func (ca *channelAccessor) msgWaitComplete(mcid cid.Cid, err error) {
|
|||||||
// The queue may have been waiting for msg completion to proceed, so
|
// The queue may have been waiting for msg completion to proceed, so
|
||||||
// process the next queue item
|
// process the next queue item
|
||||||
if len(ca.fundsReqQueue) > 0 {
|
if len(ca.fundsReqQueue) > 0 {
|
||||||
go ca.processQueue()
|
go ca.processQueue() // nolint: errcheck
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ca *channelAccessor) currentAvailableFunds(queuedAmt types.BigInt) (*api.ChannelAvailableFunds, error) {
|
||||||
|
channelInfo, err := ca.store.OutboundActiveByFromTo(ca.from, ca.to)
|
||||||
|
if err == ErrChannelNotTracked {
|
||||||
|
// If the channel does not exist we still want to return an empty
|
||||||
|
// ChannelAvailableFunds, so that clients can check for the existence
|
||||||
|
// of a channel between from / to without getting an error.
|
||||||
|
return &api.ChannelAvailableFunds{
|
||||||
|
Channel: nil,
|
||||||
|
ConfirmedAmt: types.NewInt(0),
|
||||||
|
PendingAmt: types.NewInt(0),
|
||||||
|
PendingWaitSentinel: nil,
|
||||||
|
QueuedAmt: queuedAmt,
|
||||||
|
VoucherReedeemedAmt: types.NewInt(0),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// The channel may have a pending create or add funds message
|
||||||
|
waitSentinel := channelInfo.CreateMsg
|
||||||
|
if waitSentinel == nil {
|
||||||
|
waitSentinel = channelInfo.AddFundsMsg
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the total amount redeemed by vouchers.
|
||||||
|
// This includes vouchers that have been submitted, and vouchers that are
|
||||||
|
// in the datastore but haven't yet been submitted.
|
||||||
|
totalRedeemed := types.NewInt(0)
|
||||||
|
if channelInfo.Channel != nil {
|
||||||
|
ch := *channelInfo.Channel
|
||||||
|
_, pchState, err := ca.sa.loadPaychActorState(ca.chctx, ch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
laneStates, err := ca.laneState(ca.chctx, pchState, ch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ls := range laneStates {
|
||||||
|
totalRedeemed = types.BigAdd(totalRedeemed, ls.Redeemed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &api.ChannelAvailableFunds{
|
||||||
|
Channel: channelInfo.Channel,
|
||||||
|
ConfirmedAmt: channelInfo.Amount,
|
||||||
|
PendingAmt: channelInfo.PendingAmount,
|
||||||
|
PendingWaitSentinel: waitSentinel,
|
||||||
|
QueuedAmt: queuedAmt,
|
||||||
|
VoucherReedeemedAmt: totalRedeemed,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// processTask checks the state of the channel and takes appropriate action
|
// processTask checks the state of the channel and takes appropriate action
|
||||||
// (see description of getPaych).
|
// (see description of getPaych).
|
||||||
// Note that processTask may be called repeatedly in the same state, and should
|
// Note that processTask may be called repeatedly in the same state, and should
|
||||||
// return nil if there is no state change to be made (eg when waiting for a
|
// return nil if there is no state change to be made (eg when waiting for a
|
||||||
// message to be confirmed on chain)
|
// message to be confirmed on chain)
|
||||||
func (ca *channelAccessor) processTask(
|
func (ca *channelAccessor) processTask(ctx context.Context, amt types.BigInt) *paychFundsRes {
|
||||||
ctx context.Context,
|
|
||||||
from address.Address,
|
|
||||||
to address.Address,
|
|
||||||
amt types.BigInt,
|
|
||||||
) *paychFundsRes {
|
|
||||||
// Get the payment channel for the from/to addresses.
|
// Get the payment channel for the from/to addresses.
|
||||||
// Note: It's ok if we get ErrChannelNotTracked. It just means we need to
|
// Note: It's ok if we get ErrChannelNotTracked. It just means we need to
|
||||||
// create a channel.
|
// create a channel.
|
||||||
channelInfo, err := ca.store.OutboundActiveByFromTo(from, to)
|
channelInfo, err := ca.store.OutboundActiveByFromTo(ca.from, ca.to)
|
||||||
if err != nil && err != ErrChannelNotTracked {
|
if err != nil && err != ErrChannelNotTracked {
|
||||||
return &paychFundsRes{err: err}
|
return &paychFundsRes{err: err}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a channel has not yet been created, create one.
|
// If a channel has not yet been created, create one.
|
||||||
if channelInfo == nil {
|
if channelInfo == nil {
|
||||||
mcid, err := ca.createPaych(ctx, from, to, amt)
|
mcid, err := ca.createPaych(ctx, amt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &paychFundsRes{err: err}
|
return &paychFundsRes{err: err}
|
||||||
}
|
}
|
||||||
@ -348,8 +391,8 @@ func (ca *channelAccessor) processTask(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// createPaych sends a message to create the channel and returns the message cid
|
// createPaych sends a message to create the channel and returns the message cid
|
||||||
func (ca *channelAccessor) createPaych(ctx context.Context, from, to address.Address, amt types.BigInt) (cid.Cid, error) {
|
func (ca *channelAccessor) createPaych(ctx context.Context, amt types.BigInt) (cid.Cid, error) {
|
||||||
params, aerr := actors.SerializeParams(&paych.ConstructorParams{From: from, To: to})
|
params, aerr := actors.SerializeParams(&paych.ConstructorParams{From: ca.from, To: ca.to})
|
||||||
if aerr != nil {
|
if aerr != nil {
|
||||||
return cid.Undef, aerr
|
return cid.Undef, aerr
|
||||||
}
|
}
|
||||||
@ -364,7 +407,7 @@ func (ca *channelAccessor) createPaych(ctx context.Context, from, to address.Add
|
|||||||
|
|
||||||
msg := &types.Message{
|
msg := &types.Message{
|
||||||
To: builtin.InitActorAddr,
|
To: builtin.InitActorAddr,
|
||||||
From: from,
|
From: ca.from,
|
||||||
Value: amt,
|
Value: amt,
|
||||||
Method: builtin.MethodsInit.Exec,
|
Method: builtin.MethodsInit.Exec,
|
||||||
Params: enc,
|
Params: enc,
|
||||||
@ -377,7 +420,7 @@ func (ca *channelAccessor) createPaych(ctx context.Context, from, to address.Add
|
|||||||
mcid := smsg.Cid()
|
mcid := smsg.Cid()
|
||||||
|
|
||||||
// Create a new channel in the store
|
// Create a new channel in the store
|
||||||
ci, err := ca.store.CreateChannel(from, to, mcid, amt)
|
ci, err := ca.store.CreateChannel(ca.from, ca.to, mcid, amt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("creating channel: %s", err)
|
log.Errorf("creating channel: %s", err)
|
||||||
return cid.Undef, err
|
return cid.Undef, err
|
||||||
@ -397,7 +440,7 @@ func (ca *channelAccessor) waitForPaychCreateMsg(channelID string, mcid cid.Cid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ca *channelAccessor) waitPaychCreateMsg(channelID string, mcid cid.Cid) error {
|
func (ca *channelAccessor) waitPaychCreateMsg(channelID string, mcid cid.Cid) error {
|
||||||
mwait, err := ca.api.StateWaitMsg(ca.waitCtx, mcid, build.MessageConfidence)
|
mwait, err := ca.api.StateWaitMsg(ca.chctx, mcid, build.MessageConfidence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("wait msg: %w", err)
|
log.Errorf("wait msg: %w", err)
|
||||||
return err
|
return err
|
||||||
@ -480,7 +523,7 @@ func (ca *channelAccessor) waitForAddFundsMsg(channelID string, mcid cid.Cid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ca *channelAccessor) waitAddFundsMsg(channelID string, mcid cid.Cid) error {
|
func (ca *channelAccessor) waitAddFundsMsg(channelID string, mcid cid.Cid) error {
|
||||||
mwait, err := ca.api.StateWaitMsg(ca.waitCtx, mcid, build.MessageConfidence)
|
mwait, err := ca.api.StateWaitMsg(ca.chctx, mcid, build.MessageConfidence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
return err
|
return err
|
||||||
@ -669,3 +712,7 @@ func (ca *channelAccessor) msgPromise(ctx context.Context, mcid cid.Cid) chan on
|
|||||||
|
|
||||||
return promise
|
return promise
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ca *channelAccessor) availableFunds() (*api.ChannelAvailableFunds, error) {
|
||||||
|
return ca.processQueue()
|
||||||
|
}
|
||||||
|
@ -59,12 +59,12 @@ type ChannelInfo struct {
|
|||||||
ChannelID string
|
ChannelID string
|
||||||
// Channel address - may be nil if the channel hasn't been created yet
|
// Channel address - may be nil if the channel hasn't been created yet
|
||||||
Channel *address.Address
|
Channel *address.Address
|
||||||
// Control is the address of the account that created the channel
|
// Control is the address of the local node
|
||||||
Control address.Address
|
Control address.Address
|
||||||
// Target is the address of the account on the other end of the channel
|
// Target is the address of the remote node (on the other end of the channel)
|
||||||
Target address.Address
|
Target address.Address
|
||||||
// Direction indicates if the channel is inbound (this node is the Target)
|
// Direction indicates if the channel is inbound (Control is the "to" address)
|
||||||
// or outbound (this node is the Control)
|
// or outbound (Control is the "from" address)
|
||||||
Direction uint64
|
Direction uint64
|
||||||
// Vouchers is a list of all vouchers sent on the channel
|
// Vouchers is a list of all vouchers sent on the channel
|
||||||
Vouchers []*VoucherInfo
|
Vouchers []*VoucherInfo
|
||||||
|
Loading…
Reference in New Issue
Block a user