on chain deals: Deals make it to the chain

This commit is contained in:
Łukasz Magiera 2019-10-23 19:39:14 +02:00
parent 61e14d0f4c
commit fabd074165
18 changed files with 219 additions and 82 deletions

View File

@ -121,9 +121,31 @@ func (sdp *StorageDealProposal) Verify() error {
return sdp.ProposerSignature.Verify(sdp.Client, buf.Bytes()) return sdp.ProposerSignature.Verify(sdp.Client, buf.Bytes())
} }
func (d *StorageDeal) Sign(ctx context.Context, sign SignFunc) error {
var buf bytes.Buffer
if err := d.Proposal.MarshalCBOR(&buf); err != nil {
return err
}
sig, err := sign(ctx, buf.Bytes())
if err != nil {
return err
}
d.CounterSignature = sig
return nil
}
func (d *StorageDeal) Verify(proposerWorker address.Address) error {
var buf bytes.Buffer
if err := d.Proposal.MarshalCBOR(&buf); err != nil {
return err
}
return d.CounterSignature.Verify(proposerWorker, buf.Bytes())
}
type StorageDeal struct { type StorageDeal struct {
Proposal StorageDealProposal Proposal StorageDealProposal
CounterSignature types.Signature CounterSignature *types.Signature
} }
type OnChainDeal struct { type OnChainDeal struct {
@ -214,7 +236,7 @@ func (sma StorageMarketActor) AddBalance(act *types.Actor, vmctx types.VMContext
func setMarketBalances(vmctx types.VMContext, nd *hamt.Node, set map[address.Address]StorageParticipantBalance) (cid.Cid, ActorError) { func setMarketBalances(vmctx types.VMContext, nd *hamt.Node, set map[address.Address]StorageParticipantBalance) (cid.Cid, ActorError) {
for addr, b := range set { for addr, b := range set {
if err := nd.Set(vmctx.Context(), string(addr.Bytes()), b); err != nil { if err := nd.Set(vmctx.Context(), string(addr.Bytes()), &b); err != nil {
return cid.Undef, aerrors.HandleExternalError(err, "setting new balance") return cid.Undef, aerrors.HandleExternalError(err, "setting new balance")
} }
} }
@ -283,7 +305,6 @@ func (sma StorageMarketActor) PublishStorageDeals(act *types.Actor, vmctx types.
deals, err := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Deals) deals, err := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Deals)
if err != nil { if err != nil {
// TODO: kind of annoying that this can be caused by gas, otherwise could be fatal
return nil, aerrors.HandleExternalError(err, "loading deals amt") return nil, aerrors.HandleExternalError(err, "loading deals amt")
} }
@ -298,7 +319,7 @@ func (sma StorageMarketActor) PublishStorageDeals(act *types.Actor, vmctx types.
return nil, err return nil, err
} }
err := deals.Set(self.NextDealID, OnChainDeal{Deal: deal}) err := deals.Set(self.NextDealID, &OnChainDeal{Deal: deal})
if err != nil { if err != nil {
return nil, aerrors.HandleExternalError(err, "setting deal in deal AMT") return nil, aerrors.HandleExternalError(err, "setting deal in deal AMT")
} }
@ -338,37 +359,33 @@ func (self *StorageMarketState) validateDeal(vmctx types.VMContext, deal Storage
return aerrors.New(1, "deal proposal already expired") return aerrors.New(1, "deal proposal already expired")
} }
var proposalBuf bytes.Buffer if err := deal.Proposal.Verify(); err != nil {
err := deal.Proposal.MarshalCBOR(&proposalBuf) return aerrors.Absorb(err, 2, "verifying proposer signature")
if err != nil {
return aerrors.HandleExternalError(err, "serializing deal proposal failed")
} }
err = deal.Proposal.ProposerSignature.Verify(deal.Proposal.Client, proposalBuf.Bytes()) workerBytes, aerr := vmctx.Send(deal.Proposal.Provider, MAMethods.GetWorkerAddr, types.NewInt(0), nil)
if aerr != nil {
return aerr
}
providerWorker, err := address.NewFromBytes(workerBytes)
if err != nil { if err != nil {
return aerrors.HandleExternalError(err, "verifying proposer signature") return aerrors.HandleExternalError(err, "parsing provider worker address bytes")
} }
var dealBuf bytes.Buffer err = deal.Verify(providerWorker)
err = deal.MarshalCBOR(&dealBuf)
if err != nil { if err != nil {
return aerrors.HandleExternalError(err, "serializing deal failed") return aerrors.Absorb(err, 2, "verifying provider signature")
}
err = deal.CounterSignature.Verify(deal.Proposal.Provider, dealBuf.Bytes())
if err != nil {
return aerrors.HandleExternalError(err, "verifying provider signature")
} }
// TODO: maybe this is actually fine // TODO: maybe this is actually fine
if vmctx.Message().From != deal.Proposal.Provider && vmctx.Message().From != deal.Proposal.Client { if vmctx.Message().From != providerWorker && vmctx.Message().From != deal.Proposal.Client {
return aerrors.New(4, "message not sent by deal participant") return aerrors.New(4, "message not sent by deal participant")
} }
// TODO: REVIEW: Do we want to check if provider exists in the power actor? // TODO: REVIEW: Do we want to check if provider exists in the power actor?
// TODO: do some caching (changes gas so needs to be in spec too) // TODO: do some caching (changes gas so needs to be in spec too)
b, bnd, aerr := GetMarketBalances(vmctx.Context(), vmctx.Ipld(), self.Balances, deal.Proposal.Client, deal.Proposal.Provider) b, bnd, aerr := GetMarketBalances(vmctx.Context(), vmctx.Ipld(), self.Balances, deal.Proposal.Client, providerWorker)
if aerr != nil { if aerr != nil {
return aerrors.Wrap(aerr, "getting client, and provider balances") return aerrors.Wrap(aerr, "getting client, and provider balances")
} }
@ -426,7 +443,16 @@ func (sma StorageMarketActor) ActivateStorageDeals(act *types.Actor, vmctx types
return nil, aerrors.HandleExternalError(err, "getting del info failed") return nil, aerrors.HandleExternalError(err, "getting del info failed")
} }
if vmctx.Message().From != dealInfo.Deal.Proposal.Provider { workerBytes, err := vmctx.Send(dealInfo.Deal.Proposal.Provider, MAMethods.GetWorkerAddr, types.NewInt(0), nil)
if err != nil {
return nil, err
}
providerWorker, eerr := address.NewFromBytes(workerBytes)
if eerr != nil {
return nil, aerrors.HandleExternalError(eerr, "parsing provider worker address bytes")
}
if vmctx.Message().From != providerWorker {
return nil, aerrors.New(1, "ActivateStorageDeals can only be called by deal provider") return nil, aerrors.New(1, "ActivateStorageDeals can only be called by deal provider")
} }

View File

@ -3197,9 +3197,21 @@ func (t *StorageDeal) UnmarshalCBOR(r io.Reader) error {
{ {
if err := t.CounterSignature.UnmarshalCBOR(br); err != nil { pb, err := br.PeekByte()
if err != nil {
return err return err
} }
if pb == cbg.CborNull[0] {
var nbuf [1]byte
if _, err := br.Read(nbuf[:]); err != nil {
return err
}
} else {
t.CounterSignature = new(types.Signature)
if err := t.CounterSignature.UnmarshalCBOR(br); err != nil {
return err
}
}
} }
return nil return nil

View File

@ -2,6 +2,7 @@ package deals
import ( import (
"context" "context"
"github.com/filecoin-project/lotus/node/impl/full"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore"
@ -42,6 +43,7 @@ type Client struct {
w *wallet.Wallet w *wallet.Wallet
dag dtypes.ClientDAG dag dtypes.ClientDAG
discovery *discovery.Local discovery *discovery.Local
mpool full.MpoolAPI
deals ClientStateStore deals ClientStateStore
conns map[cid.Cid]inet.Stream conns map[cid.Cid]inet.Stream
@ -59,7 +61,7 @@ type clientDealUpdate struct {
err error err error
} }
func NewClient(sm *stmgr.StateManager, chain *store.ChainStore, h host.Host, w *wallet.Wallet, ds dtypes.MetadataDS, dag dtypes.ClientDAG, discovery *discovery.Local) *Client { func NewClient(sm *stmgr.StateManager, chain *store.ChainStore, h host.Host, w *wallet.Wallet, ds dtypes.MetadataDS, dag dtypes.ClientDAG, discovery *discovery.Local, mpool full.MpoolAPI) *Client {
c := &Client{ c := &Client{
sm: sm, sm: sm,
chain: chain, chain: chain,
@ -67,6 +69,7 @@ func NewClient(sm *stmgr.StateManager, chain *store.ChainStore, h host.Host, w *
w: w, w: w,
dag: dag, dag: dag,
discovery: discovery, discovery: discovery,
mpool: mpool,
deals: ClientStateStore{StateStore{ds: namespace.Wrap(ds, datastore.NewKey("/deals/client"))}}, deals: ClientStateStore{StateStore{ds: namespace.Wrap(ds, datastore.NewKey("/deals/client"))}},
conns: map[cid.Cid]inet.Stream{}, conns: map[cid.Cid]inet.Stream{},
@ -167,6 +170,37 @@ type ClientDealProposal struct {
} }
func (c *Client) Start(ctx context.Context, p ClientDealProposal) (cid.Cid, error) { func (c *Client) Start(ctx context.Context, p ClientDealProposal) (cid.Cid, error) {
// check market funds
clientMarketBalance, err := c.sm.MarketBalance(ctx, p.Client, nil)
if err != nil {
return cid.Undef, xerrors.Errorf("getting client market balance failed: %w", err)
}
if clientMarketBalance.Available.LessThan(p.TotalPrice) {
// TODO: move to a smarter market funds manager
smsg, err := c.mpool.MpoolPushMessage(ctx, &types.Message{
To: actors.StorageMarketAddress,
From: p.Client,
Value: p.TotalPrice,
GasPrice: types.NewInt(0),
GasLimit: types.NewInt(1000000),
Method: actors.SMAMethods.AddBalance,
})
if err != nil {
return cid.Undef, err
}
_, r, err := c.sm.WaitForMessage(ctx, smsg.Cid())
if err != nil {
return cid.Undef, err
}
if r.ExitCode != 0 {
return cid.Undef, xerrors.Errorf("adding funds to storage miner market actor failed: exit %d", r.ExitCode)
}
}
proposal := &actors.StorageDealProposal{ proposal := &actors.StorageDealProposal{
PieceRef: p.Data.Bytes(), PieceRef: p.Data.Bytes(),
PieceSize: p.DataSize, PieceSize: p.DataSize,

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/stmgr"
"golang.org/x/xerrors" "golang.org/x/xerrors"
) )
@ -43,22 +44,27 @@ func (c *Client) new(ctx context.Context, deal ClientDeal) error {
return xerrors.Errorf("getting deal pubsish message: %w", err) return xerrors.Errorf("getting deal pubsish message: %w", err)
} }
if pubmsg.From != deal.Proposal.Provider { pw, err := stmgr.GetMinerWorker(ctx, c.sm, nil, deal.Proposal.Provider)
return xerrors.Errorf("Deal wasn't published by storage provider: from=%s, provider=%s", pubmsg.From, deal.Proposal.Provider) if err != nil {
return xerrors.Errorf("getting miner worker failed: %w", err)
}
if pubmsg.From != pw {
return xerrors.Errorf("deal wasn't published by storage provider: from=%s, provider=%s", pubmsg.From, deal.Proposal.Provider)
} }
if pubmsg.To != actors.StorageMarketAddress { if pubmsg.To != actors.StorageMarketAddress {
return xerrors.Errorf("Deal publish message wasn't set to StorageMarket actor (to=%s)", pubmsg.To) return xerrors.Errorf("deal publish message wasn't set to StorageMarket actor (to=%s)", pubmsg.To)
} }
if pubmsg.Method != actors.SMAMethods.PublishStorageDeals { if pubmsg.Method != actors.SMAMethods.PublishStorageDeals {
return xerrors.Errorf("Deal publish message called incorrect method (method=%s)", pubmsg.Method) return xerrors.Errorf("deal publish message called incorrect method (method=%s)", pubmsg.Method)
} }
// TODO: timeout // TODO: timeout
_, ret, err := c.sm.WaitForMessage(ctx, *resp.PublishMessage) _, ret, err := c.sm.WaitForMessage(ctx, *resp.PublishMessage)
if err != nil { if err != nil {
return xerrors.Errorf("Waiting for deal publish message: %w", err) return xerrors.Errorf("waiting for deal publish message: %w", err)
} }
if ret.ExitCode != 0 { if ret.ExitCode != 0 {
return xerrors.Errorf("deal publish failed: exit=%d", ret.ExitCode) return xerrors.Errorf("deal publish failed: exit=%d", ret.ExitCode)

View File

@ -160,7 +160,7 @@ func (p *Provider) onIncoming(deal MinerDeal) {
func (p *Provider) onUpdated(ctx context.Context, update minerDealUpdate) { func (p *Provider) onUpdated(ctx context.Context, update minerDealUpdate) {
log.Infof("Deal %s updated state to %d", update.id, update.newState) log.Infof("Deal %s updated state to %d", update.id, update.newState)
if update.err != nil { if update.err != nil {
log.Errorf("deal %s failed: %s", update.id, update.err) log.Errorf("deal %s (newSt: %d) failed: %s", update.id, update.newState, update.err)
p.failDeal(update.id, update.err) p.failDeal(update.id, update.err)
return return
} }

View File

@ -145,7 +145,7 @@ func (p *Provider) saveAsk(a *types.SignedStorageAsk) error {
func (c *Client) checkAskSignature(ask *types.SignedStorageAsk) error { func (c *Client) checkAskSignature(ask *types.SignedStorageAsk) error {
tss := c.sm.ChainStore().GetHeaviestTipSet().ParentState() tss := c.sm.ChainStore().GetHeaviestTipSet().ParentState()
w, err := stmgr.GetMinerWorker(context.TODO(), c.sm, tss, ask.Ask.Miner) w, err := stmgr.GetMinerWorkerRaw(context.TODO(), c.sm, tss, ask.Ask.Miner)
if err != nil { if err != nil {
return xerrors.Errorf("failed to get worker for miner in ask", err) return xerrors.Errorf("failed to get worker for miner in ask", err)
} }

View File

@ -2,15 +2,16 @@ package deals
import ( import (
"context" "context"
"github.com/ipfs/go-cid"
"github.com/filecoin-project/go-sectorbuilder/sealing_state" "github.com/filecoin-project/go-sectorbuilder/sealing_state"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-merkledag" "github.com/ipfs/go-merkledag"
unixfile "github.com/ipfs/go-unixfs/file" unixfile "github.com/ipfs/go-unixfs/file"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/address"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/sectorbuilder" "github.com/filecoin-project/lotus/lib/sectorbuilder"
"github.com/filecoin-project/lotus/storage/sectorblocks" "github.com/filecoin-project/lotus/storage/sectorblocks"
@ -40,11 +41,11 @@ func (p *Provider) handle(ctx context.Context, deal MinerDeal, cb providerHandle
// ACCEPTED // ACCEPTED
func (p *Provider) addMarketFunds(ctx context.Context, deal MinerDeal) error { func (p *Provider) addMarketFunds(ctx context.Context, worker address.Address, deal MinerDeal) error {
log.Info("Adding market funds for storage collateral") log.Info("Adding market funds for storage collateral")
smsg, err := p.full.MpoolPushMessage(ctx, &types.Message{ smsg, err := p.full.MpoolPushMessage(ctx, &types.Message{
To: actors.StorageMarketAddress, To: actors.StorageMarketAddress,
From: deal.Proposal.Provider, From: worker,
Value: deal.Proposal.StorageCollateral, Value: deal.Proposal.StorageCollateral,
GasPrice: types.NewInt(0), GasPrice: types.NewInt(0),
GasLimit: types.NewInt(1000000), GasLimit: types.NewInt(1000000),
@ -75,6 +76,14 @@ func (p *Provider) accept(ctx context.Context, deal MinerDeal) (func(*MinerDeal)
return nil, xerrors.Errorf("deal proposal with unsupported serialization: %s", deal.Proposal.PieceSerialization) return nil, xerrors.Errorf("deal proposal with unsupported serialization: %s", deal.Proposal.PieceSerialization)
} }
head, err := p.full.ChainHead(ctx)
if err != nil {
return nil, err
}
if head.Height() >= deal.Proposal.ProposalExpiration {
return nil, xerrors.Errorf("deal proposal already expired")
}
// TODO: check StorageCollateral / StoragePrice // TODO: check StorageCollateral / StoragePrice
// check market funds // check market funds
@ -89,28 +98,48 @@ func (p *Provider) accept(ctx context.Context, deal MinerDeal) (func(*MinerDeal)
return nil, xerrors.New("clientMarketBalance.Available too small") return nil, xerrors.New("clientMarketBalance.Available too small")
} }
providerMarketBalance, err := p.full.StateMarketBalance(ctx, deal.Proposal.Provider, nil) waddr, err := p.full.StateMinerWorker(ctx, deal.Proposal.Provider, nil)
if err != nil {
return nil, err
}
providerMarketBalance, err := p.full.StateMarketBalance(ctx, waddr, nil)
if err != nil { if err != nil {
return nil, xerrors.Errorf("getting provider market balance failed: %w", err) return nil, xerrors.Errorf("getting provider market balance failed: %w", err)
} }
// TODO: this needs to be atomic // TODO: this needs to be atomic
if providerMarketBalance.Available.LessThan(deal.Proposal.StorageCollateral) { if providerMarketBalance.Available.LessThan(deal.Proposal.StorageCollateral) {
if err := p.addMarketFunds(ctx, deal); err != nil { if err := p.addMarketFunds(ctx, waddr, deal); err != nil {
return nil, err return nil, err
} }
} }
log.Info("publishing deal") log.Info("publishing deal")
storageDeal := actors.StorageDeal{
Proposal: deal.Proposal,
}
if err := api.SignWith(ctx, p.full.WalletSign, waddr, &storageDeal); err != nil {
return nil, xerrors.Errorf("signing storage deal failed: ", err)
}
params, err := actors.SerializeParams(&actors.PublishStorageDealsParams{
Deals: []actors.StorageDeal{storageDeal},
})
if err != nil {
return nil, xerrors.Errorf("serializing PublishStorageDeals params failed: ", err)
}
// TODO: We may want this to happen after fetching data // TODO: We may want this to happen after fetching data
smsg, err := p.full.MpoolPushMessage(ctx, &types.Message{ smsg, err := p.full.MpoolPushMessage(ctx, &types.Message{
To: actors.StorageMarketAddress, To: actors.StorageMarketAddress,
From: deal.Proposal.Provider, From: waddr,
Value: types.NewInt(0), Value: types.NewInt(0),
GasPrice: types.NewInt(0), GasPrice: types.NewInt(0),
GasLimit: types.NewInt(1000000), GasLimit: types.NewInt(1000000),
Method: actors.SMAMethods.PublishStorageDeals, Method: actors.SMAMethods.PublishStorageDeals,
Params: params,
}) })
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -206,7 +206,7 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add
st := pts.ParentState() st := pts.ParentState()
worker, err := stmgr.GetMinerWorker(ctx, cg.sm, st, m) worker, err := stmgr.GetMinerWorkerRaw(ctx, cg.sm, st, m)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -385,7 +385,7 @@ func (mca mca) StateMinerPower(ctx context.Context, maddr address.Address, ts *t
} }
func (mca mca) StateMinerWorker(ctx context.Context, maddr address.Address, ts *types.TipSet) (address.Address, error) { func (mca mca) StateMinerWorker(ctx context.Context, maddr address.Address, ts *types.TipSet) (address.Address, error) {
return stmgr.GetMinerWorker(ctx, mca.sm, ts.ParentState(), maddr) return stmgr.GetMinerWorkerRaw(ctx, mca.sm, ts.ParentState(), maddr)
} }
func (mca mca) WalletSign(ctx context.Context, a address.Address, v []byte) (*types.Signature, error) { func (mca mca) WalletSign(ctx context.Context, a address.Address, v []byte) (*types.Signature, error) {

View File

@ -27,7 +27,7 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal
height := parents.Height() + uint64(len(tickets)) height := parents.Height() + uint64(len(tickets))
worker, err := stmgr.GetMinerWorker(ctx, sm, st, miner) worker, err := stmgr.GetMinerWorkerRaw(ctx, sm, st, miner)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to get miner worker: %w", err) return nil, xerrors.Errorf("failed to get miner worker: %w", err)
} }

View File

@ -459,3 +459,17 @@ func (sm *StateManager) ListAllActors(ctx context.Context, ts *types.TipSet) ([]
return out, nil return out, nil
} }
func (sm *StateManager) MarketBalance(ctx context.Context, addr address.Address, ts *types.TipSet) (actors.StorageParticipantBalance, error) {
var state actors.StorageMarketState
if _, err := sm.LoadActorState(ctx, actors.StorageMarketAddress, &state, ts); err != nil {
return actors.StorageParticipantBalance{}, err
}
cst := hamt.CSTFromBstore(sm.ChainStore().Blockstore())
b, _, err := actors.GetMarketBalances(ctx, cst, state.Balances, addr)
if err != nil {
return actors.StorageParticipantBalance{}, err
}
return b[0], nil
}

View File

@ -16,7 +16,7 @@ import (
"golang.org/x/xerrors" "golang.org/x/xerrors"
) )
func GetMinerWorker(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (address.Address, error) { func GetMinerWorkerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (address.Address, error) {
recp, err := sm.CallRaw(ctx, &types.Message{ recp, err := sm.CallRaw(ctx, &types.Message{
To: maddr, To: maddr,
From: maddr, From: maddr,
@ -118,7 +118,7 @@ func GetMinerPeerID(ctx context.Context, sm *StateManager, ts *types.TipSet, mad
Method: actors.MAMethods.GetPeerID, Method: actors.MAMethods.GetPeerID,
}, ts) }, ts)
if err != nil { if err != nil {
return "", xerrors.Errorf("callRaw failed: %w", err) return "", xerrors.Errorf("call failed: %w", err)
} }
if recp.ExitCode != 0 { if recp.ExitCode != 0 {
@ -128,6 +128,23 @@ func GetMinerPeerID(ctx context.Context, sm *StateManager, ts *types.TipSet, mad
return peer.IDFromBytes(recp.Return) return peer.IDFromBytes(recp.Return)
} }
func GetMinerWorker(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (address.Address, error) {
recp, err := sm.Call(ctx, &types.Message{
To: maddr,
From: maddr,
Method: actors.MAMethods.GetWorkerAddr,
}, ts)
if err != nil {
return address.Undef, xerrors.Errorf("call failed: %w", err)
}
if recp.ExitCode != 0 {
return address.Undef, xerrors.Errorf("getting miner peer ID failed (exit code %d)", recp.ExitCode)
}
return address.NewFromBytes(recp.Return)
}
func GetMinerProvingPeriodEnd(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (uint64, error) { func GetMinerProvingPeriodEnd(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (uint64, error) {
var mas actors.StorageMinerActorState var mas actors.StorageMinerActorState
_, err := sm.LoadActorState(ctx, maddr, &mas, ts) _, err := sm.LoadActorState(ctx, maddr, &mas, ts)

View File

@ -482,9 +482,9 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
return xerrors.Errorf("minerIsValid failed: %w", err) return xerrors.Errorf("minerIsValid failed: %w", err)
} }
waddr, err := stmgr.GetMinerWorker(ctx, syncer.sm, stateroot, h.Miner) waddr, err := stmgr.GetMinerWorkerRaw(ctx, syncer.sm, stateroot, h.Miner)
if err != nil { if err != nil {
return xerrors.Errorf("GetMinerWorker failed: %w", err) return xerrors.Errorf("GetMinerWorkerRaw failed: %w", err)
} }
if err := h.CheckBlockSignature(ctx, waddr); err != nil { if err := h.CheckBlockSignature(ctx, waddr); err != nil {

View File

@ -212,7 +212,7 @@ func (h handlers) handle(ctx context.Context, req request, w func(func(io.Writer
if handler.errOut != -1 { if handler.errOut != -1 {
err := callResult[handler.errOut].Interface() err := callResult[handler.errOut].Interface()
if err != nil { if err != nil {
log.Warnf("error in RPC call to '%s': %s", req.Method, err) log.Warnf("error in RPC call to '%s': %+v", req.Method, err)
resp.Error = &respError{ resp.Error = &respError{
Code: 1, Code: 1,
Message: err.(error).Error(), Message: err.(error).Error(),

View File

@ -6,6 +6,9 @@ import State from "./State"
import methods from "./chain/methods" import methods from "./chain/methods"
function truncAddr(addr, len) { function truncAddr(addr, len) {
if (!addr) {
return "<!nil>"
}
if (addr.length > len) { if (addr.length > len) {
return <abbr title={addr}>{addr.substr(0, len - 3) + '..'}</abbr> return <abbr title={addr}>{addr.substr(0, len - 3) + '..'}</abbr>
} }

View File

@ -104,11 +104,19 @@ class MarketState extends React.Component {
return <div> return <div>
<div> <div>
<div>Participants:</div> <div>Participants:</div>
{Object.keys(this.state.participants).map(p => <span>{p}</span>)} <table>
<tr><td>Address</td><td>Available</td><td>Locked</td></tr>
{Object.keys(this.state.participants).map(p => <tr>
<td><Address addr={p} client={this.props.client} mountWindow={this.props.mountWindow}/></td>
<td>{this.state.participants[p].Available}</td>
<td>{this.state.participants[p].Locked}</td>
</tr>)}
</table>
</div> </div>
<div> <div>
<div>---</div>
<div>Deals:</div> <div>Deals:</div>
{this.state.deals.map(d => <span>{d}</span>)} {Object.keys(this.state.deals).map(d => <div>{d}</div>)}
</div> </div>
</div> </div>
} }

View File

@ -1,10 +1,10 @@
export default { export default {
"account": [ "filecoin/1.0/AccountActor": [
"Send", "Send",
"Constructor", "Constructor",
"GetAddress", "GetAddress",
], ],
"smarket": [ "filecoin/1.0/StoragePowerActor": [
"Send", "Send",
"Constructor", "Constructor",
"CreateStorageMiner", "CreateStorageMiner",
@ -15,7 +15,21 @@ export default {
"IsMiner", "IsMiner",
"StorageCollateralForSize" "StorageCollateralForSize"
], ],
"sminer": [ "filecoin/1.0/StorageMarketActor": [
"Send",
"Constructor",
"WithdrawBalance",
"AddBalance",
"CheckLockedBalance",
"PublishStorageDeals",
"HandleCronAction",
"SettleExpiredDeals",
"ProcessStorageDealsPayment",
"SlashStorageDealCollateral",
"GetLastExpirationFromDealIDs",
"ActivateStorageDeals",
],
"filecoin/1.0/StorageMinerActor": [
"Send", "Send",
"Constructor", "Constructor",
"CommitSector", "CommitSector",
@ -36,7 +50,7 @@ export default {
"PaymentVerifyInclusion", "PaymentVerifyInclusion",
"PaymentVerifySector", "PaymentVerifySector",
], ],
"multisig": [ "filecoin/1.0/MultisigActor": [
"Send", "Send",
"Constructor", "Constructor",
"Propose", "Propose",
@ -48,13 +62,13 @@ export default {
"SwapSigner", "SwapSigner",
"ChangeRequirement", "ChangeRequirement",
], ],
"init": [ "filecoin/1.0/InitActor": [
"Send", "Send",
"Constructor", "Constructor",
"Exec", "Exec",
"GetIdForAddress" "GetIdForAddress"
], ],
"paych": [ "filecoin/1.0/PaymentChannelActor": [
"Send", "Send",
"Constructor", "Constructor",
"UpdateChannelState", "UpdateChannelState",

View File

@ -5,6 +5,7 @@ import (
"errors" "errors"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"io" "io"
"math"
"os" "os"
"github.com/ipfs/go-blockservice" "github.com/ipfs/go-blockservice"
@ -81,6 +82,7 @@ func (a *API) ClientStartDeal(ctx context.Context, data cid.Cid, miner address.A
proposal := deals.ClientDealProposal{ proposal := deals.ClientDealProposal{
Data: data, Data: data,
TotalPrice: total, TotalPrice: total,
ProposalExpiration: math.MaxUint64, // TODO: set something reasonable
Duration: blocksDuration, Duration: blocksDuration,
ProviderAddress: miner, ProviderAddress: miner,
Client: self, Client: self,

View File

@ -58,25 +58,7 @@ func (a *StateAPI) StateMinerPower(ctx context.Context, maddr address.Address, t
} }
func (a *StateAPI) StateMinerWorker(ctx context.Context, m address.Address, ts *types.TipSet) (address.Address, error) { func (a *StateAPI) StateMinerWorker(ctx context.Context, m address.Address, ts *types.TipSet) (address.Address, error) {
ret, err := a.StateManager.Call(ctx, &types.Message{ return stmgr.GetMinerWorker(ctx, a.StateManager, ts, m)
From: m,
To: m,
Method: actors.MAMethods.GetWorkerAddr,
}, ts)
if err != nil {
return address.Undef, xerrors.Errorf("failed to get miner worker addr: %w", err)
}
if ret.ExitCode != 0 {
return address.Undef, xerrors.Errorf("failed to get miner worker addr (exit code %d)", ret.ExitCode)
}
w, err := address.NewFromBytes(ret.Return)
if err != nil {
return address.Undef, xerrors.Errorf("GetWorkerAddr returned malformed address: %w", err)
}
return w, nil
} }
func (a *StateAPI) StateMinerPeerID(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) { func (a *StateAPI) StateMinerPeerID(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) {
@ -232,17 +214,7 @@ func (a *StateAPI) StateListActors(ctx context.Context, ts *types.TipSet) ([]add
} }
func (a *StateAPI) StateMarketBalance(ctx context.Context, addr address.Address, ts *types.TipSet) (actors.StorageParticipantBalance, error) { func (a *StateAPI) StateMarketBalance(ctx context.Context, addr address.Address, ts *types.TipSet) (actors.StorageParticipantBalance, error) {
var state actors.StorageMarketState return a.StateManager.MarketBalance(ctx, addr, ts)
if _, err := a.StateManager.LoadActorState(ctx, actors.StorageMarketAddress, &state, ts); err != nil {
return actors.StorageParticipantBalance{}, err
}
cst := hamt.CSTFromBstore(a.StateManager.ChainStore().Blockstore())
b, _, err := actors.GetMarketBalances(ctx, cst, state.Balances, addr)
if err != nil {
return actors.StorageParticipantBalance{}, err
}
return b[0], nil
} }
func (a *StateAPI) StateMarketParticipants(ctx context.Context, ts *types.TipSet) (map[string]actors.StorageParticipantBalance, error) { func (a *StateAPI) StateMarketParticipants(ctx context.Context, ts *types.TipSet) (map[string]actors.StorageParticipantBalance, error) {