671 lines
18 KiB
Go
671 lines
18 KiB
Go
package actors
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"sort"
|
|
|
|
"go.opencensus.io/trace"
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/filecoin-project/go-amt-ipld"
|
|
"github.com/ipfs/go-cid"
|
|
"github.com/ipfs/go-hamt-ipld"
|
|
|
|
"github.com/filecoin-project/go-address"
|
|
"github.com/filecoin-project/go-cbor-util"
|
|
"github.com/filecoin-project/lotus/build"
|
|
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
|
"github.com/filecoin-project/lotus/chain/types"
|
|
"github.com/filecoin-project/lotus/lib/sectorbuilder"
|
|
)
|
|
|
|
type StorageMarketActor struct{}
|
|
|
|
type smaMethods struct {
|
|
Constructor uint64
|
|
WithdrawBalance uint64
|
|
AddBalance uint64
|
|
CheckLockedBalance uint64
|
|
PublishStorageDeals uint64
|
|
HandleCronAction uint64
|
|
SettleExpiredDeals uint64
|
|
ProcessStorageDealsPayment uint64
|
|
SlashStorageDealCollateral uint64
|
|
GetLastExpirationFromDealIDs uint64
|
|
ActivateStorageDeals uint64
|
|
ComputeDataCommitment uint64
|
|
}
|
|
|
|
var SMAMethods = smaMethods{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
|
|
|
|
func (sma StorageMarketActor) Exports() []interface{} {
|
|
return []interface{}{
|
|
2: sma.WithdrawBalance,
|
|
3: sma.AddBalance,
|
|
// 4: sma.CheckLockedBalance,
|
|
5: sma.PublishStorageDeals,
|
|
// 6: sma.HandleCronAction,
|
|
// 7: sma.SettleExpiredDeals,
|
|
// 8: sma.ProcessStorageDealsPayment,
|
|
// 9: sma.SlashStorageDealCollateral,
|
|
// 10: sma.GetLastExpirationFromDealIDs,
|
|
11: sma.ActivateStorageDeals, // TODO: move under PublishStorageDeals after specs team approves
|
|
12: sma.ComputeDataCommitment,
|
|
}
|
|
}
|
|
|
|
type StorageParticipantBalance struct {
|
|
Locked types.BigInt
|
|
Available types.BigInt
|
|
}
|
|
|
|
type StorageMarketState struct {
|
|
Balances cid.Cid // hamt<addr, StorageParticipantBalance>
|
|
Deals cid.Cid // amt<StorageDeal>
|
|
|
|
NextDealID uint64 // TODO: spec
|
|
}
|
|
|
|
// TODO: Drop in favour of car storage
|
|
type SerializationMode = uint64
|
|
|
|
const (
|
|
SerializationUnixFSv0 = iota
|
|
// IPLD / car
|
|
)
|
|
|
|
type StorageDealProposal struct {
|
|
PieceRef []byte // cid bytes // TODO: spec says to use cid.Cid, probably not a good idea
|
|
PieceSize uint64
|
|
|
|
Client address.Address
|
|
Provider address.Address
|
|
|
|
ProposalExpiration uint64
|
|
Duration uint64 // TODO: spec
|
|
|
|
StoragePricePerEpoch types.BigInt
|
|
StorageCollateral types.BigInt
|
|
|
|
ProposerSignature *types.Signature
|
|
}
|
|
|
|
func (sdp *StorageDealProposal) TotalStoragePrice() types.BigInt {
|
|
return types.BigMul(sdp.StoragePricePerEpoch, types.NewInt(sdp.Duration))
|
|
}
|
|
|
|
type SignFunc = func(context.Context, []byte) (*types.Signature, error)
|
|
|
|
func (sdp *StorageDealProposal) Sign(ctx context.Context, sign SignFunc) error {
|
|
if sdp.ProposerSignature != nil {
|
|
return xerrors.New("signature already present in StorageDealProposal")
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := sdp.MarshalCBOR(&buf); err != nil {
|
|
return err
|
|
}
|
|
sig, err := sign(ctx, buf.Bytes())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
sdp.ProposerSignature = sig
|
|
return nil
|
|
}
|
|
|
|
func (sdp *StorageDealProposal) Cid() (cid.Cid, error) {
|
|
nd, err := cborutil.AsIpld(sdp)
|
|
if err != nil {
|
|
return cid.Undef, err
|
|
}
|
|
|
|
return nd.Cid(), nil
|
|
}
|
|
|
|
func (sdp *StorageDealProposal) Verify() error {
|
|
unsigned := *sdp
|
|
unsigned.ProposerSignature = nil
|
|
var buf bytes.Buffer
|
|
if err := unsigned.MarshalCBOR(&buf); err != nil {
|
|
return err
|
|
}
|
|
|
|
return sdp.ProposerSignature.Verify(sdp.Client, buf.Bytes())
|
|
}
|
|
|
|
type OnChainDeal struct {
|
|
PieceRef []byte // cid bytes // TODO: spec says to use cid.Cid, probably not a good idea
|
|
PieceSize uint64
|
|
|
|
Client address.Address
|
|
Provider address.Address
|
|
|
|
ProposalExpiration uint64
|
|
Duration uint64 // TODO: spec
|
|
|
|
StoragePricePerEpoch types.BigInt
|
|
StorageCollateral types.BigInt
|
|
ActivationEpoch uint64 // 0 = inactive
|
|
}
|
|
|
|
type WithdrawBalanceParams struct {
|
|
Balance types.BigInt
|
|
}
|
|
|
|
func (sma StorageMarketActor) WithdrawBalance(act *types.Actor, vmctx types.VMContext, params *WithdrawBalanceParams) ([]byte, ActorError) {
|
|
// TODO: (spec) this should be 2-stage
|
|
|
|
var self StorageMarketState
|
|
old := vmctx.Storage().GetHead()
|
|
if err := vmctx.Storage().Get(old, &self); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
b, bnd, err := GetMarketBalances(vmctx.Context(), vmctx.Ipld(), self.Balances, vmctx.Message().From)
|
|
if err != nil {
|
|
return nil, aerrors.Wrap(err, "could not get balance")
|
|
}
|
|
|
|
balance := b[0]
|
|
|
|
if balance.Available.LessThan(params.Balance) {
|
|
return nil, aerrors.Newf(1, "can not withdraw more funds than available: %s > %s", params.Balance, b[0].Available)
|
|
}
|
|
|
|
balance.Available = types.BigSub(balance.Available, params.Balance)
|
|
|
|
_, err = vmctx.Send(vmctx.Message().From, 0, params.Balance, nil)
|
|
if err != nil {
|
|
return nil, aerrors.Wrap(err, "sending funds failed")
|
|
}
|
|
|
|
bcid, err := setMarketBalances(vmctx, bnd, map[address.Address]StorageParticipantBalance{
|
|
vmctx.Message().From: balance,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
self.Balances = bcid
|
|
|
|
nroot, err := vmctx.Storage().Put(&self)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return nil, vmctx.Storage().Commit(old, nroot)
|
|
}
|
|
|
|
func (sma StorageMarketActor) AddBalance(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
|
var self StorageMarketState
|
|
old := vmctx.Storage().GetHead()
|
|
if err := vmctx.Storage().Get(old, &self); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
b, bnd, err := GetMarketBalances(vmctx.Context(), vmctx.Ipld(), self.Balances, vmctx.Message().From)
|
|
if err != nil {
|
|
return nil, aerrors.Wrap(err, "could not get balance")
|
|
}
|
|
|
|
balance := b[0]
|
|
|
|
balance.Available = types.BigAdd(balance.Available, vmctx.Message().Value)
|
|
|
|
bcid, err := setMarketBalances(vmctx, bnd, map[address.Address]StorageParticipantBalance{
|
|
vmctx.Message().From: balance,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
self.Balances = bcid
|
|
|
|
nroot, err := vmctx.Storage().Put(&self)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return nil, vmctx.Storage().Commit(old, nroot)
|
|
}
|
|
|
|
func setMarketBalances(vmctx types.VMContext, nd *hamt.Node, set map[address.Address]StorageParticipantBalance) (cid.Cid, ActorError) {
|
|
keys := make([]address.Address, 0, len(set))
|
|
for k := range set {
|
|
keys = append(keys, k)
|
|
}
|
|
sort.Slice(keys, func(i, j int) bool {
|
|
return bytes.Compare(keys[i].Bytes(), keys[j].Bytes()) < 0
|
|
})
|
|
for _, addr := range keys {
|
|
balance := set[addr]
|
|
if err := nd.Set(vmctx.Context(), string(addr.Bytes()), &balance); err != nil {
|
|
return cid.Undef, aerrors.HandleExternalError(err, "setting new balance")
|
|
}
|
|
}
|
|
if err := nd.Flush(vmctx.Context()); err != nil {
|
|
return cid.Undef, aerrors.HandleExternalError(err, "flushing balance hamt")
|
|
}
|
|
|
|
c, err := vmctx.Ipld().Put(vmctx.Context(), nd)
|
|
if err != nil {
|
|
return cid.Undef, aerrors.HandleExternalError(err, "failed to balances storage")
|
|
}
|
|
return c, nil
|
|
}
|
|
|
|
func GetMarketBalances(ctx context.Context, store *hamt.CborIpldStore, rcid cid.Cid, addrs ...address.Address) ([]StorageParticipantBalance, *hamt.Node, ActorError) {
|
|
ctx, span := trace.StartSpan(ctx, "GetMarketBalances")
|
|
defer span.End()
|
|
|
|
nd, err := hamt.LoadNode(ctx, store, rcid)
|
|
if err != nil {
|
|
return nil, nil, aerrors.HandleExternalError(err, "failed to load miner set")
|
|
}
|
|
|
|
out := make([]StorageParticipantBalance, len(addrs))
|
|
|
|
for i, a := range addrs {
|
|
var balance StorageParticipantBalance
|
|
err = nd.Find(ctx, string(a.Bytes()), &balance)
|
|
switch err {
|
|
case hamt.ErrNotFound:
|
|
out[i] = StorageParticipantBalance{
|
|
Locked: types.NewInt(0),
|
|
Available: types.NewInt(0),
|
|
}
|
|
case nil:
|
|
out[i] = balance
|
|
default:
|
|
return nil, nil, aerrors.HandleExternalError(err, "failed to do set lookup")
|
|
}
|
|
|
|
}
|
|
|
|
return out, nd, nil
|
|
}
|
|
|
|
/*
|
|
func (sma StorageMarketActor) CheckLockedBalance(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
|
|
|
}
|
|
*/
|
|
|
|
type PublishStorageDealsParams struct {
|
|
Deals []StorageDealProposal
|
|
}
|
|
|
|
type PublishStorageDealResponse struct {
|
|
DealIDs []uint64
|
|
}
|
|
|
|
func (sma StorageMarketActor) PublishStorageDeals(act *types.Actor, vmctx types.VMContext, params *PublishStorageDealsParams) ([]byte, ActorError) {
|
|
var self StorageMarketState
|
|
old := vmctx.Storage().GetHead()
|
|
if err := vmctx.Storage().Get(old, &self); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
deals, err := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Deals)
|
|
if err != nil {
|
|
return nil, aerrors.HandleExternalError(err, "loading deals amt")
|
|
}
|
|
|
|
// todo: handle duplicate deals
|
|
|
|
if len(params.Deals) == 0 {
|
|
return nil, aerrors.New(1, "no storage deals in params.Deals")
|
|
}
|
|
|
|
out := PublishStorageDealResponse{
|
|
DealIDs: make([]uint64, len(params.Deals)),
|
|
}
|
|
|
|
workerBytes, aerr := vmctx.Send(params.Deals[0].Provider, MAMethods.GetWorkerAddr, types.NewInt(0), nil)
|
|
if aerr != nil {
|
|
return nil, aerr
|
|
}
|
|
providerWorker, err := address.NewFromBytes(workerBytes)
|
|
if err != nil {
|
|
return nil, aerrors.HandleExternalError(err, "parsing provider worker address bytes")
|
|
}
|
|
|
|
// TODO: REVIEW: Do we want to check if provider exists in the power actor?
|
|
|
|
for i, deal := range params.Deals {
|
|
if err := self.validateDeal(vmctx, deal, providerWorker); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err := deals.Set(self.NextDealID, &OnChainDeal{
|
|
PieceRef: deal.PieceRef,
|
|
PieceSize: deal.PieceSize,
|
|
|
|
Client: deal.Client,
|
|
Provider: deal.Provider,
|
|
|
|
ProposalExpiration: deal.ProposalExpiration,
|
|
Duration: deal.Duration,
|
|
|
|
StoragePricePerEpoch: deal.StoragePricePerEpoch,
|
|
StorageCollateral: deal.StorageCollateral,
|
|
ActivationEpoch: 0,
|
|
})
|
|
if err != nil {
|
|
return nil, aerrors.HandleExternalError(err, "setting deal in deal AMT")
|
|
}
|
|
out.DealIDs[i] = self.NextDealID
|
|
|
|
self.NextDealID++
|
|
}
|
|
|
|
dealsCid, err := deals.Flush()
|
|
if err != nil {
|
|
return nil, aerrors.HandleExternalError(err, "saving deals AMT")
|
|
}
|
|
|
|
self.Deals = dealsCid
|
|
|
|
nroot, err := vmctx.Storage().Put(&self)
|
|
if err != nil {
|
|
return nil, aerrors.HandleExternalError(err, "storing state failed")
|
|
}
|
|
|
|
aerr = vmctx.Storage().Commit(old, nroot)
|
|
if aerr != nil {
|
|
return nil, aerr
|
|
}
|
|
|
|
var outBuf bytes.Buffer
|
|
if err := out.MarshalCBOR(&outBuf); err != nil {
|
|
return nil, aerrors.HandleExternalError(err, "serialising output")
|
|
}
|
|
|
|
return outBuf.Bytes(), nil
|
|
}
|
|
|
|
func (st *StorageMarketState) validateDeal(vmctx types.VMContext, deal StorageDealProposal, providerWorker address.Address) aerrors.ActorError {
|
|
ctx, span := trace.StartSpan(vmctx.Context(), "validateDeal")
|
|
defer span.End()
|
|
|
|
if vmctx.BlockHeight() > deal.ProposalExpiration {
|
|
return aerrors.New(1, "deal proposal already expired")
|
|
}
|
|
|
|
if vmctx.Message().From != providerWorker {
|
|
return aerrors.New(2, "Deals must be submitted by the miner worker")
|
|
}
|
|
|
|
if err := deal.Verify(); err != nil {
|
|
return aerrors.Absorb(err, 3, "verifying proposer signature")
|
|
}
|
|
|
|
// TODO: do some caching (changes gas so needs to be in spec too)
|
|
b, bnd, aerr := GetMarketBalances(ctx, vmctx.Ipld(), st.Balances, deal.Client, providerWorker)
|
|
if aerr != nil {
|
|
return aerrors.Wrap(aerr, "getting client, and provider balances")
|
|
}
|
|
clientBalance := b[0]
|
|
providerBalance := b[1]
|
|
|
|
totalPrice := deal.TotalStoragePrice()
|
|
|
|
if clientBalance.Available.LessThan(totalPrice) {
|
|
return aerrors.Newf(5, "client doesn't have enough available funds to cover storage price; %d < %d", clientBalance.Available, totalPrice)
|
|
}
|
|
|
|
clientBalance = lockFunds(clientBalance, totalPrice)
|
|
|
|
// TODO: REVIEW: Not clear who pays for this
|
|
if providerBalance.Available.LessThan(deal.StorageCollateral) {
|
|
return aerrors.Newf(6, "provider doesn't have enough available funds to cover StorageCollateral; %d < %d", providerBalance.Available, deal.StorageCollateral)
|
|
}
|
|
|
|
providerBalance = lockFunds(providerBalance, deal.StorageCollateral)
|
|
|
|
// TODO: piece checks (e.g. size > sectorSize)?
|
|
|
|
bcid, aerr := setMarketBalances(vmctx, bnd, map[address.Address]StorageParticipantBalance{
|
|
deal.Client: clientBalance,
|
|
providerWorker: providerBalance,
|
|
})
|
|
if aerr != nil {
|
|
return aerr
|
|
}
|
|
|
|
st.Balances = bcid
|
|
|
|
return nil
|
|
}
|
|
|
|
type ActivateStorageDealsParams struct {
|
|
Deals []uint64
|
|
}
|
|
|
|
func (sma StorageMarketActor) ActivateStorageDeals(act *types.Actor, vmctx types.VMContext, params *ActivateStorageDealsParams) ([]byte, ActorError) {
|
|
var self StorageMarketState
|
|
old := vmctx.Storage().GetHead()
|
|
if err := vmctx.Storage().Get(old, &self); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
deals, err := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Deals)
|
|
if err != nil {
|
|
return nil, aerrors.HandleExternalError(err, "loading deals amt")
|
|
}
|
|
|
|
for _, deal := range params.Deals {
|
|
var dealInfo OnChainDeal
|
|
if err := deals.Get(deal, &dealInfo); err != nil {
|
|
if _, is := err.(*amt.ErrNotFound); is {
|
|
return nil, aerrors.New(3, "deal not found")
|
|
}
|
|
return nil, aerrors.HandleExternalError(err, "getting deal info failed")
|
|
}
|
|
|
|
if vmctx.Message().From != dealInfo.Provider {
|
|
return nil, aerrors.New(1, "ActivateStorageDeals can only be called by the deal provider")
|
|
}
|
|
|
|
if vmctx.BlockHeight() > dealInfo.ProposalExpiration {
|
|
return nil, aerrors.New(2, "deal cannot be activated: proposal expired")
|
|
}
|
|
|
|
if dealInfo.ActivationEpoch > 0 {
|
|
// this probably can't happen in practice
|
|
return nil, aerrors.New(3, "deal already active")
|
|
}
|
|
|
|
dealInfo.ActivationEpoch = vmctx.BlockHeight()
|
|
|
|
if err := deals.Set(deal, &dealInfo); err != nil {
|
|
return nil, aerrors.HandleExternalError(err, "setting deal info in AMT failed")
|
|
}
|
|
}
|
|
|
|
dealsCid, err := deals.Flush()
|
|
if err != nil {
|
|
return nil, aerrors.HandleExternalError(err, "saving deals AMT")
|
|
}
|
|
|
|
self.Deals = dealsCid
|
|
|
|
nroot, err := vmctx.Storage().Put(&self)
|
|
if err != nil {
|
|
return nil, aerrors.HandleExternalError(err, "storing state failed")
|
|
}
|
|
|
|
aerr := vmctx.Storage().Commit(old, nroot)
|
|
if aerr != nil {
|
|
return nil, aerr
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
type ProcessStorageDealsPaymentParams struct {
|
|
DealIDs []uint64
|
|
}
|
|
|
|
func (sma StorageMarketActor) ProcessStorageDealsPayment(act *types.Actor, vmctx types.VMContext, params *ProcessStorageDealsPaymentParams) ([]byte, ActorError) {
|
|
var self StorageMarketState
|
|
old := vmctx.Storage().GetHead()
|
|
if err := vmctx.Storage().Get(old, &self); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
deals, err := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Deals)
|
|
if err != nil {
|
|
return nil, aerrors.HandleExternalError(err, "loading deals amt")
|
|
}
|
|
|
|
// TODO: Would be nice if send could assert actor type
|
|
workerBytes, aerr := vmctx.Send(vmctx.Message().From, MAMethods.GetWorkerAddr, types.NewInt(0), nil)
|
|
if aerr != nil {
|
|
return nil, aerr
|
|
}
|
|
providerWorker, err := address.NewFromBytes(workerBytes)
|
|
if err != nil {
|
|
return nil, aerrors.HandleExternalError(err, "parsing provider worker address bytes")
|
|
}
|
|
|
|
for _, deal := range params.DealIDs {
|
|
var dealInfo OnChainDeal
|
|
if err := deals.Get(deal, &dealInfo); err != nil {
|
|
if _, is := err.(*amt.ErrNotFound); is {
|
|
return nil, aerrors.New(2, "deal not found")
|
|
}
|
|
return nil, aerrors.HandleExternalError(err, "getting deal info failed")
|
|
}
|
|
|
|
if dealInfo.Provider != vmctx.Message().From {
|
|
return nil, aerrors.New(3, "ProcessStorageDealsPayment can only be called by deal provider")
|
|
}
|
|
|
|
if vmctx.BlockHeight() < dealInfo.ActivationEpoch {
|
|
// TODO: This is probably fatal
|
|
return nil, aerrors.New(4, "ActivationEpoch lower than block height")
|
|
}
|
|
|
|
if vmctx.BlockHeight() > dealInfo.ActivationEpoch+dealInfo.Duration {
|
|
// Deal expired, miner should drop it
|
|
// TODO: process payment for the remainder of last proving period
|
|
return nil, nil
|
|
}
|
|
|
|
toPay := types.BigMul(dealInfo.StoragePricePerEpoch, types.NewInt(build.SlashablePowerDelay))
|
|
|
|
b, bnd, aerr := GetMarketBalances(vmctx.Context(), vmctx.Ipld(), self.Balances, dealInfo.Client, providerWorker)
|
|
if aerr != nil {
|
|
return nil, aerr
|
|
}
|
|
clientBal := b[0]
|
|
providerBal := b[1]
|
|
|
|
clientBal.Locked, providerBal.Available = transferFunds(clientBal.Locked, providerBal.Available, toPay)
|
|
|
|
// TODO: call set once
|
|
bcid, aerr := setMarketBalances(vmctx, bnd, map[address.Address]StorageParticipantBalance{
|
|
dealInfo.Client: clientBal,
|
|
providerWorker: providerBal,
|
|
})
|
|
if aerr != nil {
|
|
return nil, aerr
|
|
}
|
|
|
|
self.Balances = bcid
|
|
}
|
|
|
|
nroot, err := vmctx.Storage().Put(&self)
|
|
if err != nil {
|
|
return nil, aerrors.HandleExternalError(err, "storing state failed")
|
|
}
|
|
|
|
aerr = vmctx.Storage().Commit(old, nroot)
|
|
if aerr != nil {
|
|
return nil, aerr
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
func lockFunds(p StorageParticipantBalance, amt types.BigInt) StorageParticipantBalance {
|
|
p.Available, p.Locked = transferFunds(p.Available, p.Locked, amt)
|
|
return p
|
|
}
|
|
|
|
func transferFunds(from, to, amt types.BigInt) (types.BigInt, types.BigInt) {
|
|
// TODO: some asserts
|
|
return types.BigSub(from, amt), types.BigAdd(to, amt)
|
|
}
|
|
|
|
type ComputeDataCommitmentParams struct {
|
|
DealIDs []uint64
|
|
SectorSize uint64
|
|
}
|
|
|
|
func (sma StorageMarketActor) ComputeDataCommitment(act *types.Actor, vmctx types.VMContext, params *ComputeDataCommitmentParams) ([]byte, ActorError) {
|
|
var self StorageMarketState
|
|
old := vmctx.Storage().GetHead()
|
|
if err := vmctx.Storage().Get(old, &self); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
deals, err := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Deals)
|
|
if err != nil {
|
|
return nil, aerrors.HandleExternalError(err, "loading deals amt")
|
|
}
|
|
|
|
if len(params.DealIDs) == 0 {
|
|
return nil, aerrors.New(3, "no deal IDs")
|
|
}
|
|
|
|
var pieces []sectorbuilder.PublicPieceInfo
|
|
for _, deal := range params.DealIDs {
|
|
var dealInfo OnChainDeal
|
|
if err := deals.Get(deal, &dealInfo); err != nil {
|
|
if _, is := err.(*amt.ErrNotFound); is {
|
|
return nil, aerrors.New(4, "deal not found")
|
|
}
|
|
return nil, aerrors.HandleExternalError(err, "getting deal info failed")
|
|
}
|
|
|
|
if dealInfo.Provider != vmctx.Message().From {
|
|
return nil, aerrors.New(5, "referenced deal was not from caller")
|
|
}
|
|
|
|
var commP [32]byte
|
|
copy(commP[:], dealInfo.PieceRef)
|
|
|
|
pieces = append(pieces, sectorbuilder.PublicPieceInfo{
|
|
Size: dealInfo.PieceSize,
|
|
CommP: commP,
|
|
})
|
|
}
|
|
|
|
commd, err := sectorbuilder.GenerateDataCommitment(params.SectorSize, pieces)
|
|
if err != nil {
|
|
return nil, aerrors.Absorb(err, 6, "failed to generate data commitment from pieces")
|
|
}
|
|
|
|
return commd[:], nil
|
|
}
|
|
|
|
/*
|
|
func (sma StorageMarketActor) HandleCronAction(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
|
|
|
}
|
|
|
|
func (sma StorageMarketActor) SettleExpiredDeals(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
|
|
|
}
|
|
|
|
func (sma StorageMarketActor) SlashStorageDealCollateral(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
|
|
|
}
|
|
|
|
func (sma StorageMarketActor) GetLastExpirationFromDealIDs(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
|
|
|
}
|
|
*/
|