164 lines
3.4 KiB
Go
164 lines
3.4 KiB
Go
package deals
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/filecoin-project/go-lotus/chain/address"
|
|
"github.com/filecoin-project/go-lotus/chain/stmgr"
|
|
"github.com/filecoin-project/go-lotus/chain/types"
|
|
"github.com/filecoin-project/go-lotus/lib/cborrpc"
|
|
datastore "github.com/ipfs/go-datastore"
|
|
cbor "github.com/ipfs/go-ipld-cbor"
|
|
inet "github.com/libp2p/go-libp2p-core/network"
|
|
"golang.org/x/xerrors"
|
|
)
|
|
|
|
func (h *Handler) SetPrice(p types.BigInt, ttlsecs int64) error {
|
|
h.askLk.Lock()
|
|
defer h.askLk.Unlock()
|
|
|
|
var seqno uint64
|
|
if h.ask != nil {
|
|
seqno = h.ask.Ask.SeqNo + 1
|
|
}
|
|
|
|
now := time.Now().Unix()
|
|
ask := &types.StorageAsk{
|
|
Price: p,
|
|
Timestamp: now,
|
|
Expiry: now + ttlsecs,
|
|
Miner: h.actor,
|
|
SeqNo: seqno,
|
|
MinPieceSize: h.minPieceSize,
|
|
}
|
|
|
|
ssa, err := h.signAsk(ask)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return h.saveAsk(ssa)
|
|
}
|
|
|
|
func (h *Handler) getAsk(m address.Address) *types.SignedStorageAsk {
|
|
h.askLk.Lock()
|
|
defer h.askLk.Unlock()
|
|
if m != h.actor {
|
|
return nil
|
|
}
|
|
|
|
return h.ask
|
|
}
|
|
|
|
func (h *Handler) HandleAskStream(s inet.Stream) {
|
|
defer s.Close()
|
|
var ar AskRequest
|
|
if err := cborrpc.ReadCborRPC(s, &ar); err != nil {
|
|
log.Errorf("failed to read AskRequest from incoming stream: %s", err)
|
|
return
|
|
}
|
|
|
|
resp := h.processAskRequest(&ar)
|
|
|
|
if err := cborrpc.WriteCborRPC(s, resp); err != nil {
|
|
log.Errorf("failed to write ask response: %s", err)
|
|
return
|
|
}
|
|
}
|
|
|
|
func (h *Handler) processAskRequest(ar *AskRequest) *AskResponse {
|
|
return &AskResponse{
|
|
Ask: h.getAsk(ar.Miner),
|
|
}
|
|
}
|
|
|
|
var bestAskKey = datastore.NewKey("latest-ask")
|
|
|
|
func (h *Handler) tryLoadAsk() error {
|
|
h.askLk.Lock()
|
|
defer h.askLk.Unlock()
|
|
|
|
err := h.loadAsk()
|
|
if err != nil {
|
|
if xerrors.Is(err, datastore.ErrNotFound) {
|
|
log.Warn("no previous ask found, miner will not accept deals until a price is set")
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (h *Handler) loadAsk() error {
|
|
askb, err := h.ds.Get(datastore.NewKey("latest-ask"))
|
|
if err != nil {
|
|
return xerrors.Errorf("failed to load most recent ask from disk: %w", err)
|
|
}
|
|
|
|
var ssa types.SignedStorageAsk
|
|
if err := cbor.DecodeInto(askb, &ssa); err != nil {
|
|
return err
|
|
}
|
|
|
|
h.ask = &ssa
|
|
return nil
|
|
}
|
|
|
|
func (h *Handler) signAsk(a *types.StorageAsk) (*types.SignedStorageAsk, error) {
|
|
b, err := cbor.DumpObject(a)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
worker, err := h.getWorker(h.actor)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("failed to get worker to sign ask: %w", err)
|
|
}
|
|
|
|
sig, err := h.full.WalletSign(context.TODO(), worker, b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &types.SignedStorageAsk{
|
|
Ask: a,
|
|
Signature: sig,
|
|
}, nil
|
|
}
|
|
|
|
func (h *Handler) saveAsk(a *types.SignedStorageAsk) error {
|
|
b, err := cbor.DumpObject(a)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := h.ds.Put(bestAskKey, b); err != nil {
|
|
return err
|
|
}
|
|
|
|
h.ask = a
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) checkAskSignature(ask *types.SignedStorageAsk) error {
|
|
tss, err := c.sm.TipSetState(c.sm.ChainStore().GetHeaviestTipSet().Cids())
|
|
if err != nil {
|
|
return xerrors.Errorf("failed to get tipsetstate to query for miner worker: %w", err)
|
|
}
|
|
|
|
w, err := stmgr.GetMinerWorker(context.TODO(), c.sm, tss, ask.Ask.Miner)
|
|
if err != nil {
|
|
return xerrors.Errorf("failed to get worker for miner in ask", err)
|
|
}
|
|
|
|
sigb, err := cbor.DumpObject(ask.Ask)
|
|
if err != nil {
|
|
return xerrors.Errorf("failed to re-serialize ask")
|
|
}
|
|
|
|
return ask.Signature.Verify(w, sigb)
|
|
|
|
}
|