From 92942d44d122af3d25f14130d0671db3f6d17e8b Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Fri, 9 Oct 2020 13:41:09 +0200 Subject: [PATCH 1/3] feat: lite-mode - market storage and retrieval clients --- api/api_gateway.go | 12 ++++ api/apistruct/struct.go | 85 ++++++++++++++++++----- api/test/ccupgrade.go | 2 +- api/test/deals.go | 29 +++++--- chain/stmgr/stmgr.go | 2 + chain/stmgr/utils.go | 19 ----- cmd/lotus-gateway/api.go | 107 ++++++++++++++++++++++------- cmd/lotus-gateway/api_test.go | 39 +++++++++-- cmd/lotus-gateway/endtoend_test.go | 86 +++++++++++++++++++---- markets/storageadapter/client.go | 24 +++---- node/builder.go | 1 - node/impl/full/chain.go | 17 +++-- node/impl/full/state.go | 82 +++++++++++++--------- node/impl/paych/paych.go | 5 -- node/modules/rpcstatemanager.go | 31 ++++++++- paychmgr/manager.go | 11 +-- 16 files changed, 394 insertions(+), 158 deletions(-) diff --git a/api/api_gateway.go b/api/api_gateway.go index c99ff8408..2b7b52b43 100644 --- a/api/api_gateway.go +++ b/api/api_gateway.go @@ -5,6 +5,8 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/types" "github.com/ipfs/go-cid" ) @@ -12,15 +14,25 @@ import ( type GatewayAPI interface { ChainHasObj(context.Context, cid.Cid) (bool, error) ChainHead(ctx context.Context) (*types.TipSet, error) + ChainGetBlockMessages(context.Context, cid.Cid) (*BlockMessages, error) + ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) + ChainNotify(context.Context) (<-chan []*HeadChange, error) ChainReadObj(context.Context, cid.Cid) ([]byte, error) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) + StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (DealCollateralBounds, error) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) + StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error) + StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) + StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (MarketBalance, error) + StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*MarketDeal, error) + StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) + StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*MsgLookup, error) } diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index e8e4ee33c..6811eff98 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -374,20 +374,29 @@ type WorkerStruct struct { type GatewayStruct struct { Internal struct { - // TODO: does the gateway need perms? - ChainHasObj func(context.Context, cid.Cid) (bool, error) - ChainGetTipSet func(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) - ChainGetTipSetByHeight func(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) - ChainHead func(ctx context.Context) (*types.TipSet, error) - ChainReadObj func(context.Context, cid.Cid) ([]byte, error) - GasEstimateMessageGas func(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) - MpoolPush func(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) - MsigGetAvailableBalance func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) - MsigGetVested func(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) - StateAccountKey func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) - StateGetActor func(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) - StateLookupID func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) - StateWaitMsg func(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) + ChainGetBlockMessages func(ctx context.Context, c cid.Cid) (*api.BlockMessages, error) + ChainGetMessage func(ctx context.Context, mc cid.Cid) (*types.Message, error) + ChainGetTipSet func(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) + ChainGetTipSetByHeight func(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) + ChainHasObj func(context.Context, cid.Cid) (bool, error) + ChainHead func(ctx context.Context) (*types.TipSet, error) + ChainNotify func(ctx context.Context) (<-chan []*api.HeadChange, error) + ChainReadObj func(context.Context, cid.Cid) ([]byte, error) + GasEstimateMessageGas func(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) + MpoolPush func(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) + MsigGetAvailableBalance func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) + MsigGetVested func(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) + StateAccountKey func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) + StateDealProviderCollateralBounds func(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (api.DealCollateralBounds, error) + StateGetActor func(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) + StateGetReceipt func(ctx context.Context, c cid.Cid, tsk types.TipSetKey) (*types.MessageReceipt, error) + StateLookupID func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) + StateListMiners func(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) + StateMinerInfo func(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) + StateMarketBalance func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error) + StateMarketStorageDeal func(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) + StateNetworkVersion func(ctx context.Context, tsk types.TipSetKey) (stnetwork.Version, error) + StateWaitMsg func(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) } } @@ -1450,12 +1459,12 @@ func (w *WorkerStruct) Closing(ctx context.Context) (<-chan struct{}, error) { return w.Internal.Closing(ctx) } -func (g GatewayStruct) ChainHasObj(ctx context.Context, c cid.Cid) (bool, error) { - return g.Internal.ChainHasObj(ctx, c) +func (g GatewayStruct) ChainGetBlockMessages(ctx context.Context, c cid.Cid) (*api.BlockMessages, error) { + return g.Internal.ChainGetBlockMessages(ctx, c) } -func (g GatewayStruct) ChainHead(ctx context.Context) (*types.TipSet, error) { - return g.Internal.ChainHead(ctx) +func (g GatewayStruct) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error) { + return g.Internal.ChainGetMessage(ctx, mc) } func (g GatewayStruct) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) { @@ -1466,6 +1475,18 @@ func (g GatewayStruct) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEp return g.Internal.ChainGetTipSetByHeight(ctx, h, tsk) } +func (g GatewayStruct) ChainHasObj(ctx context.Context, c cid.Cid) (bool, error) { + return g.Internal.ChainHasObj(ctx, c) +} + +func (g GatewayStruct) ChainHead(ctx context.Context) (*types.TipSet, error) { + return g.Internal.ChainHead(ctx) +} + +func (g GatewayStruct) ChainNotify(ctx context.Context) (<-chan []*api.HeadChange, error) { + return g.Internal.ChainNotify(ctx) +} + func (g GatewayStruct) ChainReadObj(ctx context.Context, c cid.Cid) ([]byte, error) { return g.Internal.ChainReadObj(ctx, c) } @@ -1490,14 +1511,42 @@ func (g GatewayStruct) StateAccountKey(ctx context.Context, addr address.Address return g.Internal.StateAccountKey(ctx, addr, tsk) } +func (g GatewayStruct) StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (api.DealCollateralBounds, error) { + return g.Internal.StateDealProviderCollateralBounds(ctx, size, verified, tsk) +} + func (g GatewayStruct) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) { return g.Internal.StateGetActor(ctx, actor, ts) } +func (g GatewayStruct) StateGetReceipt(ctx context.Context, c cid.Cid, tsk types.TipSetKey) (*types.MessageReceipt, error) { + return g.Internal.StateGetReceipt(ctx, c, tsk) +} + func (g GatewayStruct) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) { return g.Internal.StateLookupID(ctx, addr, tsk) } +func (g GatewayStruct) StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) { + return g.Internal.StateListMiners(ctx, tsk) +} + +func (g GatewayStruct) StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error) { + return g.Internal.StateMarketBalance(ctx, addr, tsk) +} + +func (g GatewayStruct) StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) { + return g.Internal.StateMarketStorageDeal(ctx, dealId, tsk) +} + +func (g GatewayStruct) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) { + return g.Internal.StateMinerInfo(ctx, actor, tsk) +} + +func (g GatewayStruct) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (stnetwork.Version, error) { + return g.Internal.StateNetworkVersion(ctx, tsk) +} + func (g GatewayStruct) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) { return g.Internal.StateWaitMsg(ctx, msg, confidence) } diff --git a/api/test/ccupgrade.go b/api/test/ccupgrade.go index e8010bdd4..75f72d861 100644 --- a/api/test/ccupgrade.go +++ b/api/test/ccupgrade.go @@ -89,7 +89,7 @@ func testCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration, upgradeH t.Fatal(err) } - makeDeal(t, ctx, 6, client, miner, false, false) + MakeDeal(t, ctx, 6, client, miner, false, false) // Validate upgrade diff --git a/api/test/deals.go b/api/test/deals.go index ed856445b..2317131f8 100644 --- a/api/test/deals.go +++ b/api/test/deals.go @@ -60,7 +60,7 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport } }() - makeDeal(t, ctx, 6, client, miner, carExport, fastRet) + MakeDeal(t, ctx, 6, client, miner, carExport, fastRet) atomic.AddInt64(&mine, -1) fmt.Println("shutting down mining") @@ -97,24 +97,35 @@ func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) { } }() - makeDeal(t, ctx, 6, client, miner, false, false) - makeDeal(t, ctx, 7, client, miner, false, false) + MakeDeal(t, ctx, 6, client, miner, false, false) + MakeDeal(t, ctx, 7, client, miner, false, false) atomic.AddInt64(&mine, -1) fmt.Println("shutting down mining") <-done } -func makeDeal(t *testing.T, ctx context.Context, rseed int, client *impl.FullNodeAPI, miner TestStorageNode, carExport, fastRet bool) { +func MakeDeal(t *testing.T, ctx context.Context, rseed int, client api.FullNode, miner TestStorageNode, carExport, fastRet bool) { data := make([]byte, 1600) rand.New(rand.NewSource(int64(rseed))).Read(data) - r := bytes.NewReader(data) - fcid, err := client.ClientImportLocal(ctx, r) + dir, err := ioutil.TempDir(os.TempDir(), "test-make-deal-") if err != nil { t.Fatal(err) } + path := filepath.Join(dir, "sourcefile.dat") + err = ioutil.WriteFile(path, data, 0644) + if err != nil { + t.Fatal(err) + } + + res, err := client.ClientImport(ctx, api.FileRef{Path: path}) + if err != nil { + t.Fatal(err) + } + + fcid := res.Root fmt.Println("FILE CID: ", fcid) deal := startDeal(t, ctx, miner, client, fcid, fastRet) @@ -259,7 +270,7 @@ func TestSenondDealRetrieval(t *testing.T, b APIBuilder, blocktime time.Duration <-done } -func startDeal(t *testing.T, ctx context.Context, miner TestStorageNode, client *impl.FullNodeAPI, fcid cid.Cid, fastRet bool) *cid.Cid { +func startDeal(t *testing.T, ctx context.Context, miner TestStorageNode, client api.FullNode, fcid cid.Cid, fastRet bool) *cid.Cid { maddr, err := miner.ActorAddress(ctx) if err != nil { t.Fatal(err) @@ -286,7 +297,7 @@ func startDeal(t *testing.T, ctx context.Context, miner TestStorageNode, client return deal } -func waitDealSealed(t *testing.T, ctx context.Context, miner TestStorageNode, client *impl.FullNodeAPI, deal *cid.Cid, noseal bool) { +func waitDealSealed(t *testing.T, ctx context.Context, miner TestStorageNode, client api.FullNode, deal *cid.Cid, noseal bool) { loop: for { di, err := client.ClientGetDealInfo(ctx, *deal) @@ -359,7 +370,7 @@ func startSealingWaiting(t *testing.T, ctx context.Context, miner TestStorageNod } } -func testRetrieval(t *testing.T, ctx context.Context, client *impl.FullNodeAPI, fcid cid.Cid, piece *cid.Cid, carExport bool, data []byte) { +func testRetrieval(t *testing.T, ctx context.Context, client api.FullNode, fcid cid.Cid, piece *cid.Cid, carExport bool, data []byte) { offers, err := client.ClientFindData(ctx, fcid, piece) if err != nil { t.Fatal(err) diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index 4f0c26b7c..2822344b0 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -46,6 +46,8 @@ const LookbackNoLimit = abi.ChainEpoch(-1) var log = logging.Logger("statemgr") type StateManagerAPI interface { + Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) + GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error) LoadActorTsk(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*types.Actor, error) LookupID(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index 7c744f60f..54f75c138 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -255,25 +255,6 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S return out, nil } -func StateMinerInfo(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (*miner.MinerInfo, error) { - act, err := sm.LoadActor(ctx, maddr, ts) - if err != nil { - return nil, xerrors.Errorf("failed to load miner actor: %w", err) - } - - mas, err := miner.Load(sm.cs.Store(ctx), act) - if err != nil { - return nil, xerrors.Errorf("failed to load miner actor state: %w", err) - } - - mi, err := mas.Info() - if err != nil { - return nil, err - } - - return &mi, err -} - func GetMinerSlashed(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (bool, error) { act, err := sm.LoadActor(ctx, power.Address, ts) if err != nil { diff --git a/cmd/lotus-gateway/api.go b/cmd/lotus-gateway/api.go index 7fc004327..0ebb99298 100644 --- a/cmd/lotus-gateway/api.go +++ b/cmd/lotus-gateway/api.go @@ -24,7 +24,7 @@ import ( const ( LookbackCap = time.Hour * 24 - stateWaitLookbackLimit = abi.ChainEpoch(20) + StateWaitLookbackLimit = abi.ChainEpoch(20) ) var ( @@ -35,20 +35,28 @@ var ( // (to make it easy to mock for tests) type gatewayDepsAPI interface { Version(context.Context) (api.Version, error) - - ChainHasObj(context.Context, cid.Cid) (bool, error) - ChainHead(ctx context.Context) (*types.TipSet, error) + ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error) + ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error) + ChainGetNode(ctx context.Context, p string) (*api.IpldObject, error) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) + ChainHasObj(context.Context, cid.Cid) (bool, error) + ChainHead(ctx context.Context) (*types.TipSet, error) + ChainNotify(context.Context) (<-chan []*api.HeadChange, error) ChainReadObj(context.Context, cid.Cid) ([]byte, error) - ChainGetNode(ctx context.Context, p string) (*api.IpldObject, error) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) MpoolPushUntrusted(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) + StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (api.DealCollateralBounds, error) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) + StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) + StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) + StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error) + StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) + StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error) StateWaitMsgLimited(ctx context.Context, msg cid.Cid, confidence uint64, h abi.ChainEpoch) (*api.MsgLookup, error) StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*api.ActorState, error) StateMinerPower(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error) @@ -60,22 +68,22 @@ type gatewayDepsAPI interface { StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*dline.Info, error) StateCirculatingSupply(context.Context, types.TipSetKey) (abi.TokenAmount, error) StateVMCirculatingSupplyInternal(context.Context, types.TipSetKey) (api.CirculatingSupply, error) - StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error) } type GatewayAPI struct { - api gatewayDepsAPI - lookbackCap time.Duration + api gatewayDepsAPI + lookbackCap time.Duration + stateWaitLookbackLimit abi.ChainEpoch } // NewGatewayAPI creates a new GatewayAPI with the default lookback cap func NewGatewayAPI(api gatewayDepsAPI) *GatewayAPI { - return newGatewayAPI(api, LookbackCap) + return newGatewayAPI(api, LookbackCap, StateWaitLookbackLimit) } // used by the tests -func newGatewayAPI(api gatewayDepsAPI, lookbackCap time.Duration) *GatewayAPI { - return &GatewayAPI{api: api, lookbackCap: lookbackCap} +func newGatewayAPI(api gatewayDepsAPI, lookbackCap time.Duration, stateWaitLookbackLimit abi.ChainEpoch) *GatewayAPI { + return &GatewayAPI{api: api, lookbackCap: lookbackCap, stateWaitLookbackLimit: stateWaitLookbackLimit} } func (a *GatewayAPI) checkTipsetKey(ctx context.Context, tsk types.TipSetKey) error { @@ -122,6 +130,10 @@ func (a *GatewayAPI) Version(ctx context.Context) (api.Version, error) { return a.api.Version(ctx) } +func (a *GatewayAPI) ChainGetBlockMessages(ctx context.Context, c cid.Cid) (*api.BlockMessages, error) { + return a.api.ChainGetBlockMessages(ctx, c) +} + func (a *GatewayAPI) ChainHasObj(ctx context.Context, c cid.Cid) (bool, error) { return a.api.ChainHasObj(ctx, c) } @@ -132,6 +144,10 @@ func (a *GatewayAPI) ChainHead(ctx context.Context) (*types.TipSet, error) { return a.api.ChainHead(ctx) } +func (a *GatewayAPI) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error) { + return a.api.ChainGetMessage(ctx, mc) +} + func (a *GatewayAPI) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) { return a.api.ChainGetTipSet(ctx, tsk) } @@ -165,14 +181,18 @@ func (a *GatewayAPI) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoc return a.api.ChainGetTipSetByHeight(ctx, h, tsk) } -func (a *GatewayAPI) ChainReadObj(ctx context.Context, c cid.Cid) ([]byte, error) { - return a.api.ChainReadObj(ctx, c) -} - func (a *GatewayAPI) ChainGetNode(ctx context.Context, p string) (*api.IpldObject, error) { return a.api.ChainGetNode(ctx, p) } +func (a *GatewayAPI) ChainNotify(ctx context.Context) (<-chan []*api.HeadChange, error) { + return a.api.ChainNotify(ctx) +} + +func (a *GatewayAPI) ChainReadObj(ctx context.Context, c cid.Cid) ([]byte, error) { + return a.api.ChainReadObj(ctx, c) +} + func (a *GatewayAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) { if err := a.checkTipsetKey(ctx, tsk); err != nil { return nil, err @@ -213,6 +233,14 @@ func (a *GatewayAPI) StateAccountKey(ctx context.Context, addr address.Address, return a.api.StateAccountKey(ctx, addr, tsk) } +func (a *GatewayAPI) StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (api.DealCollateralBounds, error) { + if err := a.checkTipsetKey(ctx, tsk); err != nil { + return api.DealCollateralBounds{}, err + } + + return a.api.StateDealProviderCollateralBounds(ctx, size, verified, tsk) +} + func (a *GatewayAPI) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) { if err := a.checkTipsetKey(ctx, tsk); err != nil { return nil, err @@ -221,6 +249,22 @@ func (a *GatewayAPI) StateGetActor(ctx context.Context, actor address.Address, t return a.api.StateGetActor(ctx, actor, tsk) } +func (a *GatewayAPI) StateGetReceipt(ctx context.Context, c cid.Cid, tsk types.TipSetKey) (*types.MessageReceipt, error) { + if err := a.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + + return a.api.StateGetReceipt(ctx, c, tsk) +} + +func (a *GatewayAPI) StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) { + if err := a.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + + return a.api.StateListMiners(ctx, tsk) +} + func (a *GatewayAPI) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) { if err := a.checkTipsetKey(ctx, tsk); err != nil { return address.Undef, err @@ -229,8 +273,32 @@ func (a *GatewayAPI) StateLookupID(ctx context.Context, addr address.Address, ts return a.api.StateLookupID(ctx, addr, tsk) } +func (a *GatewayAPI) StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error) { + if err := a.checkTipsetKey(ctx, tsk); err != nil { + return api.MarketBalance{}, err + } + + return a.api.StateMarketBalance(ctx, addr, tsk) +} + +func (a *GatewayAPI) StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) { + if err := a.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + + return a.api.StateMarketStorageDeal(ctx, dealId, tsk) +} + +func (a *GatewayAPI) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (network.Version, error) { + if err := a.checkTipsetKey(ctx, tsk); err != nil { + return network.VersionMax, err + } + + return a.api.StateNetworkVersion(ctx, tsk) +} + func (a *GatewayAPI) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) { - return a.api.StateWaitMsgLimited(ctx, msg, confidence, stateWaitLookbackLimit) + return a.api.StateWaitMsgLimited(ctx, msg, confidence, a.stateWaitLookbackLimit) } func (a *GatewayAPI) StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*api.ActorState, error) { @@ -303,13 +371,6 @@ func (a *GatewayAPI) StateVMCirculatingSupplyInternal(ctx context.Context, tsk t return a.api.StateVMCirculatingSupplyInternal(ctx, tsk) } -func (a *GatewayAPI) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (network.Version, error) { - if err := a.checkTipsetKey(ctx, tsk); err != nil { - return 0, err - } - return a.api.StateNetworkVersion(ctx, tsk) -} - func (a *GatewayAPI) WalletVerify(ctx context.Context, k address.Address, msg []byte, sig *crypto.Signature) (bool, error) { return sigs.Verify(sig, k, msg) == nil, nil } diff --git a/cmd/lotus-gateway/api_test.go b/cmd/lotus-gateway/api_test.go index ae161945b..23d2cbf3a 100644 --- a/cmd/lotus-gateway/api_test.go +++ b/cmd/lotus-gateway/api_test.go @@ -6,6 +6,9 @@ import ( "testing" "time" + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/build" "github.com/stretchr/testify/require" @@ -116,6 +119,38 @@ func (m *mockGatewayDepsAPI) ChainHasObj(context.Context, cid.Cid) (bool, error) panic("implement me") } +func (m *mockGatewayDepsAPI) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error) { + panic("implement me") +} + +func (m *mockGatewayDepsAPI) ChainReadObj(ctx context.Context, c cid.Cid) ([]byte, error) { + panic("implement me") +} + +func (m *mockGatewayDepsAPI) StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (api.DealCollateralBounds, error) { + panic("implement me") +} + +func (m *mockGatewayDepsAPI) StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) { + panic("implement me") +} + +func (m *mockGatewayDepsAPI) StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error) { + panic("implement me") +} + +func (m *mockGatewayDepsAPI) StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) { + panic("implement me") +} + +func (m *mockGatewayDepsAPI) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) { + panic("implement me") +} + +func (m *mockGatewayDepsAPI) StateNetworkVersion(ctx context.Context, key types.TipSetKey) (network.Version, error) { + panic("implement me") +} + func (m *mockGatewayDepsAPI) ChainHead(ctx context.Context) (*types.TipSet, error) { m.lk.RLock() defer m.lk.RUnlock() @@ -165,10 +200,6 @@ func (m *mockGatewayDepsAPI) ChainGetTipSetByHeight(ctx context.Context, h abi.C return m.tipsets[h], nil } -func (m *mockGatewayDepsAPI) ChainReadObj(ctx context.Context, c cid.Cid) ([]byte, error) { - panic("implement me") -} - func (m *mockGatewayDepsAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) { panic("implement me") } diff --git a/cmd/lotus-gateway/endtoend_test.go b/cmd/lotus-gateway/endtoend_test.go index b043ce28c..c5b513f44 100644 --- a/cmd/lotus-gateway/endtoend_test.go +++ b/cmd/lotus-gateway/endtoend_test.go @@ -11,6 +11,7 @@ import ( "github.com/filecoin-project/lotus/cli" clitest "github.com/filecoin-project/lotus/cli/test" + logging "github.com/ipfs/go-log/v2" init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init" multisig2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/multisig" @@ -25,12 +26,14 @@ import ( "github.com/filecoin-project/lotus/api/client" "github.com/filecoin-project/lotus/api/test" "github.com/filecoin-project/lotus/chain/actors/policy" + "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node" builder "github.com/filecoin-project/lotus/node/test" ) const maxLookbackCap = time.Duration(math.MaxInt64) +const maxStateWaitLookbackLimit = stmgr.LookbackNoLimit func init() { policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1) @@ -38,15 +41,18 @@ func init() { policy.SetMinVerifiedDealSize(abi.NewStoragePower(256)) } -// TestEndToEndWalletMsig tests that wallet and msig API calls can be made -// on a lite node that is connected through a gateway to a full API node -func TestEndToEndWalletMsig(t *testing.T) { +// TestWalletMsig tests that API calls to wallet and msig can be made on a lite +// node that is connected through a gateway to a full API node +func TestWalletMsig(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") blocktime := 5 * time.Millisecond ctx := context.Background() - full, lite, closer := startNodes(ctx, t, blocktime, maxLookbackCap) - defer closer() + nodes := startNodes(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit) + defer nodes.closer() + + lite := nodes.lite + full := nodes.full // The full node starts with a wallet fullWalletAddr, err := full.WalletDefaultAddress(ctx) @@ -141,16 +147,19 @@ func TestEndToEndWalletMsig(t *testing.T) { require.True(t, approveReturn.Applied) } -// TestEndToEndMsigCLI tests that msig CLI calls can be made +// TestMsigCLI tests that msig CLI calls can be made // on a lite node that is connected through a gateway to a full API node -func TestEndToEndMsigCLI(t *testing.T) { +func TestMsigCLI(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") clitest.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() - full, lite, closer := startNodes(ctx, t, blocktime, maxLookbackCap) - defer closer() + nodes := startNodes(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit) + defer nodes.closer() + + lite := nodes.lite + full := nodes.full // The full node starts with a wallet fullWalletAddr, err := full.WalletDefaultAddress(ctx) @@ -190,7 +199,52 @@ func sendFunds(ctx context.Context, fromNode test.TestNode, fromAddr address.Add return nil } -func startNodes(ctx context.Context, t *testing.T, blocktime time.Duration, lookbackCap time.Duration) (test.TestNode, test.TestNode, jsonrpc.ClientCloser) { +func TestDealFlow(t *testing.T) { + _ = os.Setenv("BELLMAN_NO_GPU", "1") + + logging.SetLogLevel("miner", "ERROR") + logging.SetLogLevel("chainstore", "ERROR") + logging.SetLogLevel("chain", "ERROR") + logging.SetLogLevel("sub", "ERROR") + logging.SetLogLevel("storageminer", "ERROR") + + blocktime := 5 * time.Millisecond + ctx := context.Background() + nodes := startNodes(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit) + defer nodes.closer() + + full := nodes.full + lite := nodes.lite + + // The full node starts with a wallet + fullWalletAddr, err := full.WalletDefaultAddress(ctx) + require.NoError(t, err) + + // Create a wallet on the lite node + liteWalletAddr, err := lite.WalletNew(ctx, types.KTSecp256k1) + require.NoError(t, err) + + // Send some funds from the full node to the lite node + err = sendFunds(ctx, full, fullWalletAddr, liteWalletAddr, types.NewInt(1e18)) + require.NoError(t, err) + + test.MakeDeal(t, ctx, 6, lite, nodes.miner, false, false) +} + +type testNodes struct { + lite test.TestNode + full test.TestNode + miner test.TestStorageNode + closer jsonrpc.ClientCloser +} + +func startNodes( + ctx context.Context, + t *testing.T, + blocktime time.Duration, + lookbackCap time.Duration, + stateWaitLookbackLimit abi.ChainEpoch, +) *testNodes { var closer jsonrpc.ClientCloser // Create one miner and two full nodes. @@ -207,7 +261,8 @@ func startNodes(ctx context.Context, t *testing.T, blocktime time.Duration, look fullNode := nodes[0] // Create a gateway server in front of the full node - _, addr, err := builder.CreateRPCServer(newGatewayAPI(fullNode, lookbackCap)) + gapiImpl := newGatewayAPI(fullNode, lookbackCap, stateWaitLookbackLimit) + _, addr, err := builder.CreateRPCServer(gapiImpl) require.NoError(t, err) // Create a gateway client API that connects to the gateway server @@ -234,9 +289,16 @@ func startNodes(ctx context.Context, t *testing.T, blocktime time.Duration, look err = miner.NetConnect(ctx, fullAddr) require.NoError(t, err) + // Connect the miner and the lite node (so that the lite node can send + // data to the miner) + liteAddr, err := lite.NetAddrsListen(ctx) + require.NoError(t, err) + err = miner.NetConnect(ctx, liteAddr) + require.NoError(t, err) + // Start mining blocks bm := test.NewBlockMiner(ctx, t, miner, blocktime) bm.MineBlocks() - return full, lite, closer + return &testNodes{lite: lite, full: full, miner: miner, closer: closer} } diff --git a/markets/storageadapter/client.go b/markets/storageadapter/client.go index ad2b2df8a..f299dd4d5 100644 --- a/markets/storageadapter/client.go +++ b/markets/storageadapter/client.go @@ -27,8 +27,6 @@ import ( "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/events/state" "github.com/filecoin-project/lotus/chain/market" - "github.com/filecoin-project/lotus/chain/stmgr" - "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/lib/sigs" "github.com/filecoin-project/lotus/markets/utils" @@ -40,8 +38,6 @@ type ClientNodeAdapter struct { full.ChainAPI full.MpoolAPI - sm *stmgr.StateManager - cs *store.ChainStore fm *market.FundMgr ev *events.Events } @@ -51,14 +47,12 @@ type clientApi struct { full.StateAPI } -func NewClientNodeAdapter(state full.StateAPI, chain full.ChainAPI, mpool full.MpoolAPI, sm *stmgr.StateManager, cs *store.ChainStore, fm *market.FundMgr) storagemarket.StorageClientNode { +func NewClientNodeAdapter(state full.StateAPI, chain full.ChainAPI, mpool full.MpoolAPI, fm *market.FundMgr) storagemarket.StorageClientNode { return &ClientNodeAdapter{ StateAPI: state, ChainAPI: chain, MpoolAPI: mpool, - sm: sm, - cs: cs, fm: fm, ev: events.NewEvents(context.TODO(), &clientApi{chain, state}), } @@ -138,12 +132,12 @@ func (c *ClientNodeAdapter) GetBalance(ctx context.Context, addr address.Address func (c *ClientNodeAdapter) ValidatePublishedDeal(ctx context.Context, deal storagemarket.ClientDeal) (abi.DealID, error) { log.Infow("DEAL ACCEPTED!") - pubmsg, err := c.cs.GetMessage(*deal.PublishMessage) + pubmsg, err := c.ChainGetMessage(ctx, *deal.PublishMessage) if err != nil { return 0, xerrors.Errorf("getting deal publish message: %w", err) } - mi, err := stmgr.StateMinerInfo(ctx, c.sm, c.cs.GetHeaviestTipSet(), deal.Proposal.Provider) + mi, err := c.StateMinerInfo(ctx, deal.Proposal.Provider, types.EmptyTSK) if err != nil { return 0, xerrors.Errorf("getting miner worker failed: %w", err) } @@ -189,16 +183,16 @@ func (c *ClientNodeAdapter) ValidatePublishedDeal(ctx context.Context, deal stor } // TODO: timeout - _, ret, _, err := c.sm.WaitForMessage(ctx, *deal.PublishMessage, build.MessageConfidence, stmgr.LookbackNoLimit) + ret, err := c.StateWaitMsg(ctx, *deal.PublishMessage, build.MessageConfidence) if err != nil { return 0, xerrors.Errorf("waiting for deal publish message: %w", err) } - if ret.ExitCode != 0 { - return 0, xerrors.Errorf("deal publish failed: exit=%d", ret.ExitCode) + if ret.Receipt.ExitCode != 0 { + return 0, xerrors.Errorf("deal publish failed: exit=%d", ret.Receipt.ExitCode) } var res market2.PublishStorageDealsReturn - if err := res.UnmarshalCBOR(bytes.NewReader(ret.Return)); err != nil { + if err := res.UnmarshalCBOR(bytes.NewReader(ret.Receipt.Return)); err != nil { return 0, err } @@ -218,7 +212,7 @@ func (c *ClientNodeAdapter) DealProviderCollateralBounds(ctx context.Context, si func (c *ClientNodeAdapter) OnDealSectorCommitted(ctx context.Context, provider address.Address, dealId abi.DealID, cb storagemarket.DealSectorCommittedCallback) error { checkFunc := func(ts *types.TipSet) (done bool, more bool, err error) { - sd, err := stmgr.GetStorageDeal(ctx, c.StateManager, dealId, ts) + sd, err := c.StateMarketStorageDeal(ctx, dealId, ts.Key()) if err != nil { // TODO: This may be fine for some errors @@ -245,7 +239,7 @@ func (c *ClientNodeAdapter) OnDealSectorCommitted(ctx context.Context, provider return false, nil } - sd, err := stmgr.GetStorageDeal(ctx, c.StateManager, dealId, ts) + sd, err := c.StateMarketStorageDeal(ctx, dealId, ts.Key()) if err != nil { return false, xerrors.Errorf("failed to look up deal on chain: %w", err) } diff --git a/node/builder.go b/node/builder.go index 1dc12e80a..1d632c35c 100644 --- a/node/builder.go +++ b/node/builder.go @@ -250,7 +250,6 @@ func Online() Option { Override(new(*store.ChainStore), modules.ChainStore), Override(new(stmgr.UpgradeSchedule), stmgr.DefaultUpgradeSchedule()), Override(new(*stmgr.StateManager), stmgr.NewStateManagerWithUpgradeSchedule), - Override(new(stmgr.StateManagerAPI), From(new(*stmgr.StateManager))), Override(new(*wallet.LocalWallet), wallet.NewWallet), Override(new(wallet.Default), From(new(*wallet.LocalWallet))), Override(new(api.WalletAPI), From(new(wallet.MultiWallet))), diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index 095b51ed8..a3410b8db 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -40,8 +40,11 @@ import ( var log = logging.Logger("fullnode") type ChainModuleAPI interface { + ChainNotify(context.Context) (<-chan []*api.HeadChange, error) + ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error) ChainHasObj(context.Context, cid.Cid) (bool, error) ChainHead(context.Context) (*types.TipSet, error) + ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) ChainReadObj(context.Context, cid.Cid) ([]byte, error) @@ -67,8 +70,8 @@ type ChainAPI struct { Chain *store.ChainStore } -func (a *ChainAPI) ChainNotify(ctx context.Context) (<-chan []*api.HeadChange, error) { - return a.Chain.SubHeadChanges(ctx), nil +func (m *ChainModule) ChainNotify(ctx context.Context) (<-chan []*api.HeadChange, error) { + return m.Chain.SubHeadChanges(ctx), nil } func (m *ChainModule) ChainHead(context.Context) (*types.TipSet, error) { @@ -101,13 +104,13 @@ func (m *ChainModule) ChainGetTipSet(ctx context.Context, key types.TipSetKey) ( return m.Chain.LoadTipSet(key) } -func (a *ChainAPI) ChainGetBlockMessages(ctx context.Context, msg cid.Cid) (*api.BlockMessages, error) { - b, err := a.Chain.GetBlock(msg) +func (m *ChainModule) ChainGetBlockMessages(ctx context.Context, msg cid.Cid) (*api.BlockMessages, error) { + b, err := m.Chain.GetBlock(msg) if err != nil { return nil, err } - bmsgs, smsgs, err := a.Chain.MessagesForBlock(b) + bmsgs, smsgs, err := m.Chain.MessagesForBlock(b) if err != nil { return nil, err } @@ -532,8 +535,8 @@ func (a *ChainAPI) ChainGetNode(ctx context.Context, p string) (*api.IpldObject, }, nil } -func (a *ChainAPI) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error) { - cm, err := a.Chain.GetCMessage(mc) +func (m *ChainModule) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error) { + cm, err := m.Chain.GetCMessage(mc) if err != nil { return nil, err } diff --git a/node/impl/full/state.go b/node/impl/full/state.go index a6564296b..75ad03e7b 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -40,12 +40,19 @@ import ( ) type StateModuleAPI interface { - StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) - StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) - StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) - StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) + StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) + StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (api.DealCollateralBounds, error) + StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) + StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error) + StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) + StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) + StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error) + StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) + StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) + StateNetworkVersion(ctx context.Context, key types.TipSetKey) (network.Version, error) + StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) } // StateModule provides a default implementation of StateModuleAPI. @@ -112,13 +119,13 @@ func (a *StateAPI) StateMinerActiveSectors(ctx context.Context, maddr address.Ad return stmgr.GetMinerSectorSet(ctx, a.StateManager, ts, maddr, &activeSectors) } -func (a *StateAPI) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) { - act, err := a.StateManager.LoadActorTsk(ctx, actor, tsk) +func (m *StateModule) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) { + act, err := m.StateManager.LoadActorTsk(ctx, actor, tsk) if err != nil { return miner.MinerInfo{}, xerrors.Errorf("failed to load miner actor: %w", err) } - mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act) + mas, err := miner.Load(m.StateManager.ChainStore().Store(ctx), act) if err != nil { return miner.MinerInfo{}, xerrors.Errorf("failed to load miner actor state: %w", err) } @@ -563,20 +570,20 @@ func (a *StateAPI) StateSearchMsg(ctx context.Context, msg cid.Cid) (*api.MsgLoo return nil, nil } -func (a *StateAPI) StateGetReceipt(ctx context.Context, msg cid.Cid, tsk types.TipSetKey) (*types.MessageReceipt, error) { - ts, err := a.Chain.GetTipSetFromKey(tsk) +func (m *StateModule) StateGetReceipt(ctx context.Context, msg cid.Cid, tsk types.TipSetKey) (*types.MessageReceipt, error) { + ts, err := m.Chain.GetTipSetFromKey(tsk) if err != nil { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - return a.StateManager.GetReceipt(ctx, msg, ts) + return m.StateManager.GetReceipt(ctx, msg, ts) } -func (a *StateAPI) StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) { - ts, err := a.Chain.GetTipSetFromKey(tsk) +func (m *StateModule) StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) { + ts, err := m.Chain.GetTipSetFromKey(tsk) if err != nil { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - return stmgr.ListMinerActors(ctx, a.StateManager, ts) + return stmgr.ListMinerActors(ctx, m.StateManager, ts) } func (a *StateAPI) StateListActors(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) { @@ -587,12 +594,12 @@ func (a *StateAPI) StateListActors(ctx context.Context, tsk types.TipSetKey) ([] return a.StateManager.ListAllActors(ctx, ts) } -func (a *StateAPI) StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error) { - ts, err := a.Chain.GetTipSetFromKey(tsk) +func (m *StateModule) StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error) { + ts, err := m.Chain.GetTipSetFromKey(tsk) if err != nil { return api.MarketBalance{}, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - return a.StateManager.MarketBalance(ctx, addr, ts) + return m.StateManager.MarketBalance(ctx, addr, ts) } func (a *StateAPI) StateMarketParticipants(ctx context.Context, tsk types.TipSetKey) (map[string]api.MarketBalance, error) { @@ -676,12 +683,12 @@ func (a *StateAPI) StateMarketDeals(ctx context.Context, tsk types.TipSetKey) (m return out, nil } -func (a *StateAPI) StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) { - ts, err := a.Chain.GetTipSetFromKey(tsk) +func (m *StateModule) StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) { + ts, err := m.Chain.GetTipSetFromKey(tsk) if err != nil { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - return stmgr.GetStorageDeal(ctx, a.StateManager, dealId, ts) + return stmgr.GetStorageDeal(ctx, m.StateManager, dealId, ts) } func (a *StateAPI) StateChangedActors(ctx context.Context, old cid.Cid, new cid.Cid) (map[string]types.Actor, error) { @@ -1205,33 +1212,33 @@ var dealProviderCollateralDen = types.NewInt(100) // StateDealProviderCollateralBounds returns the min and max collateral a storage provider // can issue. It takes the deal size and verified status as parameters. -func (a *StateAPI) StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (api.DealCollateralBounds, error) { - ts, err := a.Chain.GetTipSetFromKey(tsk) +func (m *StateModule) StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (api.DealCollateralBounds, error) { + ts, err := m.Chain.GetTipSetFromKey(tsk) if err != nil { return api.DealCollateralBounds{}, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - pact, err := a.StateGetActor(ctx, power.Address, tsk) + pact, err := m.StateGetActor(ctx, power.Address, tsk) if err != nil { return api.DealCollateralBounds{}, xerrors.Errorf("failed to load power actor: %w", err) } - ract, err := a.StateGetActor(ctx, reward.Address, tsk) + ract, err := m.StateGetActor(ctx, reward.Address, tsk) if err != nil { return api.DealCollateralBounds{}, xerrors.Errorf("failed to load reward actor: %w", err) } - pst, err := power.Load(a.StateManager.ChainStore().Store(ctx), pact) + pst, err := power.Load(m.StateManager.ChainStore().Store(ctx), pact) if err != nil { return api.DealCollateralBounds{}, xerrors.Errorf("failed to load power actor state: %w", err) } - rst, err := reward.Load(a.StateManager.ChainStore().Store(ctx), ract) + rst, err := reward.Load(m.StateManager.ChainStore().Store(ctx), ract) if err != nil { return api.DealCollateralBounds{}, xerrors.Errorf("failed to load reward actor state: %w", err) } - circ, err := a.StateVMCirculatingSupplyInternal(ctx, ts.Key()) + circ, err := stateVMCirculatingSupplyInternal(ctx, ts.Key(), m.Chain, m.StateManager) if err != nil { return api.DealCollateralBounds{}, xerrors.Errorf("getting total circulating supply: %w", err) } @@ -1252,7 +1259,7 @@ func (a *StateAPI) StateDealProviderCollateralBounds(ctx context.Context, size a powClaim.QualityAdjPower, rewPow, circ.FilCirculating, - a.StateManager.GetNtwkVersion(ctx, ts.Height())) + m.StateManager.GetNtwkVersion(ctx, ts.Height())) return api.DealCollateralBounds{ Min: types.BigDiv(types.BigMul(min, dealProviderCollateralNum), dealProviderCollateralDen), Max: max, @@ -1273,23 +1280,32 @@ func (a *StateAPI) StateCirculatingSupply(ctx context.Context, tsk types.TipSetK } func (a *StateAPI) StateVMCirculatingSupplyInternal(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) { - ts, err := a.Chain.GetTipSetFromKey(tsk) + return stateVMCirculatingSupplyInternal(ctx, tsk, a.Chain, a.StateManager) +} +func stateVMCirculatingSupplyInternal( + ctx context.Context, + tsk types.TipSetKey, + cstore *store.ChainStore, + smgr *stmgr.StateManager, +) (api.CirculatingSupply, error) { + ts, err := cstore.GetTipSetFromKey(tsk) if err != nil { return api.CirculatingSupply{}, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - sTree, err := a.stateForTs(ctx, ts) + sTree, err := stateForTs(ctx, ts, cstore, smgr) if err != nil { return api.CirculatingSupply{}, err } - return a.StateManager.GetVMCirculatingSupplyDetailed(ctx, ts.Height(), sTree) + + return smgr.GetVMCirculatingSupplyDetailed(ctx, ts.Height(), sTree) } -func (a *StateAPI) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (network.Version, error) { - ts, err := a.Chain.GetTipSetFromKey(tsk) +func (m *StateModule) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (network.Version, error) { + ts, err := m.Chain.GetTipSetFromKey(tsk) if err != nil { return network.VersionMax, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - return a.StateManager.GetNtwkVersion(ctx, ts.Height()), nil + return m.StateManager.GetNtwkVersion(ctx, ts.Height()), nil } diff --git a/node/impl/paych/paych.go b/node/impl/paych/paych.go index af0a1db15..773a5efab 100644 --- a/node/impl/paych/paych.go +++ b/node/impl/paych/paych.go @@ -13,17 +13,12 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/types" - full "github.com/filecoin-project/lotus/node/impl/full" "github.com/filecoin-project/lotus/paychmgr" ) type PaychAPI struct { fx.In - full.MpoolAPI - full.WalletAPI - full.ChainAPI - PaychMgr *paychmgr.Manager } diff --git a/node/modules/rpcstatemanager.go b/node/modules/rpcstatemanager.go index 0ed054d45..7d7b92437 100644 --- a/node/modules/rpcstatemanager.go +++ b/node/modules/rpcstatemanager.go @@ -3,19 +3,40 @@ package modules import ( "context" - "github.com/filecoin-project/lotus/api" + "golang.org/x/xerrors" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/apibstore" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" + cbor "github.com/ipfs/go-ipld-cbor" ) type RPCStateManager struct { - gapi api.GatewayAPI + gapi api.GatewayAPI + cstore *cbor.BasicIpldStore } func NewRPCStateManager(api api.GatewayAPI) *RPCStateManager { - return &RPCStateManager{gapi: api} + cstore := cbor.NewCborStore(apibstore.NewAPIBlockstore(api)) + return &RPCStateManager{gapi: api, cstore: cstore} +} + +func (s *RPCStateManager) GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error) { + act, err := s.gapi.StateGetActor(ctx, addr, ts.Key()) + if err != nil { + return nil, nil, err + } + + actState, err := paych.Load(adt.WrapStore(ctx, s.cstore), act) + if err != nil { + return nil, nil, err + } + return act, actState, nil + } func (s *RPCStateManager) LoadActorTsk(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*types.Actor, error) { @@ -30,4 +51,8 @@ func (s *RPCStateManager) ResolveToKeyAddress(ctx context.Context, addr address. return s.gapi.StateAccountKey(ctx, addr, ts.Key()) } +func (s *RPCStateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) { + return nil, xerrors.Errorf("RPCStateManager does not implement StateManager.Call") +} + var _ stmgr.StateManagerAPI = (*RPCStateManager)(nil) diff --git a/paychmgr/manager.go b/paychmgr/manager.go index f2fc190c7..5e0aa88ce 100644 --- a/paychmgr/manager.go +++ b/paychmgr/manager.go @@ -16,7 +16,6 @@ import ( "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" @@ -61,14 +60,10 @@ type managerAPI interface { // managerAPIImpl is used to create a composite that implements managerAPI type managerAPIImpl struct { - *stmgr.StateManager + stmgr.StateManagerAPI paychAPI } -func (m *managerAPIImpl) AdtStore(ctx context.Context) adt.Store { - return m.ChainStore().Store(ctx) -} - type Manager struct { // The Manager context is used to terminate wait operations on shutdown ctx context.Context @@ -82,11 +77,11 @@ type Manager struct { channels map[string]*channelAccessor } -func NewManager(mctx helpers.MetricsCtx, lc fx.Lifecycle, sm *stmgr.StateManager, pchstore *Store, api PaychAPI) *Manager { +func NewManager(mctx helpers.MetricsCtx, lc fx.Lifecycle, sm stmgr.StateManagerAPI, pchstore *Store, api PaychAPI) *Manager { ctx := helpers.LifecycleCtx(mctx, lc) ctx, shutdown := context.WithCancel(ctx) - impl := &managerAPIImpl{StateManager: sm, paychAPI: &api} + impl := &managerAPIImpl{StateManagerAPI: sm, paychAPI: &api} return &Manager{ ctx: ctx, shutdown: shutdown, From 906286fdbe245a286cb4e0340d0dafeee1a01bc9 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Tue, 20 Oct 2020 17:08:25 +0200 Subject: [PATCH 2/3] feat: lite-mode - CLI tests for `lotus client` commands --- api/api_gateway.go | 1 + api/apistruct/struct.go | 5 ++ api/test/deals.go | 38 +++++---- cli/client.go | 74 +++++++++--------- cli/client_test.go | 22 ++++++ cli/helper.go | 43 +++++++++-- cli/multisig_test.go | 37 +-------- cli/test/client.go | 115 +++++++++++++++++++++++++++ cli/test/mockcli.go | 9 +++ cli/test/multisig.go | 9 --- cli/test/net.go | 41 ++++++++++ cli/test/util.go | 12 +++ cmd/lotus-gateway/api.go | 8 ++ cmd/lotus-gateway/endtoend_test.go | 120 +++++++++++++++-------------- node/impl/full/state.go | 9 ++- 15 files changed, 381 insertions(+), 162 deletions(-) create mode 100644 cli/client_test.go create mode 100644 cli/test/client.go create mode 100644 cli/test/net.go create mode 100644 cli/test/util.go diff --git a/api/api_gateway.go b/api/api_gateway.go index 2b7b52b43..5f31b8d31 100644 --- a/api/api_gateway.go +++ b/api/api_gateway.go @@ -34,5 +34,6 @@ type GatewayAPI interface { StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*MarketDeal, error) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error) + StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*MsgLookup, error) } diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index 6811eff98..6c6c19f23 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -396,6 +396,7 @@ type GatewayStruct struct { StateMarketBalance func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error) StateMarketStorageDeal func(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) StateNetworkVersion func(ctx context.Context, tsk types.TipSetKey) (stnetwork.Version, error) + StateVerifiedClientStatus func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) StateWaitMsg func(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) } } @@ -1547,6 +1548,10 @@ func (g GatewayStruct) StateNetworkVersion(ctx context.Context, tsk types.TipSet return g.Internal.StateNetworkVersion(ctx, tsk) } +func (g GatewayStruct) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) { + return g.Internal.StateVerifiedClientStatus(ctx, addr, tsk) +} + func (g GatewayStruct) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) { return g.Internal.StateWaitMsg(ctx, msg, confidence) } diff --git a/api/test/deals.go b/api/test/deals.go index 2317131f8..b81099d90 100644 --- a/api/test/deals.go +++ b/api/test/deals.go @@ -106,21 +106,7 @@ func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) { } func MakeDeal(t *testing.T, ctx context.Context, rseed int, client api.FullNode, miner TestStorageNode, carExport, fastRet bool) { - data := make([]byte, 1600) - rand.New(rand.NewSource(int64(rseed))).Read(data) - - dir, err := ioutil.TempDir(os.TempDir(), "test-make-deal-") - if err != nil { - t.Fatal(err) - } - - path := filepath.Join(dir, "sourcefile.dat") - err = ioutil.WriteFile(path, data, 0644) - if err != nil { - t.Fatal(err) - } - - res, err := client.ClientImport(ctx, api.FileRef{Path: path}) + res, data, err := CreateClientFile(ctx, client, rseed) if err != nil { t.Fatal(err) } @@ -141,6 +127,28 @@ func MakeDeal(t *testing.T, ctx context.Context, rseed int, client api.FullNode, testRetrieval(t, ctx, client, fcid, &info.PieceCID, carExport, data) } +func CreateClientFile(ctx context.Context, client api.FullNode, rseed int) (*api.ImportRes, []byte, error) { + data := make([]byte, 1600) + rand.New(rand.NewSource(int64(rseed))).Read(data) + + dir, err := ioutil.TempDir(os.TempDir(), "test-make-deal-") + if err != nil { + return nil, nil, err + } + + path := filepath.Join(dir, "sourcefile.dat") + err = ioutil.WriteFile(path, data, 0644) + if err != nil { + return nil, nil, err + } + + res, err := client.ClientImport(ctx, api.FileRef{Path: path}) + if err != nil { + return nil, nil, err + } + return res, data, nil +} + func TestFastRetrievalDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) { ctx := context.Background() diff --git a/cli/client.go b/cli/client.go index 83c452555..c3479a725 100644 --- a/cli/client.go +++ b/cli/client.go @@ -343,6 +343,7 @@ var clientDealCmd = &cli.Command{ } defer closer() ctx := ReqContext(cctx) + afmt := NewAppFmt(cctx.App) if cctx.NArg() != 4 { return xerrors.New("expected 4 args: dataCid, miner, price, duration") @@ -462,7 +463,7 @@ var clientDealCmd = &cli.Command{ return err } - fmt.Println(encoder.Encode(*proposal)) + afmt.Println(encoder.Encode(*proposal)) return nil }, @@ -477,6 +478,7 @@ func interactiveDeal(cctx *cli.Context) error { ctx := ReqContext(cctx) ctx, cancel := context.WithCancel(ctx) defer cancel() + afmt := NewAppFmt(cctx.App) state := "import" gib := types.NewInt(1 << 30) @@ -517,10 +519,10 @@ func interactiveDeal(cctx *cli.Context) error { } printErr := func(err error) { - fmt.Printf("%s %s\n", color.RedString("Error:"), err.Error()) + afmt.Printf("%s %s\n", color.RedString("Error:"), err.Error()) } - cs := readline.NewCancelableStdin(os.Stdin) + cs := readline.NewCancelableStdin(afmt.Stdin) go func() { <-ctx.Done() cs.Close() // nolint:errcheck @@ -537,7 +539,7 @@ uiLoop: switch state { case "import": - fmt.Print("Data CID (from " + color.YellowString("lotus client import") + "): ") + afmt.Print("Data CID (from " + color.YellowString("lotus client import") + "): ") _cidStr, _, err := rl.ReadLine() cidStr := string(_cidStr) @@ -560,7 +562,7 @@ uiLoop: state = "duration" case "duration": - fmt.Print("Deal duration (days): ") + afmt.Print("Deal duration (days): ") _daystr, _, err := rl.ReadLine() daystr := string(_daystr) @@ -605,7 +607,7 @@ uiLoop: continue } - fmt.Print("\nMake this a verified deal? (yes/no): ") + afmt.Print("\nMake this a verified deal? (yes/no): ") _yn, _, err := rl.ReadLine() yn := string(_yn) @@ -619,13 +621,13 @@ uiLoop: case "no": verified = false default: - fmt.Println("Type in full 'yes' or 'no'") + afmt.Println("Type in full 'yes' or 'no'") continue } state = "miner" case "miner": - fmt.Print("Miner Addresses (f0.. f0..), none to find: ") + afmt.Print("Miner Addresses (f0.. f0..), none to find: ") _maddrsStr, _, err := rl.ReadLine() maddrsStr := string(_maddrsStr) @@ -664,11 +666,11 @@ uiLoop: candidateAsks = append(candidateAsks, ask) } - fmt.Printf("Found %d candidate asks\n", len(candidateAsks)) + afmt.Printf("Found %d candidate asks\n", len(candidateAsks)) state = "find-budget" case "find-budget": - fmt.Printf("Proposing from %s, Current Balance: %s\n", a, types.FIL(fromBal)) - fmt.Print("Maximum budget (FIL): ") // TODO: Propose some default somehow? + afmt.Printf("Proposing from %s, Current Balance: %s\n", a, types.FIL(fromBal)) + afmt.Print("Maximum budget (FIL): ") // TODO: Propose some default somehow? _budgetStr, _, err := rl.ReadLine() budgetStr := string(_budgetStr) @@ -698,10 +700,10 @@ uiLoop: } } candidateAsks = goodAsks - fmt.Printf("%d asks within budget\n", len(candidateAsks)) + afmt.Printf("%d asks within budget\n", len(candidateAsks)) state = "find-count" case "find-count": - fmt.Print("Deals to make (1): ") + afmt.Print("Deals to make (1): ") dealcStr, _, err := rl.ReadLine() if err != nil { printErr(xerrors.Errorf("reading deal count: %w", err)) @@ -780,12 +782,12 @@ uiLoop: case "confirm": // TODO: do some more or epochs math (round to miner PP, deal start buffer) - fmt.Printf("-----\n") - fmt.Printf("Proposing from %s\n", a) - fmt.Printf("\tBalance: %s\n", types.FIL(fromBal)) - fmt.Printf("\n") - fmt.Printf("Piece size: %s (Payload size: %s)\n", units.BytesSize(float64(ds.PieceSize)), units.BytesSize(float64(ds.PayloadSize))) - fmt.Printf("Duration: %s\n", dur) + afmt.Printf("-----\n") + afmt.Printf("Proposing from %s\n", a) + afmt.Printf("\tBalance: %s\n", types.FIL(fromBal)) + afmt.Printf("\n") + afmt.Printf("Piece size: %s (Payload size: %s)\n", units.BytesSize(float64(ds.PieceSize)), units.BytesSize(float64(ds.PayloadSize))) + afmt.Printf("Duration: %s\n", dur) pricePerGib := big.Zero() for _, a := range ask { @@ -804,7 +806,7 @@ uiLoop: if len(ask) > 1 { totalPrice := types.BigMul(epochPrice, types.NewInt(uint64(epochs))) - fmt.Printf("Miner %s (Power:%s) price: ~%s (%s per epoch)\n", color.YellowString(a.Miner.String()), color.GreenString(types.SizeStr(mpow.MinerPower.QualityAdjPower)), color.BlueString(types.FIL(totalPrice).String()), types.FIL(epochPrice)) + afmt.Printf("Miner %s (Power:%s) price: ~%s (%s per epoch)\n", color.YellowString(a.Miner.String()), color.GreenString(types.SizeStr(mpow.MinerPower.QualityAdjPower)), color.BlueString(types.FIL(totalPrice).String()), types.FIL(epochPrice)) } } @@ -812,12 +814,12 @@ uiLoop: epochPrice := types.BigDiv(types.BigMul(pricePerGib, types.NewInt(uint64(ds.PieceSize))), gib) totalPrice := types.BigMul(epochPrice, types.NewInt(uint64(epochs))) - fmt.Printf("Total price: ~%s (%s per epoch)\n", color.CyanString(types.FIL(totalPrice).String()), types.FIL(epochPrice)) - fmt.Printf("Verified: %v\n", verified) + afmt.Printf("Total price: ~%s (%s per epoch)\n", color.CyanString(types.FIL(totalPrice).String()), types.FIL(epochPrice)) + afmt.Printf("Verified: %v\n", verified) state = "accept" case "accept": - fmt.Print("\nAccept (yes/no): ") + afmt.Print("\nAccept (yes/no): ") _yn, _, err := rl.ReadLine() yn := string(_yn) @@ -830,7 +832,7 @@ uiLoop: } if yn != "yes" { - fmt.Println("Type in full 'yes' or 'no'") + afmt.Println("Type in full 'yes' or 'no'") continue } @@ -861,7 +863,7 @@ uiLoop: return err } - fmt.Printf("Deal (%s) CID: %s\n", maddr, color.GreenString(encoder.Encode(*proposal))) + afmt.Printf("Deal (%s) CID: %s\n", maddr, color.GreenString(encoder.Encode(*proposal))) } return nil @@ -975,6 +977,7 @@ var clientRetrieveCmd = &cli.Command{ } defer closer() ctx := ReqContext(cctx) + afmt := NewAppFmt(cctx.App) var payer address.Address if cctx.String("from") != "" { @@ -1083,14 +1086,14 @@ var clientRetrieveCmd = &cli.Command{ select { case evt, ok := <-updates: if ok { - fmt.Printf("> Recv: %s, Paid %s, %s (%s)\n", + afmt.Printf("> Recv: %s, Paid %s, %s (%s)\n", types.SizeStr(types.NewInt(evt.BytesReceived)), types.FIL(evt.FundsSpent), retrievalmarket.ClientEvents[evt.Event], retrievalmarket.DealStatuses[evt.Status], ) } else { - fmt.Println("Success") + afmt.Println("Success") return nil } @@ -1269,8 +1272,9 @@ var clientQueryAskCmd = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { + afmt := NewAppFmt(cctx.App) if cctx.NArg() != 1 { - fmt.Println("Usage: query-ask [minerAddress]") + afmt.Println("Usage: query-ask [minerAddress]") return nil } @@ -1311,23 +1315,23 @@ var clientQueryAskCmd = &cli.Command{ return err } - fmt.Printf("Ask: %s\n", maddr) - fmt.Printf("Price per GiB: %s\n", types.FIL(ask.Price)) - fmt.Printf("Verified Price per GiB: %s\n", types.FIL(ask.VerifiedPrice)) - fmt.Printf("Max Piece size: %s\n", types.SizeStr(types.NewInt(uint64(ask.MaxPieceSize)))) + afmt.Printf("Ask: %s\n", maddr) + afmt.Printf("Price per GiB: %s\n", types.FIL(ask.Price)) + afmt.Printf("Verified Price per GiB: %s\n", types.FIL(ask.VerifiedPrice)) + afmt.Printf("Max Piece size: %s\n", types.SizeStr(types.NewInt(uint64(ask.MaxPieceSize)))) size := cctx.Int64("size") if size == 0 { return nil } perEpoch := types.BigDiv(types.BigMul(ask.Price, types.NewInt(uint64(size))), types.NewInt(1<<30)) - fmt.Printf("Price per Block: %s\n", types.FIL(perEpoch)) + afmt.Printf("Price per Block: %s\n", types.FIL(perEpoch)) duration := cctx.Int64("duration") if duration == 0 { return nil } - fmt.Printf("Total Price: %s\n", types.FIL(types.BigMul(perEpoch, types.NewInt(uint64(duration))))) + afmt.Printf("Total Price: %s\n", types.FIL(types.BigMul(perEpoch, types.NewInt(uint64(duration))))) return nil }, @@ -1410,7 +1414,7 @@ var clientListDeals = &cli.Command{ } } - return outputStorageDeals(ctx, os.Stdout, api, localDeals, cctx.Bool("verbose"), cctx.Bool("color"), showFailed) + return outputStorageDeals(ctx, cctx.App.Writer, api, localDeals, cctx.Bool("verbose"), cctx.Bool("color"), showFailed) }, } diff --git a/cli/client_test.go b/cli/client_test.go new file mode 100644 index 000000000..f0e8efda8 --- /dev/null +++ b/cli/client_test.go @@ -0,0 +1,22 @@ +package cli + +import ( + "context" + "os" + "testing" + "time" + + clitest "github.com/filecoin-project/lotus/cli/test" +) + +// TestClient does a basic test to exercise the client CLI +// commands +func TestClient(t *testing.T) { + _ = os.Setenv("BELLMAN_NO_GPU", "1") + clitest.QuietMiningLogs() + + blocktime := 5 * time.Millisecond + ctx := context.Background() + clientNode, _ := clitest.StartOneNodeOneMiner(ctx, t, blocktime) + clitest.RunClientTest(t, Commands, clientNode) +} diff --git a/cli/helper.go b/cli/helper.go index 9398ead71..da236bcae 100644 --- a/cli/helper.go +++ b/cli/helper.go @@ -2,15 +2,16 @@ package cli import ( "fmt" + "io" "os" - "github.com/urfave/cli/v2" + ufcli "github.com/urfave/cli/v2" "golang.org/x/xerrors" ) type PrintHelpErr struct { Err error - Ctx *cli.Context + Ctx *ufcli.Context } func (e *PrintHelpErr) Error() string { @@ -26,11 +27,11 @@ func (e *PrintHelpErr) Is(o error) bool { return ok } -func ShowHelp(cctx *cli.Context, err error) error { +func ShowHelp(cctx *ufcli.Context, err error) error { return &PrintHelpErr{Err: err, Ctx: cctx} } -func RunApp(app *cli.App) { +func RunApp(app *ufcli.App) { if err := app.Run(os.Args); err != nil { if os.Getenv("LOTUS_DEV") != "" { log.Warnf("%+v", err) @@ -39,8 +40,40 @@ func RunApp(app *cli.App) { } var phe *PrintHelpErr if xerrors.As(err, &phe) { - _ = cli.ShowCommandHelp(phe.Ctx, phe.Ctx.Command.Name) + _ = ufcli.ShowCommandHelp(phe.Ctx, phe.Ctx.Command.Name) } os.Exit(1) } } + +type AppFmt struct { + app *ufcli.App + Stdin io.Reader +} + +func NewAppFmt(a *ufcli.App) *AppFmt { + var stdin io.Reader + istdin, ok := a.Metadata["stdin"] + if ok { + stdin = istdin.(io.Reader) + } else { + stdin = os.Stdin + } + return &AppFmt{app: a, Stdin: stdin} +} + +func (a *AppFmt) Print(args ...interface{}) { + fmt.Fprint(a.app.Writer, args...) +} + +func (a *AppFmt) Println(args ...interface{}) { + fmt.Fprintln(a.app.Writer, args...) +} + +func (a *AppFmt) Printf(fmtstr string, args ...interface{}) { + fmt.Fprintf(a.app.Writer, fmtstr, args...) +} + +func (a *AppFmt) Scan(args ...interface{}) (int, error) { + return fmt.Fscan(a.Stdin, args...) +} diff --git a/cli/multisig_test.go b/cli/multisig_test.go index 09cdbe056..82472cd62 100644 --- a/cli/multisig_test.go +++ b/cli/multisig_test.go @@ -6,50 +6,17 @@ import ( "testing" "time" - "github.com/filecoin-project/go-address" - "github.com/filecoin-project/lotus/api/test" clitest "github.com/filecoin-project/lotus/cli/test" - builder "github.com/filecoin-project/lotus/node/test" ) // TestMultisig does a basic test to exercise the multisig CLI // commands func TestMultisig(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") + clitest.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() - nodes, _ := startNodes(ctx, t, blocktime) - clientNode := nodes[0] + clientNode, _ := clitest.StartOneNodeOneMiner(ctx, t, blocktime) clitest.RunMultisigTest(t, Commands, clientNode) } - -func startNodes(ctx context.Context, t *testing.T, blocktime time.Duration) ([]test.TestNode, []address.Address) { - n, sn := builder.RPCMockSbBuilder(t, test.OneFull, test.OneMiner) - - full := n[0] - miner := sn[0] - - // Get everyone connected - addrs, err := full.NetAddrsListen(ctx) - if err != nil { - t.Fatal(err) - } - - if err := miner.NetConnect(ctx, addrs); err != nil { - t.Fatal(err) - } - - // Start mining blocks - bm := test.NewBlockMiner(ctx, t, miner, blocktime) - bm.MineBlocks() - - // Get the creator's address - creatorAddr, err := full.WalletDefaultAddress(ctx) - if err != nil { - t.Fatal(err) - } - - // Create mock CLI - return n, []address.Address{creatorAddr} -} diff --git a/cli/test/client.go b/cli/test/client.go new file mode 100644 index 000000000..3a5146219 --- /dev/null +++ b/cli/test/client.go @@ -0,0 +1,115 @@ +package test + +import ( + "context" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "regexp" + "strings" + "testing" + "time" + + "github.com/filecoin-project/lotus/api/test" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/specs-actors/v2/actors/builtin" + "github.com/stretchr/testify/require" + lcli "github.com/urfave/cli/v2" +) + +// RunClientTest exercises some of the client CLI commands +func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode test.TestNode) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // Create mock CLI + mockCLI := newMockCLI(t, cmds) + clientCLI := mockCLI.client(clientNode.ListenAddr) + + // Get the miner address + addrs, err := clientNode.StateListMiners(ctx, types.EmptyTSK) + require.NoError(t, err) + require.Len(t, addrs, 1) + + minerAddr := addrs[0] + fmt.Println("Miner:", minerAddr) + + // client query-ask + cmd := []string{ + "client", "query-ask", minerAddr.String(), + } + out := clientCLI.runCmd(cmd) + require.Regexp(t, regexp.MustCompile("Ask:"), out) + + // Create a deal (non-interactive) + // client deal 1000000attofil + res, _, err := test.CreateClientFile(ctx, clientNode, 1) + require.NoError(t, err) + dataCid := res.Root + price := "1000000attofil" + duration := fmt.Sprintf("%d", build.MinDealDuration) + cmd = []string{ + "client", "deal", dataCid.String(), minerAddr.String(), price, duration, + } + out = clientCLI.runCmd(cmd) + fmt.Println("client deal", out) + + // Create a deal (interactive) + // client deal + // + // (in days) + // + // "no" (verified client) + // "yes" (confirm deal) + res, _, err = test.CreateClientFile(ctx, clientNode, 2) + require.NoError(t, err) + dataCid2 := res.Root + duration = fmt.Sprintf("%d", build.MinDealDuration/builtin.EpochsInDay) + cmd = []string{ + "client", "deal", + } + interactiveCmds := []string{ + dataCid2.String(), + duration, + minerAddr.String(), + "no", + "yes", + } + out = clientCLI.runInteractiveCmd(cmd, interactiveCmds) + fmt.Println("client deal:\n", out) + + // Wait for provider to start sealing deal + dealStatus := "" + for dealStatus != "StorageDealSealing" { + // client list-deals + cmd = []string{"client", "list-deals"} + out = clientCLI.runCmd(cmd) + fmt.Println("list-deals:\n", out) + + lines := strings.Split(out, "\n") + require.Len(t, lines, 2) + re := regexp.MustCompile(`\s+`) + parts := re.Split(lines[1], -1) + if len(parts) < 4 { + require.Fail(t, "bad list-deals output format") + } + dealStatus = parts[3] + fmt.Println(" Deal status:", dealStatus) + + time.Sleep(time.Second) + } + + // Retrieve the first file from the miner + // client retrieve + tmpdir, err := ioutil.TempDir(os.TempDir(), "test-cli-client") + require.NoError(t, err) + path := filepath.Join(tmpdir, "outfile.dat") + cmd = []string{ + "client", "retrieve", dataCid.String(), path, + } + out = clientCLI.runCmd(cmd) + fmt.Println("retrieve:\n", out) + require.Regexp(t, regexp.MustCompile("Success"), out) +} diff --git a/cli/test/mockcli.go b/cli/test/mockcli.go index f5d5cfcba..c7eb70092 100644 --- a/cli/test/mockcli.go +++ b/cli/test/mockcli.go @@ -122,3 +122,12 @@ func (c *mockCLIClient) flagSet(cmd *lcli.Command) *flag.FlagSet { } return fs } + +func (c *mockCLIClient) runInteractiveCmd(cmd []string, interactive []string) string { + c.toStdin(strings.Join(interactive, "\n") + "\n") + return c.runCmd(cmd) +} + +func (c *mockCLIClient) toStdin(s string) { + c.cctx.App.Metadata["stdin"] = bytes.NewBufferString(s) +} diff --git a/cli/test/multisig.go b/cli/test/multisig.go index e77879346..d2c0238d2 100644 --- a/cli/test/multisig.go +++ b/cli/test/multisig.go @@ -10,19 +10,10 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/api/test" "github.com/filecoin-project/lotus/chain/types" - logging "github.com/ipfs/go-log/v2" "github.com/stretchr/testify/require" lcli "github.com/urfave/cli/v2" ) -func QuietMiningLogs() { - logging.SetLogLevel("miner", "ERROR") - logging.SetLogLevel("chainstore", "ERROR") - logging.SetLogLevel("chain", "ERROR") - logging.SetLogLevel("sub", "ERROR") - logging.SetLogLevel("storageminer", "ERROR") -} - func RunMultisigTest(t *testing.T, cmds []*lcli.Command, clientNode test.TestNode) { ctx := context.Background() diff --git a/cli/test/net.go b/cli/test/net.go new file mode 100644 index 000000000..d13993d16 --- /dev/null +++ b/cli/test/net.go @@ -0,0 +1,41 @@ +package test + +import ( + "context" + "testing" + "time" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/api/test" + test2 "github.com/filecoin-project/lotus/node/test" +) + +func StartOneNodeOneMiner(ctx context.Context, t *testing.T, blocktime time.Duration) (test.TestNode, address.Address) { + n, sn := test2.RPCMockSbBuilder(t, test.OneFull, test.OneMiner) + + full := n[0] + miner := sn[0] + + // Get everyone connected + addrs, err := full.NetAddrsListen(ctx) + if err != nil { + t.Fatal(err) + } + + if err := miner.NetConnect(ctx, addrs); err != nil { + t.Fatal(err) + } + + // Start mining blocks + bm := test.NewBlockMiner(ctx, t, miner, blocktime) + bm.MineBlocks() + + // Get the full node's wallet address + fullAddr, err := full.WalletDefaultAddress(ctx) + if err != nil { + t.Fatal(err) + } + + // Create mock CLI + return full, fullAddr +} diff --git a/cli/test/util.go b/cli/test/util.go new file mode 100644 index 000000000..e3930dc83 --- /dev/null +++ b/cli/test/util.go @@ -0,0 +1,12 @@ +package test + +import "github.com/ipfs/go-log/v2" + +func QuietMiningLogs() { + _ = log.SetLogLevel("miner", "ERROR") + _ = log.SetLogLevel("chainstore", "ERROR") + _ = log.SetLogLevel("chain", "ERROR") + _ = log.SetLogLevel("sub", "ERROR") + _ = log.SetLogLevel("storageminer", "ERROR") + _ = log.SetLogLevel("pubsub", "ERROR") +} diff --git a/cmd/lotus-gateway/api.go b/cmd/lotus-gateway/api.go index 0ebb99298..875eaac7d 100644 --- a/cmd/lotus-gateway/api.go +++ b/cmd/lotus-gateway/api.go @@ -67,6 +67,7 @@ type gatewayDepsAPI interface { StateMinerAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*dline.Info, error) StateCirculatingSupply(context.Context, types.TipSetKey) (abi.TokenAmount, error) + StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) StateVMCirculatingSupplyInternal(context.Context, types.TipSetKey) (api.CirculatingSupply, error) } @@ -364,6 +365,13 @@ func (a *GatewayAPI) StateCirculatingSupply(ctx context.Context, tsk types.TipSe } +func (a *GatewayAPI) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) { + if err := a.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return a.api.StateVerifiedClientStatus(ctx, addr, tsk) +} + func (a *GatewayAPI) StateVMCirculatingSupplyInternal(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) { if err := a.checkTipsetKey(ctx, tsk); err != nil { return api.CirculatingSupply{}, err diff --git a/cmd/lotus-gateway/endtoend_test.go b/cmd/lotus-gateway/endtoend_test.go index c5b513f44..1e1e5e229 100644 --- a/cmd/lotus-gateway/endtoend_test.go +++ b/cmd/lotus-gateway/endtoend_test.go @@ -11,7 +11,6 @@ import ( "github.com/filecoin-project/lotus/cli" clitest "github.com/filecoin-project/lotus/cli/test" - logging "github.com/ipfs/go-log/v2" init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init" multisig2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/multisig" @@ -45,6 +44,7 @@ func init() { // node that is connected through a gateway to a full API node func TestWalletMsig(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") + clitest.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() @@ -155,80 +155,35 @@ func TestMsigCLI(t *testing.T) { blocktime := 5 * time.Millisecond ctx := context.Background() - nodes := startNodes(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit) + nodes := startNodesWithFunds(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit) defer nodes.closer() lite := nodes.lite - full := nodes.full - - // The full node starts with a wallet - fullWalletAddr, err := full.WalletDefaultAddress(ctx) - require.NoError(t, err) - - // Create a wallet on the lite node - liteWalletAddr, err := lite.WalletNew(ctx, types.KTSecp256k1) - require.NoError(t, err) - - // Send some funds from the full node to the lite node - err = sendFunds(ctx, full, fullWalletAddr, liteWalletAddr, types.NewInt(1e18)) - require.NoError(t, err) - clitest.RunMultisigTest(t, cli.Commands, lite) } -func sendFunds(ctx context.Context, fromNode test.TestNode, fromAddr address.Address, toAddr address.Address, amt types.BigInt) error { - msg := &types.Message{ - From: fromAddr, - To: toAddr, - Value: amt, - } - - sm, err := fromNode.MpoolPushMessage(ctx, msg, nil) - if err != nil { - return err - } - - res, err := fromNode.StateWaitMsg(ctx, sm.Cid(), 1) - if err != nil { - return err - } - if res.Receipt.ExitCode != 0 { - return xerrors.Errorf("send funds failed with exit code %d", res.Receipt.ExitCode) - } - - return nil -} - func TestDealFlow(t *testing.T) { _ = os.Setenv("BELLMAN_NO_GPU", "1") - - logging.SetLogLevel("miner", "ERROR") - logging.SetLogLevel("chainstore", "ERROR") - logging.SetLogLevel("chain", "ERROR") - logging.SetLogLevel("sub", "ERROR") - logging.SetLogLevel("storageminer", "ERROR") + clitest.QuietMiningLogs() blocktime := 5 * time.Millisecond ctx := context.Background() - nodes := startNodes(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit) + nodes := startNodesWithFunds(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit) defer nodes.closer() - full := nodes.full - lite := nodes.lite + test.MakeDeal(t, ctx, 6, nodes.lite, nodes.miner, false, false) +} - // The full node starts with a wallet - fullWalletAddr, err := full.WalletDefaultAddress(ctx) - require.NoError(t, err) +func TestCLIDealFlow(t *testing.T) { + _ = os.Setenv("BELLMAN_NO_GPU", "1") + clitest.QuietMiningLogs() - // Create a wallet on the lite node - liteWalletAddr, err := lite.WalletNew(ctx, types.KTSecp256k1) - require.NoError(t, err) + blocktime := 5 * time.Millisecond + ctx := context.Background() + nodes := startNodesWithFunds(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit) + defer nodes.closer() - // Send some funds from the full node to the lite node - err = sendFunds(ctx, full, fullWalletAddr, liteWalletAddr, types.NewInt(1e18)) - require.NoError(t, err) - - test.MakeDeal(t, ctx, 6, lite, nodes.miner, false, false) + clitest.RunClientTest(t, cli.Commands, nodes.lite) } type testNodes struct { @@ -238,6 +193,30 @@ type testNodes struct { closer jsonrpc.ClientCloser } +func startNodesWithFunds( + ctx context.Context, + t *testing.T, + blocktime time.Duration, + lookbackCap time.Duration, + stateWaitLookbackLimit abi.ChainEpoch, +) *testNodes { + nodes := startNodes(ctx, t, blocktime, lookbackCap, stateWaitLookbackLimit) + + // The full node starts with a wallet + fullWalletAddr, err := nodes.full.WalletDefaultAddress(ctx) + require.NoError(t, err) + + // Create a wallet on the lite node + liteWalletAddr, err := nodes.lite.WalletNew(ctx, types.KTSecp256k1) + require.NoError(t, err) + + // Send some funds from the full node to the lite node + err = sendFunds(ctx, nodes.full, fullWalletAddr, liteWalletAddr, types.NewInt(1e18)) + require.NoError(t, err) + + return nodes +} + func startNodes( ctx context.Context, t *testing.T, @@ -302,3 +281,26 @@ func startNodes( return &testNodes{lite: lite, full: full, miner: miner, closer: closer} } + +func sendFunds(ctx context.Context, fromNode test.TestNode, fromAddr address.Address, toAddr address.Address, amt types.BigInt) error { + msg := &types.Message{ + From: fromAddr, + To: toAddr, + Value: amt, + } + + sm, err := fromNode.MpoolPushMessage(ctx, msg, nil) + if err != nil { + return err + } + + res, err := fromNode.StateWaitMsg(ctx, sm.Cid(), 1) + if err != nil { + return err + } + if res.Receipt.ExitCode != 0 { + return xerrors.Errorf("send funds failed with exit code %d", res.Receipt.ExitCode) + } + + return nil +} diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 75ad03e7b..d0e813758 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -52,6 +52,7 @@ type StateModuleAPI interface { StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) StateNetworkVersion(ctx context.Context, key types.TipSetKey) (network.Version, error) + StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) } @@ -1165,19 +1166,19 @@ func (a *StateAPI) StateVerifierStatus(ctx context.Context, addr address.Address // StateVerifiedClientStatus returns the data cap for the given address. // Returns zero if there is no entry in the data cap table for the // address. -func (a *StateAPI) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) { - act, err := a.StateGetActor(ctx, verifreg.Address, tsk) +func (m *StateModule) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) { + act, err := m.StateGetActor(ctx, verifreg.Address, tsk) if err != nil { return nil, err } - aid, err := a.StateLookupID(ctx, addr, tsk) + aid, err := m.StateLookupID(ctx, addr, tsk) if err != nil { log.Warnf("lookup failure %v", err) return nil, err } - vrs, err := verifreg.Load(a.StateManager.ChainStore().Store(ctx), act) + vrs, err := verifreg.Load(m.StateManager.ChainStore().Store(ctx), act) if err != nil { return nil, xerrors.Errorf("failed to load verified registry state: %w", err) } From 36816fb4f3281ad23c72a66b00b90eb73063036f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Fri, 23 Oct 2020 16:51:27 +0200 Subject: [PATCH 3/3] Fix list-asks, deals with non-genesis miners in lite-mode --- api/api_gateway.go | 7 ++++++- api/apistruct/struct.go | 10 ++++++++++ node/impl/client/client.go | 4 ++-- node/impl/full/state.go | 18 ++++++++++-------- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/api/api_gateway.go b/api/api_gateway.go index 5f31b8d31..07fb5deb3 100644 --- a/api/api_gateway.go +++ b/api/api_gateway.go @@ -3,12 +3,15 @@ package api import ( "context" + "github.com/ipfs/go-cid" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/dline" "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/types" - "github.com/ipfs/go-cid" ) type GatewayAPI interface { @@ -33,6 +36,8 @@ type GatewayAPI interface { StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (MarketBalance, error) StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*MarketDeal, error) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) + StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*dline.Info, error) + StateMinerPower(context.Context, address.Address, types.TipSetKey) (*MinerPower, error) StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*MsgLookup, error) diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index 6c6c19f23..883eeda46 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -393,6 +393,8 @@ type GatewayStruct struct { StateLookupID func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) StateListMiners func(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) StateMinerInfo func(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) + StateMinerProvingDeadline func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*dline.Info, error) + StateMinerPower func(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error) StateMarketBalance func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error) StateMarketStorageDeal func(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) StateNetworkVersion func(ctx context.Context, tsk types.TipSetKey) (stnetwork.Version, error) @@ -1544,6 +1546,14 @@ func (g GatewayStruct) StateMinerInfo(ctx context.Context, actor address.Address return g.Internal.StateMinerInfo(ctx, actor, tsk) } +func (g GatewayStruct) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*dline.Info, error) { + return g.Internal.StateMinerProvingDeadline(ctx, addr, tsk) +} + +func (g GatewayStruct) StateMinerPower(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*api.MinerPower, error) { + return g.Internal.StateMinerPower(ctx, addr, tsk) +} + func (g GatewayStruct) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (stnetwork.Version, error) { return g.Internal.StateNetworkVersion(ctx, tsk) } diff --git a/node/impl/client/client.go b/node/impl/client/client.go index 0cd164826..37a24998e 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -65,9 +65,9 @@ type API struct { fx.In full.ChainAPI - full.StateAPI full.WalletAPI paych.PaychAPI + full.StateAPI SMDealClient storagemarket.StorageClient RetDiscovery discovery.PeerResolver @@ -117,7 +117,7 @@ func (a *API) ClientStartDeal(ctx context.Context, params *api.StartDealParams) } } - walletKey, err := a.StateAPI.StateManager.ResolveToKeyAddress(ctx, params.Wallet, nil) + walletKey, err := a.StateAccountKey(ctx, params.Wallet, types.EmptyTSK) if err != nil { return nil, xerrors.Errorf("failed resolving params.Wallet addr: %w", params.Wallet) } diff --git a/node/impl/full/state.go b/node/impl/full/state.go index d0e813758..882b3e93c 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -51,6 +51,8 @@ type StateModuleAPI interface { StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error) StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) + StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*dline.Info, error) + StateMinerPower(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error) StateNetworkVersion(ctx context.Context, key types.TipSetKey) (network.Version, error) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) @@ -223,18 +225,18 @@ func (a *StateAPI) StateMinerPartitions(ctx context.Context, m address.Address, return out, err } -func (a *StateAPI) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*dline.Info, error) { - ts, err := a.StateManager.ChainStore().GetTipSetFromKey(tsk) +func (m *StateModule) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*dline.Info, error) { + ts, err := m.Chain.GetTipSetFromKey(tsk) if err != nil { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - act, err := a.StateManager.LoadActor(ctx, addr, ts) + act, err := m.StateManager.LoadActor(ctx, addr, ts) if err != nil { return nil, xerrors.Errorf("failed to load miner actor: %w", err) } - mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act) + mas, err := miner.Load(m.StateManager.ChainStore().Store(ctx), act) if err != nil { return nil, xerrors.Errorf("failed to load miner actor state: %w", err) } @@ -318,19 +320,19 @@ func (a *StateAPI) StateMinerRecoveries(ctx context.Context, addr address.Addres return miner.AllPartSectors(mas, miner.Partition.RecoveringSectors) } -func (a *StateAPI) StateMinerPower(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*api.MinerPower, error) { - ts, err := a.Chain.GetTipSetFromKey(tsk) +func (m *StateModule) StateMinerPower(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*api.MinerPower, error) { + ts, err := m.Chain.GetTipSetFromKey(tsk) if err != nil { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - m, net, hmp, err := stmgr.GetPower(ctx, a.StateManager, ts, addr) + mp, net, hmp, err := stmgr.GetPower(ctx, m.StateManager, ts, addr) if err != nil { return nil, err } return &api.MinerPower{ - MinerPower: m, + MinerPower: mp, TotalPower: net, HasMinPower: hmp, }, nil