Merge pull request #4263 from filecoin-project/feat/lite-market-client

lite-mode - market storage and retrieval clients
This commit is contained in:
Łukasz Magiera 2020-10-23 17:23:06 +02:00 committed by GitHub
commit dbcba6477e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 763 additions and 291 deletions

View File

@ -3,24 +3,42 @@ package api
import ( import (
"context" "context"
"github.com/ipfs/go-cid"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/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/filecoin-project/lotus/chain/types"
"github.com/ipfs/go-cid"
) )
type GatewayAPI interface { type GatewayAPI interface {
ChainHasObj(context.Context, cid.Cid) (bool, error) ChainHasObj(context.Context, cid.Cid) (bool, error)
ChainHead(ctx context.Context) (*types.TipSet, 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) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error)
ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, 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) ChainReadObj(context.Context, cid.Cid) ([]byte, error)
GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *MessageSendSpec, tsk types.TipSetKey) (*types.Message, 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) MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error)
MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, 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) 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) 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) 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) 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)
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) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*MsgLookup, error)
} }

View File

@ -374,20 +374,32 @@ type WorkerStruct struct {
type GatewayStruct struct { type GatewayStruct struct {
Internal struct { Internal struct {
// TODO: does the gateway need perms? ChainGetBlockMessages func(ctx context.Context, c cid.Cid) (*api.BlockMessages, error)
ChainHasObj func(context.Context, cid.Cid) (bool, error) ChainGetMessage func(ctx context.Context, mc cid.Cid) (*types.Message, error)
ChainGetTipSet func(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, 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) ChainGetTipSetByHeight func(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error)
ChainHead func(ctx context.Context) (*types.TipSet, error) ChainHasObj func(context.Context, cid.Cid) (bool, error)
ChainReadObj func(context.Context, cid.Cid) ([]byte, error) ChainHead func(ctx context.Context) (*types.TipSet, error)
GasEstimateMessageGas func(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) ChainNotify func(ctx context.Context) (<-chan []*api.HeadChange, error)
MpoolPush func(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) ChainReadObj func(context.Context, cid.Cid) ([]byte, error)
MsigGetAvailableBalance func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) GasEstimateMessageGas func(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error)
MsigGetVested func(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) MpoolPush func(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error)
StateAccountKey func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) MsigGetAvailableBalance func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error)
StateGetActor func(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) MsigGetVested func(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error)
StateLookupID func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) StateAccountKey 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) 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)
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)
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)
} }
} }
@ -1450,12 +1462,12 @@ func (w *WorkerStruct) Closing(ctx context.Context) (<-chan struct{}, error) {
return w.Internal.Closing(ctx) return w.Internal.Closing(ctx)
} }
func (g GatewayStruct) ChainHasObj(ctx context.Context, c cid.Cid) (bool, error) { func (g GatewayStruct) ChainGetBlockMessages(ctx context.Context, c cid.Cid) (*api.BlockMessages, error) {
return g.Internal.ChainHasObj(ctx, c) return g.Internal.ChainGetBlockMessages(ctx, c)
} }
func (g GatewayStruct) ChainHead(ctx context.Context) (*types.TipSet, error) { func (g GatewayStruct) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error) {
return g.Internal.ChainHead(ctx) return g.Internal.ChainGetMessage(ctx, mc)
} }
func (g GatewayStruct) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) { func (g GatewayStruct) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
@ -1466,6 +1478,18 @@ func (g GatewayStruct) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEp
return g.Internal.ChainGetTipSetByHeight(ctx, h, tsk) 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) { func (g GatewayStruct) ChainReadObj(ctx context.Context, c cid.Cid) ([]byte, error) {
return g.Internal.ChainReadObj(ctx, c) return g.Internal.ChainReadObj(ctx, c)
} }
@ -1490,14 +1514,54 @@ func (g GatewayStruct) StateAccountKey(ctx context.Context, addr address.Address
return g.Internal.StateAccountKey(ctx, addr, tsk) 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) { func (g GatewayStruct) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) {
return g.Internal.StateGetActor(ctx, actor, ts) 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) { func (g GatewayStruct) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
return g.Internal.StateLookupID(ctx, addr, tsk) 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) 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)
}
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) { func (g GatewayStruct) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) {
return g.Internal.StateWaitMsg(ctx, msg, confidence) return g.Internal.StateWaitMsg(ctx, msg, confidence)
} }

View File

@ -89,7 +89,7 @@ func testCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration, upgradeH
t.Fatal(err) t.Fatal(err)
} }
makeDeal(t, ctx, 6, client, miner, false, false) MakeDeal(t, ctx, 6, client, miner, false, false)
// Validate upgrade // Validate upgrade

View File

@ -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) atomic.AddInt64(&mine, -1)
fmt.Println("shutting down mining") fmt.Println("shutting down mining")
@ -97,24 +97,21 @@ func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
} }
}() }()
makeDeal(t, ctx, 6, client, miner, false, false) MakeDeal(t, ctx, 6, client, miner, false, false)
makeDeal(t, ctx, 7, client, miner, false, false) MakeDeal(t, ctx, 7, client, miner, false, false)
atomic.AddInt64(&mine, -1) atomic.AddInt64(&mine, -1)
fmt.Println("shutting down mining") fmt.Println("shutting down mining")
<-done <-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) res, data, err := CreateClientFile(ctx, client, rseed)
rand.New(rand.NewSource(int64(rseed))).Read(data)
r := bytes.NewReader(data)
fcid, err := client.ClientImportLocal(ctx, r)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
fcid := res.Root
fmt.Println("FILE CID: ", fcid) fmt.Println("FILE CID: ", fcid)
deal := startDeal(t, ctx, miner, client, fcid, fastRet) deal := startDeal(t, ctx, miner, client, fcid, fastRet)
@ -130,6 +127,28 @@ func makeDeal(t *testing.T, ctx context.Context, rseed int, client *impl.FullNod
testRetrieval(t, ctx, client, fcid, &info.PieceCID, carExport, data) 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) { func TestFastRetrievalDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
ctx := context.Background() ctx := context.Background()
@ -259,7 +278,7 @@ func TestSenondDealRetrieval(t *testing.T, b APIBuilder, blocktime time.Duration
<-done <-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) maddr, err := miner.ActorAddress(ctx)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -286,7 +305,7 @@ func startDeal(t *testing.T, ctx context.Context, miner TestStorageNode, client
return deal 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: loop:
for { for {
di, err := client.ClientGetDealInfo(ctx, *deal) di, err := client.ClientGetDealInfo(ctx, *deal)
@ -359,7 +378,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) offers, err := client.ClientFindData(ctx, fcid, piece)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View File

@ -46,6 +46,8 @@ const LookbackNoLimit = abi.ChainEpoch(-1)
var log = logging.Logger("statemgr") var log = logging.Logger("statemgr")
type StateManagerAPI interface { 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) 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) 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) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error)

View File

@ -255,25 +255,6 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S
return out, nil 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) { func GetMinerSlashed(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (bool, error) {
act, err := sm.LoadActor(ctx, power.Address, ts) act, err := sm.LoadActor(ctx, power.Address, ts)
if err != nil { if err != nil {

View File

@ -343,6 +343,7 @@ var clientDealCmd = &cli.Command{
} }
defer closer() defer closer()
ctx := ReqContext(cctx) ctx := ReqContext(cctx)
afmt := NewAppFmt(cctx.App)
if cctx.NArg() != 4 { if cctx.NArg() != 4 {
return xerrors.New("expected 4 args: dataCid, miner, price, duration") return xerrors.New("expected 4 args: dataCid, miner, price, duration")
@ -462,7 +463,7 @@ var clientDealCmd = &cli.Command{
return err return err
} }
fmt.Println(encoder.Encode(*proposal)) afmt.Println(encoder.Encode(*proposal))
return nil return nil
}, },
@ -477,6 +478,7 @@ func interactiveDeal(cctx *cli.Context) error {
ctx := ReqContext(cctx) ctx := ReqContext(cctx)
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
defer cancel() defer cancel()
afmt := NewAppFmt(cctx.App)
state := "import" state := "import"
gib := types.NewInt(1 << 30) gib := types.NewInt(1 << 30)
@ -517,10 +519,10 @@ func interactiveDeal(cctx *cli.Context) error {
} }
printErr := func(err 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() { go func() {
<-ctx.Done() <-ctx.Done()
cs.Close() // nolint:errcheck cs.Close() // nolint:errcheck
@ -537,7 +539,7 @@ uiLoop:
switch state { switch state {
case "import": 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, _, err := rl.ReadLine()
cidStr := string(_cidStr) cidStr := string(_cidStr)
@ -560,7 +562,7 @@ uiLoop:
state = "duration" state = "duration"
case "duration": case "duration":
fmt.Print("Deal duration (days): ") afmt.Print("Deal duration (days): ")
_daystr, _, err := rl.ReadLine() _daystr, _, err := rl.ReadLine()
daystr := string(_daystr) daystr := string(_daystr)
@ -605,7 +607,7 @@ uiLoop:
continue continue
} }
fmt.Print("\nMake this a verified deal? (yes/no): ") afmt.Print("\nMake this a verified deal? (yes/no): ")
_yn, _, err := rl.ReadLine() _yn, _, err := rl.ReadLine()
yn := string(_yn) yn := string(_yn)
@ -619,13 +621,13 @@ uiLoop:
case "no": case "no":
verified = false verified = false
default: default:
fmt.Println("Type in full 'yes' or 'no'") afmt.Println("Type in full 'yes' or 'no'")
continue continue
} }
state = "miner" state = "miner"
case "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, _, err := rl.ReadLine()
maddrsStr := string(_maddrsStr) maddrsStr := string(_maddrsStr)
@ -664,11 +666,11 @@ uiLoop:
candidateAsks = append(candidateAsks, ask) 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" state = "find-budget"
case "find-budget": case "find-budget":
fmt.Printf("Proposing from %s, Current Balance: %s\n", a, types.FIL(fromBal)) afmt.Printf("Proposing from %s, Current Balance: %s\n", a, types.FIL(fromBal))
fmt.Print("Maximum budget (FIL): ") // TODO: Propose some default somehow? afmt.Print("Maximum budget (FIL): ") // TODO: Propose some default somehow?
_budgetStr, _, err := rl.ReadLine() _budgetStr, _, err := rl.ReadLine()
budgetStr := string(_budgetStr) budgetStr := string(_budgetStr)
@ -698,10 +700,10 @@ uiLoop:
} }
} }
candidateAsks = goodAsks candidateAsks = goodAsks
fmt.Printf("%d asks within budget\n", len(candidateAsks)) afmt.Printf("%d asks within budget\n", len(candidateAsks))
state = "find-count" state = "find-count"
case "find-count": case "find-count":
fmt.Print("Deals to make (1): ") afmt.Print("Deals to make (1): ")
dealcStr, _, err := rl.ReadLine() dealcStr, _, err := rl.ReadLine()
if err != nil { if err != nil {
printErr(xerrors.Errorf("reading deal count: %w", err)) printErr(xerrors.Errorf("reading deal count: %w", err))
@ -780,12 +782,12 @@ uiLoop:
case "confirm": case "confirm":
// TODO: do some more or epochs math (round to miner PP, deal start buffer) // TODO: do some more or epochs math (round to miner PP, deal start buffer)
fmt.Printf("-----\n") afmt.Printf("-----\n")
fmt.Printf("Proposing from %s\n", a) afmt.Printf("Proposing from %s\n", a)
fmt.Printf("\tBalance: %s\n", types.FIL(fromBal)) afmt.Printf("\tBalance: %s\n", types.FIL(fromBal))
fmt.Printf("\n") afmt.Printf("\n")
fmt.Printf("Piece size: %s (Payload size: %s)\n", units.BytesSize(float64(ds.PieceSize)), units.BytesSize(float64(ds.PayloadSize))) afmt.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("Duration: %s\n", dur)
pricePerGib := big.Zero() pricePerGib := big.Zero()
for _, a := range ask { for _, a := range ask {
@ -804,7 +806,7 @@ uiLoop:
if len(ask) > 1 { if len(ask) > 1 {
totalPrice := types.BigMul(epochPrice, types.NewInt(uint64(epochs))) 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) epochPrice := types.BigDiv(types.BigMul(pricePerGib, types.NewInt(uint64(ds.PieceSize))), gib)
totalPrice := types.BigMul(epochPrice, types.NewInt(uint64(epochs))) 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)) afmt.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("Verified: %v\n", verified)
state = "accept" state = "accept"
case "accept": case "accept":
fmt.Print("\nAccept (yes/no): ") afmt.Print("\nAccept (yes/no): ")
_yn, _, err := rl.ReadLine() _yn, _, err := rl.ReadLine()
yn := string(_yn) yn := string(_yn)
@ -830,7 +832,7 @@ uiLoop:
} }
if yn != "yes" { if yn != "yes" {
fmt.Println("Type in full 'yes' or 'no'") afmt.Println("Type in full 'yes' or 'no'")
continue continue
} }
@ -861,7 +863,7 @@ uiLoop:
return err 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 return nil
@ -975,6 +977,7 @@ var clientRetrieveCmd = &cli.Command{
} }
defer closer() defer closer()
ctx := ReqContext(cctx) ctx := ReqContext(cctx)
afmt := NewAppFmt(cctx.App)
var payer address.Address var payer address.Address
if cctx.String("from") != "" { if cctx.String("from") != "" {
@ -1083,14 +1086,14 @@ var clientRetrieveCmd = &cli.Command{
select { select {
case evt, ok := <-updates: case evt, ok := <-updates:
if ok { 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.SizeStr(types.NewInt(evt.BytesReceived)),
types.FIL(evt.FundsSpent), types.FIL(evt.FundsSpent),
retrievalmarket.ClientEvents[evt.Event], retrievalmarket.ClientEvents[evt.Event],
retrievalmarket.DealStatuses[evt.Status], retrievalmarket.DealStatuses[evt.Status],
) )
} else { } else {
fmt.Println("Success") afmt.Println("Success")
return nil return nil
} }
@ -1269,8 +1272,9 @@ var clientQueryAskCmd = &cli.Command{
}, },
}, },
Action: func(cctx *cli.Context) error { Action: func(cctx *cli.Context) error {
afmt := NewAppFmt(cctx.App)
if cctx.NArg() != 1 { if cctx.NArg() != 1 {
fmt.Println("Usage: query-ask [minerAddress]") afmt.Println("Usage: query-ask [minerAddress]")
return nil return nil
} }
@ -1311,23 +1315,23 @@ var clientQueryAskCmd = &cli.Command{
return err return err
} }
fmt.Printf("Ask: %s\n", maddr) afmt.Printf("Ask: %s\n", maddr)
fmt.Printf("Price per GiB: %s\n", types.FIL(ask.Price)) afmt.Printf("Price per GiB: %s\n", types.FIL(ask.Price))
fmt.Printf("Verified Price per GiB: %s\n", types.FIL(ask.VerifiedPrice)) afmt.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("Max Piece size: %s\n", types.SizeStr(types.NewInt(uint64(ask.MaxPieceSize))))
size := cctx.Int64("size") size := cctx.Int64("size")
if size == 0 { if size == 0 {
return nil return nil
} }
perEpoch := types.BigDiv(types.BigMul(ask.Price, types.NewInt(uint64(size))), types.NewInt(1<<30)) 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") duration := cctx.Int64("duration")
if duration == 0 { if duration == 0 {
return nil 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 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)
}, },
} }

22
cli/client_test.go Normal file
View File

@ -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)
}

View File

@ -2,15 +2,16 @@ package cli
import ( import (
"fmt" "fmt"
"io"
"os" "os"
"github.com/urfave/cli/v2" ufcli "github.com/urfave/cli/v2"
"golang.org/x/xerrors" "golang.org/x/xerrors"
) )
type PrintHelpErr struct { type PrintHelpErr struct {
Err error Err error
Ctx *cli.Context Ctx *ufcli.Context
} }
func (e *PrintHelpErr) Error() string { func (e *PrintHelpErr) Error() string {
@ -26,11 +27,11 @@ func (e *PrintHelpErr) Is(o error) bool {
return ok return ok
} }
func ShowHelp(cctx *cli.Context, err error) error { func ShowHelp(cctx *ufcli.Context, err error) error {
return &PrintHelpErr{Err: err, Ctx: cctx} 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 err := app.Run(os.Args); err != nil {
if os.Getenv("LOTUS_DEV") != "" { if os.Getenv("LOTUS_DEV") != "" {
log.Warnf("%+v", err) log.Warnf("%+v", err)
@ -39,8 +40,40 @@ func RunApp(app *cli.App) {
} }
var phe *PrintHelpErr var phe *PrintHelpErr
if xerrors.As(err, &phe) { if xerrors.As(err, &phe) {
_ = cli.ShowCommandHelp(phe.Ctx, phe.Ctx.Command.Name) _ = ufcli.ShowCommandHelp(phe.Ctx, phe.Ctx.Command.Name)
} }
os.Exit(1) 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...)
}

View File

@ -6,50 +6,17 @@ import (
"testing" "testing"
"time" "time"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/api/test"
clitest "github.com/filecoin-project/lotus/cli/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 // TestMultisig does a basic test to exercise the multisig CLI
// commands // commands
func TestMultisig(t *testing.T) { func TestMultisig(t *testing.T) {
_ = os.Setenv("BELLMAN_NO_GPU", "1") _ = os.Setenv("BELLMAN_NO_GPU", "1")
clitest.QuietMiningLogs()
blocktime := 5 * time.Millisecond blocktime := 5 * time.Millisecond
ctx := context.Background() ctx := context.Background()
nodes, _ := startNodes(ctx, t, blocktime) clientNode, _ := clitest.StartOneNodeOneMiner(ctx, t, blocktime)
clientNode := nodes[0]
clitest.RunMultisigTest(t, Commands, clientNode) 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}
}

115
cli/test/client.go Normal file
View File

@ -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 <miner addr>
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 <cid> <miner addr> 1000000attofil <duration>
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
// <cid>
// <duration> (in days)
// <miner addr>
// "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 <cid> <file path>
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)
}

View File

@ -122,3 +122,12 @@ func (c *mockCLIClient) flagSet(cmd *lcli.Command) *flag.FlagSet {
} }
return fs 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)
}

View File

@ -10,19 +10,10 @@ import (
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/api/test" "github.com/filecoin-project/lotus/api/test"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
logging "github.com/ipfs/go-log/v2"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
lcli "github.com/urfave/cli/v2" 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) { func RunMultisigTest(t *testing.T, cmds []*lcli.Command, clientNode test.TestNode) {
ctx := context.Background() ctx := context.Background()

41
cli/test/net.go Normal file
View File

@ -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
}

12
cli/test/util.go Normal file
View File

@ -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")
}

View File

@ -24,7 +24,7 @@ import (
const ( const (
LookbackCap = time.Hour * 24 LookbackCap = time.Hour * 24
stateWaitLookbackLimit = abi.ChainEpoch(20) StateWaitLookbackLimit = abi.ChainEpoch(20)
) )
var ( var (
@ -35,20 +35,28 @@ var (
// (to make it easy to mock for tests) // (to make it easy to mock for tests)
type gatewayDepsAPI interface { type gatewayDepsAPI interface {
Version(context.Context) (api.Version, error) Version(context.Context) (api.Version, error)
ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error)
ChainHasObj(context.Context, cid.Cid) (bool, error) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error)
ChainHead(ctx context.Context) (*types.TipSet, error) ChainGetNode(ctx context.Context, p string) (*api.IpldObject, error)
ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error)
ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) 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) 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) 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) MpoolPushUntrusted(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error)
MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, 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) 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) 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) 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) 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) 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) StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*api.ActorState, error)
StateMinerPower(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error) StateMinerPower(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error)
@ -59,23 +67,24 @@ type gatewayDepsAPI interface {
StateMinerAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) StateMinerAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*dline.Info, error) StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*dline.Info, error)
StateCirculatingSupply(context.Context, types.TipSetKey) (abi.TokenAmount, 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) StateVMCirculatingSupplyInternal(context.Context, types.TipSetKey) (api.CirculatingSupply, error)
StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error)
} }
type GatewayAPI struct { type GatewayAPI struct {
api gatewayDepsAPI api gatewayDepsAPI
lookbackCap time.Duration lookbackCap time.Duration
stateWaitLookbackLimit abi.ChainEpoch
} }
// NewGatewayAPI creates a new GatewayAPI with the default lookback cap // NewGatewayAPI creates a new GatewayAPI with the default lookback cap
func NewGatewayAPI(api gatewayDepsAPI) *GatewayAPI { func NewGatewayAPI(api gatewayDepsAPI) *GatewayAPI {
return newGatewayAPI(api, LookbackCap) return newGatewayAPI(api, LookbackCap, StateWaitLookbackLimit)
} }
// used by the tests // used by the tests
func newGatewayAPI(api gatewayDepsAPI, lookbackCap time.Duration) *GatewayAPI { func newGatewayAPI(api gatewayDepsAPI, lookbackCap time.Duration, stateWaitLookbackLimit abi.ChainEpoch) *GatewayAPI {
return &GatewayAPI{api: api, lookbackCap: lookbackCap} return &GatewayAPI{api: api, lookbackCap: lookbackCap, stateWaitLookbackLimit: stateWaitLookbackLimit}
} }
func (a *GatewayAPI) checkTipsetKey(ctx context.Context, tsk types.TipSetKey) error { func (a *GatewayAPI) checkTipsetKey(ctx context.Context, tsk types.TipSetKey) error {
@ -122,6 +131,10 @@ func (a *GatewayAPI) Version(ctx context.Context) (api.Version, error) {
return a.api.Version(ctx) 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) { func (a *GatewayAPI) ChainHasObj(ctx context.Context, c cid.Cid) (bool, error) {
return a.api.ChainHasObj(ctx, c) return a.api.ChainHasObj(ctx, c)
} }
@ -132,6 +145,10 @@ func (a *GatewayAPI) ChainHead(ctx context.Context) (*types.TipSet, error) {
return a.api.ChainHead(ctx) 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) { func (a *GatewayAPI) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
return a.api.ChainGetTipSet(ctx, tsk) return a.api.ChainGetTipSet(ctx, tsk)
} }
@ -165,14 +182,18 @@ func (a *GatewayAPI) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoc
return a.api.ChainGetTipSetByHeight(ctx, h, tsk) 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) { func (a *GatewayAPI) ChainGetNode(ctx context.Context, p string) (*api.IpldObject, error) {
return a.api.ChainGetNode(ctx, p) 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) { 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 { if err := a.checkTipsetKey(ctx, tsk); err != nil {
return nil, err return nil, err
@ -213,6 +234,14 @@ func (a *GatewayAPI) StateAccountKey(ctx context.Context, addr address.Address,
return a.api.StateAccountKey(ctx, addr, tsk) 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) { func (a *GatewayAPI) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) {
if err := a.checkTipsetKey(ctx, tsk); err != nil { if err := a.checkTipsetKey(ctx, tsk); err != nil {
return nil, err return nil, err
@ -221,6 +250,22 @@ func (a *GatewayAPI) StateGetActor(ctx context.Context, actor address.Address, t
return a.api.StateGetActor(ctx, actor, tsk) 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) { func (a *GatewayAPI) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
if err := a.checkTipsetKey(ctx, tsk); err != nil { if err := a.checkTipsetKey(ctx, tsk); err != nil {
return address.Undef, err return address.Undef, err
@ -229,8 +274,32 @@ func (a *GatewayAPI) StateLookupID(ctx context.Context, addr address.Address, ts
return a.api.StateLookupID(ctx, addr, tsk) 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) { 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) { func (a *GatewayAPI) StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*api.ActorState, error) {
@ -296,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) { func (a *GatewayAPI) StateVMCirculatingSupplyInternal(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) {
if err := a.checkTipsetKey(ctx, tsk); err != nil { if err := a.checkTipsetKey(ctx, tsk); err != nil {
return api.CirculatingSupply{}, err return api.CirculatingSupply{}, err
@ -303,13 +379,6 @@ func (a *GatewayAPI) StateVMCirculatingSupplyInternal(ctx context.Context, tsk t
return a.api.StateVMCirculatingSupplyInternal(ctx, tsk) 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) { 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 return sigs.Verify(sig, k, msg) == nil, nil
} }

View File

@ -6,6 +6,9 @@ import (
"testing" "testing"
"time" "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/filecoin-project/lotus/build"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -116,6 +119,38 @@ func (m *mockGatewayDepsAPI) ChainHasObj(context.Context, cid.Cid) (bool, error)
panic("implement me") 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) { func (m *mockGatewayDepsAPI) ChainHead(ctx context.Context) (*types.TipSet, error) {
m.lk.RLock() m.lk.RLock()
defer m.lk.RUnlock() defer m.lk.RUnlock()
@ -165,10 +200,6 @@ func (m *mockGatewayDepsAPI) ChainGetTipSetByHeight(ctx context.Context, h abi.C
return m.tipsets[h], nil 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) { func (m *mockGatewayDepsAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) {
panic("implement me") panic("implement me")
} }

View File

@ -25,12 +25,14 @@ import (
"github.com/filecoin-project/lotus/api/client" "github.com/filecoin-project/lotus/api/client"
"github.com/filecoin-project/lotus/api/test" "github.com/filecoin-project/lotus/api/test"
"github.com/filecoin-project/lotus/chain/actors/policy" "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/chain/types"
"github.com/filecoin-project/lotus/node" "github.com/filecoin-project/lotus/node"
builder "github.com/filecoin-project/lotus/node/test" builder "github.com/filecoin-project/lotus/node/test"
) )
const maxLookbackCap = time.Duration(math.MaxInt64) const maxLookbackCap = time.Duration(math.MaxInt64)
const maxStateWaitLookbackLimit = stmgr.LookbackNoLimit
func init() { func init() {
policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1) policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1)
@ -38,15 +40,19 @@ func init() {
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256)) policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
} }
// TestEndToEndWalletMsig tests that wallet and msig API calls can be made // TestWalletMsig tests that API calls to wallet and msig can be made on a lite
// on a lite node that is connected through a gateway to a full API node // node that is connected through a gateway to a full API node
func TestEndToEndWalletMsig(t *testing.T) { func TestWalletMsig(t *testing.T) {
_ = os.Setenv("BELLMAN_NO_GPU", "1") _ = os.Setenv("BELLMAN_NO_GPU", "1")
clitest.QuietMiningLogs()
blocktime := 5 * time.Millisecond blocktime := 5 * time.Millisecond
ctx := context.Background() ctx := context.Background()
full, lite, closer := startNodes(ctx, t, blocktime, maxLookbackCap) nodes := startNodes(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit)
defer closer() defer nodes.closer()
lite := nodes.lite
full := nodes.full
// The full node starts with a wallet // The full node starts with a wallet
fullWalletAddr, err := full.WalletDefaultAddress(ctx) fullWalletAddr, err := full.WalletDefaultAddress(ctx)
@ -141,56 +147,83 @@ func TestEndToEndWalletMsig(t *testing.T) {
require.True(t, approveReturn.Applied) 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 // 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") _ = os.Setenv("BELLMAN_NO_GPU", "1")
clitest.QuietMiningLogs() clitest.QuietMiningLogs()
blocktime := 5 * time.Millisecond blocktime := 5 * time.Millisecond
ctx := context.Background() ctx := context.Background()
full, lite, closer := startNodes(ctx, t, blocktime, maxLookbackCap) nodes := startNodesWithFunds(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit)
defer closer() defer nodes.closer()
// 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)
lite := nodes.lite
clitest.RunMultisigTest(t, cli.Commands, lite) clitest.RunMultisigTest(t, cli.Commands, lite)
} }
func sendFunds(ctx context.Context, fromNode test.TestNode, fromAddr address.Address, toAddr address.Address, amt types.BigInt) error { func TestDealFlow(t *testing.T) {
msg := &types.Message{ _ = os.Setenv("BELLMAN_NO_GPU", "1")
From: fromAddr, clitest.QuietMiningLogs()
To: toAddr,
Value: amt,
}
sm, err := fromNode.MpoolPushMessage(ctx, msg, nil) blocktime := 5 * time.Millisecond
if err != nil { ctx := context.Background()
return err nodes := startNodesWithFunds(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit)
} defer nodes.closer()
res, err := fromNode.StateWaitMsg(ctx, sm.Cid(), 1) test.MakeDeal(t, ctx, 6, nodes.lite, nodes.miner, false, false)
if err != nil {
return err
}
if res.Receipt.ExitCode != 0 {
return xerrors.Errorf("send funds failed with exit code %d", res.Receipt.ExitCode)
}
return nil
} }
func startNodes(ctx context.Context, t *testing.T, blocktime time.Duration, lookbackCap time.Duration) (test.TestNode, test.TestNode, jsonrpc.ClientCloser) { func TestCLIDealFlow(t *testing.T) {
_ = os.Setenv("BELLMAN_NO_GPU", "1")
clitest.QuietMiningLogs()
blocktime := 5 * time.Millisecond
ctx := context.Background()
nodes := startNodesWithFunds(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit)
defer nodes.closer()
clitest.RunClientTest(t, cli.Commands, nodes.lite)
}
type testNodes struct {
lite test.TestNode
full test.TestNode
miner test.TestStorageNode
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,
blocktime time.Duration,
lookbackCap time.Duration,
stateWaitLookbackLimit abi.ChainEpoch,
) *testNodes {
var closer jsonrpc.ClientCloser var closer jsonrpc.ClientCloser
// Create one miner and two full nodes. // Create one miner and two full nodes.
@ -207,7 +240,8 @@ func startNodes(ctx context.Context, t *testing.T, blocktime time.Duration, look
fullNode := nodes[0] fullNode := nodes[0]
// Create a gateway server in front of the full node // 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) require.NoError(t, err)
// Create a gateway client API that connects to the gateway server // Create a gateway client API that connects to the gateway server
@ -234,9 +268,39 @@ func startNodes(ctx context.Context, t *testing.T, blocktime time.Duration, look
err = miner.NetConnect(ctx, fullAddr) err = miner.NetConnect(ctx, fullAddr)
require.NoError(t, err) 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 // Start mining blocks
bm := test.NewBlockMiner(ctx, t, miner, blocktime) bm := test.NewBlockMiner(ctx, t, miner, blocktime)
bm.MineBlocks() bm.MineBlocks()
return full, lite, closer 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
} }

View File

@ -27,8 +27,6 @@ import (
"github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/events"
"github.com/filecoin-project/lotus/chain/events/state" "github.com/filecoin-project/lotus/chain/events/state"
"github.com/filecoin-project/lotus/chain/market" "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/chain/types"
"github.com/filecoin-project/lotus/lib/sigs" "github.com/filecoin-project/lotus/lib/sigs"
"github.com/filecoin-project/lotus/markets/utils" "github.com/filecoin-project/lotus/markets/utils"
@ -40,8 +38,6 @@ type ClientNodeAdapter struct {
full.ChainAPI full.ChainAPI
full.MpoolAPI full.MpoolAPI
sm *stmgr.StateManager
cs *store.ChainStore
fm *market.FundMgr fm *market.FundMgr
ev *events.Events ev *events.Events
} }
@ -51,14 +47,12 @@ type clientApi struct {
full.StateAPI 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{ return &ClientNodeAdapter{
StateAPI: state, StateAPI: state,
ChainAPI: chain, ChainAPI: chain,
MpoolAPI: mpool, MpoolAPI: mpool,
sm: sm,
cs: cs,
fm: fm, fm: fm,
ev: events.NewEvents(context.TODO(), &clientApi{chain, state}), 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) { func (c *ClientNodeAdapter) ValidatePublishedDeal(ctx context.Context, deal storagemarket.ClientDeal) (abi.DealID, error) {
log.Infow("DEAL ACCEPTED!") log.Infow("DEAL ACCEPTED!")
pubmsg, err := c.cs.GetMessage(*deal.PublishMessage) pubmsg, err := c.ChainGetMessage(ctx, *deal.PublishMessage)
if err != nil { if err != nil {
return 0, xerrors.Errorf("getting deal publish message: %w", err) 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 { if err != nil {
return 0, xerrors.Errorf("getting miner worker failed: %w", err) 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 // 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 { if err != nil {
return 0, xerrors.Errorf("waiting for deal publish message: %w", err) return 0, xerrors.Errorf("waiting for deal publish message: %w", err)
} }
if ret.ExitCode != 0 { if ret.Receipt.ExitCode != 0 {
return 0, xerrors.Errorf("deal publish failed: exit=%d", ret.ExitCode) return 0, xerrors.Errorf("deal publish failed: exit=%d", ret.Receipt.ExitCode)
} }
var res market2.PublishStorageDealsReturn 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 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 { 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) { 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 { if err != nil {
// TODO: This may be fine for some errors // TODO: This may be fine for some errors
@ -245,7 +239,7 @@ func (c *ClientNodeAdapter) OnDealSectorCommitted(ctx context.Context, provider
return false, nil return false, nil
} }
sd, err := stmgr.GetStorageDeal(ctx, c.StateManager, dealId, ts) sd, err := c.StateMarketStorageDeal(ctx, dealId, ts.Key())
if err != nil { if err != nil {
return false, xerrors.Errorf("failed to look up deal on chain: %w", err) return false, xerrors.Errorf("failed to look up deal on chain: %w", err)
} }

View File

@ -250,7 +250,6 @@ func Online() Option {
Override(new(*store.ChainStore), modules.ChainStore), Override(new(*store.ChainStore), modules.ChainStore),
Override(new(stmgr.UpgradeSchedule), stmgr.DefaultUpgradeSchedule()), Override(new(stmgr.UpgradeSchedule), stmgr.DefaultUpgradeSchedule()),
Override(new(*stmgr.StateManager), stmgr.NewStateManagerWithUpgradeSchedule), Override(new(*stmgr.StateManager), stmgr.NewStateManagerWithUpgradeSchedule),
Override(new(stmgr.StateManagerAPI), From(new(*stmgr.StateManager))),
Override(new(*wallet.LocalWallet), wallet.NewWallet), Override(new(*wallet.LocalWallet), wallet.NewWallet),
Override(new(wallet.Default), From(new(*wallet.LocalWallet))), Override(new(wallet.Default), From(new(*wallet.LocalWallet))),
Override(new(api.WalletAPI), From(new(wallet.MultiWallet))), Override(new(api.WalletAPI), From(new(wallet.MultiWallet))),

View File

@ -65,9 +65,9 @@ type API struct {
fx.In fx.In
full.ChainAPI full.ChainAPI
full.StateAPI
full.WalletAPI full.WalletAPI
paych.PaychAPI paych.PaychAPI
full.StateAPI
SMDealClient storagemarket.StorageClient SMDealClient storagemarket.StorageClient
RetDiscovery discovery.PeerResolver 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 { if err != nil {
return nil, xerrors.Errorf("failed resolving params.Wallet addr: %w", params.Wallet) return nil, xerrors.Errorf("failed resolving params.Wallet addr: %w", params.Wallet)
} }

View File

@ -40,8 +40,11 @@ import (
var log = logging.Logger("fullnode") var log = logging.Logger("fullnode")
type ChainModuleAPI interface { 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) ChainHasObj(context.Context, cid.Cid) (bool, error)
ChainHead(context.Context) (*types.TipSet, 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) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error)
ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, 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) ChainReadObj(context.Context, cid.Cid) ([]byte, error)
@ -67,8 +70,8 @@ type ChainAPI struct {
Chain *store.ChainStore Chain *store.ChainStore
} }
func (a *ChainAPI) ChainNotify(ctx context.Context) (<-chan []*api.HeadChange, error) { func (m *ChainModule) ChainNotify(ctx context.Context) (<-chan []*api.HeadChange, error) {
return a.Chain.SubHeadChanges(ctx), nil return m.Chain.SubHeadChanges(ctx), nil
} }
func (m *ChainModule) ChainHead(context.Context) (*types.TipSet, error) { 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) return m.Chain.LoadTipSet(key)
} }
func (a *ChainAPI) ChainGetBlockMessages(ctx context.Context, msg cid.Cid) (*api.BlockMessages, error) { func (m *ChainModule) ChainGetBlockMessages(ctx context.Context, msg cid.Cid) (*api.BlockMessages, error) {
b, err := a.Chain.GetBlock(msg) b, err := m.Chain.GetBlock(msg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
bmsgs, smsgs, err := a.Chain.MessagesForBlock(b) bmsgs, smsgs, err := m.Chain.MessagesForBlock(b)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -532,8 +535,8 @@ func (a *ChainAPI) ChainGetNode(ctx context.Context, p string) (*api.IpldObject,
}, nil }, nil
} }
func (a *ChainAPI) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error) { func (m *ChainModule) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error) {
cm, err := a.Chain.GetCMessage(mc) cm, err := m.Chain.GetCMessage(mc)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -40,12 +40,22 @@ import (
) )
type StateModuleAPI interface { 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) 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) 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)
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)
} }
// StateModule provides a default implementation of StateModuleAPI. // StateModule provides a default implementation of StateModuleAPI.
@ -112,13 +122,13 @@ func (a *StateAPI) StateMinerActiveSectors(ctx context.Context, maddr address.Ad
return stmgr.GetMinerSectorSet(ctx, a.StateManager, ts, maddr, &activeSectors) 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) { func (m *StateModule) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) {
act, err := a.StateManager.LoadActorTsk(ctx, actor, tsk) act, err := m.StateManager.LoadActorTsk(ctx, actor, tsk)
if err != nil { if err != nil {
return miner.MinerInfo{}, xerrors.Errorf("failed to load miner actor: %w", err) 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 { if err != nil {
return miner.MinerInfo{}, xerrors.Errorf("failed to load miner actor state: %w", err) return miner.MinerInfo{}, xerrors.Errorf("failed to load miner actor state: %w", err)
} }
@ -215,18 +225,18 @@ func (a *StateAPI) StateMinerPartitions(ctx context.Context, m address.Address,
return out, err return out, err
} }
func (a *StateAPI) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*dline.Info, error) { func (m *StateModule) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*dline.Info, error) {
ts, err := a.StateManager.ChainStore().GetTipSetFromKey(tsk) ts, err := m.Chain.GetTipSetFromKey(tsk)
if err != nil { if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) 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 { if err != nil {
return nil, xerrors.Errorf("failed to load miner actor: %w", err) 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 { if err != nil {
return nil, xerrors.Errorf("failed to load miner actor state: %w", err) return nil, xerrors.Errorf("failed to load miner actor state: %w", err)
} }
@ -310,19 +320,19 @@ func (a *StateAPI) StateMinerRecoveries(ctx context.Context, addr address.Addres
return miner.AllPartSectors(mas, miner.Partition.RecoveringSectors) return miner.AllPartSectors(mas, miner.Partition.RecoveringSectors)
} }
func (a *StateAPI) StateMinerPower(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*api.MinerPower, error) { func (m *StateModule) StateMinerPower(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*api.MinerPower, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk) ts, err := m.Chain.GetTipSetFromKey(tsk)
if err != nil { if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) 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 { if err != nil {
return nil, err return nil, err
} }
return &api.MinerPower{ return &api.MinerPower{
MinerPower: m, MinerPower: mp,
TotalPower: net, TotalPower: net,
HasMinPower: hmp, HasMinPower: hmp,
}, nil }, nil
@ -563,20 +573,20 @@ func (a *StateAPI) StateSearchMsg(ctx context.Context, msg cid.Cid) (*api.MsgLoo
return nil, nil return nil, nil
} }
func (a *StateAPI) StateGetReceipt(ctx context.Context, msg cid.Cid, tsk types.TipSetKey) (*types.MessageReceipt, error) { func (m *StateModule) StateGetReceipt(ctx context.Context, msg cid.Cid, tsk types.TipSetKey) (*types.MessageReceipt, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk) ts, err := m.Chain.GetTipSetFromKey(tsk)
if err != nil { if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) 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) { func (m *StateModule) StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk) ts, err := m.Chain.GetTipSetFromKey(tsk)
if err != nil { if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) 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) { func (a *StateAPI) StateListActors(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) {
@ -587,12 +597,12 @@ func (a *StateAPI) StateListActors(ctx context.Context, tsk types.TipSetKey) ([]
return a.StateManager.ListAllActors(ctx, ts) return a.StateManager.ListAllActors(ctx, ts)
} }
func (a *StateAPI) StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error) { func (m *StateModule) StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk) ts, err := m.Chain.GetTipSetFromKey(tsk)
if err != nil { if err != nil {
return api.MarketBalance{}, xerrors.Errorf("loading tipset %s: %w", tsk, err) 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) { func (a *StateAPI) StateMarketParticipants(ctx context.Context, tsk types.TipSetKey) (map[string]api.MarketBalance, error) {
@ -676,12 +686,12 @@ func (a *StateAPI) StateMarketDeals(ctx context.Context, tsk types.TipSetKey) (m
return out, nil return out, nil
} }
func (a *StateAPI) StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) { func (m *StateModule) StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk) ts, err := m.Chain.GetTipSetFromKey(tsk)
if err != nil { if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) 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) { func (a *StateAPI) StateChangedActors(ctx context.Context, old cid.Cid, new cid.Cid) (map[string]types.Actor, error) {
@ -1158,19 +1168,19 @@ func (a *StateAPI) StateVerifierStatus(ctx context.Context, addr address.Address
// StateVerifiedClientStatus returns the data cap for the given address. // StateVerifiedClientStatus returns the data cap for the given address.
// Returns zero if there is no entry in the data cap table for the // Returns zero if there is no entry in the data cap table for the
// address. // address.
func (a *StateAPI) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) { func (m *StateModule) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) {
act, err := a.StateGetActor(ctx, verifreg.Address, tsk) act, err := m.StateGetActor(ctx, verifreg.Address, tsk)
if err != nil { if err != nil {
return nil, err return nil, err
} }
aid, err := a.StateLookupID(ctx, addr, tsk) aid, err := m.StateLookupID(ctx, addr, tsk)
if err != nil { if err != nil {
log.Warnf("lookup failure %v", err) log.Warnf("lookup failure %v", err)
return nil, 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 { if err != nil {
return nil, xerrors.Errorf("failed to load verified registry state: %w", err) return nil, xerrors.Errorf("failed to load verified registry state: %w", err)
} }
@ -1205,33 +1215,33 @@ var dealProviderCollateralDen = types.NewInt(100)
// StateDealProviderCollateralBounds returns the min and max collateral a storage provider // StateDealProviderCollateralBounds returns the min and max collateral a storage provider
// can issue. It takes the deal size and verified status as parameters. // 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) { func (m *StateModule) StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (api.DealCollateralBounds, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk) ts, err := m.Chain.GetTipSetFromKey(tsk)
if err != nil { if err != nil {
return api.DealCollateralBounds{}, xerrors.Errorf("loading tipset %s: %w", tsk, err) 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 { if err != nil {
return api.DealCollateralBounds{}, xerrors.Errorf("failed to load power actor: %w", err) 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 { if err != nil {
return api.DealCollateralBounds{}, xerrors.Errorf("failed to load reward actor: %w", err) 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 { if err != nil {
return api.DealCollateralBounds{}, xerrors.Errorf("failed to load power actor state: %w", err) 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 { if err != nil {
return api.DealCollateralBounds{}, xerrors.Errorf("failed to load reward actor state: %w", err) 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 { if err != nil {
return api.DealCollateralBounds{}, xerrors.Errorf("getting total circulating supply: %w", err) return api.DealCollateralBounds{}, xerrors.Errorf("getting total circulating supply: %w", err)
} }
@ -1252,7 +1262,7 @@ func (a *StateAPI) StateDealProviderCollateralBounds(ctx context.Context, size a
powClaim.QualityAdjPower, powClaim.QualityAdjPower,
rewPow, rewPow,
circ.FilCirculating, circ.FilCirculating,
a.StateManager.GetNtwkVersion(ctx, ts.Height())) m.StateManager.GetNtwkVersion(ctx, ts.Height()))
return api.DealCollateralBounds{ return api.DealCollateralBounds{
Min: types.BigDiv(types.BigMul(min, dealProviderCollateralNum), dealProviderCollateralDen), Min: types.BigDiv(types.BigMul(min, dealProviderCollateralNum), dealProviderCollateralDen),
Max: max, Max: max,
@ -1273,23 +1283,32 @@ func (a *StateAPI) StateCirculatingSupply(ctx context.Context, tsk types.TipSetK
} }
func (a *StateAPI) StateVMCirculatingSupplyInternal(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) { 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 { if err != nil {
return api.CirculatingSupply{}, xerrors.Errorf("loading tipset %s: %w", tsk, err) 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 { if err != nil {
return api.CirculatingSupply{}, err 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) { func (m *StateModule) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (network.Version, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk) ts, err := m.Chain.GetTipSetFromKey(tsk)
if err != nil { if err != nil {
return network.VersionMax, xerrors.Errorf("loading tipset %s: %w", tsk, err) 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
} }

View File

@ -13,17 +13,12 @@ import (
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/actors/builtin/paych"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
full "github.com/filecoin-project/lotus/node/impl/full"
"github.com/filecoin-project/lotus/paychmgr" "github.com/filecoin-project/lotus/paychmgr"
) )
type PaychAPI struct { type PaychAPI struct {
fx.In fx.In
full.MpoolAPI
full.WalletAPI
full.ChainAPI
PaychMgr *paychmgr.Manager PaychMgr *paychmgr.Manager
} }

View File

@ -3,19 +3,40 @@ package modules
import ( import (
"context" "context"
"github.com/filecoin-project/lotus/api" "golang.org/x/xerrors"
"github.com/filecoin-project/go-address" "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/stmgr"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
cbor "github.com/ipfs/go-ipld-cbor"
) )
type RPCStateManager struct { type RPCStateManager struct {
gapi api.GatewayAPI gapi api.GatewayAPI
cstore *cbor.BasicIpldStore
} }
func NewRPCStateManager(api api.GatewayAPI) *RPCStateManager { 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) { 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()) 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) var _ stmgr.StateManagerAPI = (*RPCStateManager)(nil)

View File

@ -16,7 +16,6 @@ import (
"github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/go-state-types/network"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors/adt"
"github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/actors/builtin/paych"
"github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
@ -61,14 +60,10 @@ type managerAPI interface {
// managerAPIImpl is used to create a composite that implements managerAPI // managerAPIImpl is used to create a composite that implements managerAPI
type managerAPIImpl struct { type managerAPIImpl struct {
*stmgr.StateManager stmgr.StateManagerAPI
paychAPI paychAPI
} }
func (m *managerAPIImpl) AdtStore(ctx context.Context) adt.Store {
return m.ChainStore().Store(ctx)
}
type Manager struct { type Manager struct {
// The Manager context is used to terminate wait operations on shutdown // The Manager context is used to terminate wait operations on shutdown
ctx context.Context ctx context.Context
@ -82,11 +77,11 @@ type Manager struct {
channels map[string]*channelAccessor 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 := helpers.LifecycleCtx(mctx, lc)
ctx, shutdown := context.WithCancel(ctx) ctx, shutdown := context.WithCancel(ctx)
impl := &managerAPIImpl{StateManager: sm, paychAPI: &api} impl := &managerAPIImpl{StateManagerAPI: sm, paychAPI: &api}
return &Manager{ return &Manager{
ctx: ctx, ctx: ctx,
shutdown: shutdown, shutdown: shutdown,