2019-10-18 06:16:59 +00:00
package actors
import (
2019-10-19 04:54:22 +00:00
"bytes"
2019-10-21 18:12:11 +00:00
"context"
2019-10-22 11:29:41 +00:00
2019-10-19 04:54:22 +00:00
"github.com/filecoin-project/go-amt-ipld"
2019-10-18 06:16:59 +00:00
"github.com/ipfs/go-cid"
"github.com/ipfs/go-hamt-ipld"
2019-10-19 10:20:33 +00:00
cbg "github.com/whyrusleeping/cbor-gen"
2019-10-21 18:12:11 +00:00
"golang.org/x/xerrors"
2019-10-18 06:16:59 +00:00
2019-10-21 18:12:11 +00:00
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors/aerrors"
"github.com/filecoin-project/lotus/chain/address"
"github.com/filecoin-project/lotus/chain/types"
2019-10-18 06:16:59 +00:00
)
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
2019-10-19 10:20:33 +00:00
ActivateStorageDeals uint64
2019-10-18 06:16:59 +00:00
}
2019-10-19 10:20:33 +00:00
var SMAMethods = smaMethods { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 }
2019-10-18 06:16:59 +00:00
func ( sma StorageMarketActor ) Exports ( ) [ ] interface { } {
return [ ] interface { } {
2019-10-19 04:54:22 +00:00
2 : sma . WithdrawBalance ,
3 : sma . AddBalance ,
2019-10-18 06:16:59 +00:00
// 4: sma.CheckLockedBalance,
2019-10-19 04:54:22 +00:00
5 : sma . PublishStorageDeals ,
2019-10-18 06:16:59 +00:00
// 6: sma.HandleCronAction,
// 7: sma.SettleExpiredDeals,
// 8: sma.ProcessStorageDealsPayment,
// 9: sma.SlashStorageDealCollateral,
// 10: sma.GetLastExpirationFromDealIDs,
2019-10-19 10:20:33 +00:00
11 : sma . ActivateStorageDeals , // TODO: move under PublishStorageDeals after specs team approves
2019-10-18 06:16:59 +00:00
}
}
type StorageParticipantBalance struct {
Locked types . BigInt
Available types . BigInt
}
type StorageMarketState struct {
2019-10-19 10:20:33 +00:00
Balances cid . Cid // hamt<addr, StorageParticipantBalance>
Deals cid . Cid // amt<StorageDeal>
NextDealID uint64 // TODO: amt.LastIndex()
2019-10-19 04:54:22 +00:00
}
2019-10-21 18:12:11 +00:00
// TODO: serialization mode spec
2019-10-22 10:20:43 +00:00
type SerializationMode = uint64
2019-10-21 18:12:11 +00:00
const (
SerializationUnixFSv0 = iota
// IPLD / car
)
2019-10-19 04:54:22 +00:00
type StorageDealProposal struct {
2019-10-21 08:53:41 +00:00
PieceRef [ ] byte // cid bytes // TODO: spec says to use cid.Cid, probably not a good idea
2019-10-19 04:54:22 +00:00
PieceSize uint64
2019-10-21 18:12:11 +00:00
PieceSerialization SerializationMode // Needs to be here as it tells how data in the sector maps to PieceRef cid
Client address . Address
Provider address . Address
2019-10-19 04:54:22 +00:00
ProposalExpiration uint64
2019-10-21 18:12:11 +00:00
Duration uint64 // TODO: spec proposes 'DealExpiration', but that's awkward as it
// doesn't tell when the deal actually starts, so the price per block is impossible to
// calculate. It also doesn't incentivize the miner to seal / activate sooner, as he
// still get's paid the full amount specified in the deal
//
// Changing to duration makes sure that the price-per-block is defined, and the miner
// doesn't get paid when not storing the sector
StoragePrice types . BigInt
StorageCollateral types . BigInt
ProposerSignature * types . Signature
}
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 ) Verify ( ) error {
unsigned := * sdp
unsigned . ProposerSignature = nil
var buf bytes . Buffer
2019-10-23 12:59:57 +00:00
if err := unsigned . MarshalCBOR ( & buf ) ; err != nil {
2019-10-21 18:12:11 +00:00
return err
}
return sdp . ProposerSignature . Verify ( sdp . Client , buf . Bytes ( ) )
2019-10-19 04:54:22 +00:00
}
2019-10-23 17:39:14 +00:00
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 ( ) )
}
2019-10-19 04:54:22 +00:00
type StorageDeal struct {
Proposal StorageDealProposal
2019-10-23 17:39:14 +00:00
CounterSignature * types . Signature
2019-10-18 06:16:59 +00:00
}
2019-10-19 10:20:33 +00:00
type OnChainDeal struct {
Deal StorageDeal
ActivationEpoch uint64 // 0 = inactive
}
2019-10-18 06:16:59 +00:00
type WithdrawBalanceParams struct {
Balance types . BigInt
}
func ( sma StorageMarketActor ) WithdrawBalance ( act * types . Actor , vmctx types . VMContext , params * WithdrawBalanceParams ) ( [ ] byte , ActorError ) {
2019-10-21 18:12:11 +00:00
// TODO: (spec) this should be 2-stage
2019-10-18 06:16:59 +00:00
var self StorageMarketState
old := vmctx . Storage ( ) . GetHead ( )
if err := vmctx . Storage ( ) . Get ( old , & self ) ; err != nil {
return nil , err
}
2019-10-22 10:09:36 +00:00
b , bnd , err := GetMarketBalances ( vmctx . Context ( ) , vmctx . Ipld ( ) , self . Balances , vmctx . Message ( ) . From )
2019-10-18 06:16:59 +00:00
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" )
}
2019-10-19 04:54:22 +00:00
bcid , err := setMarketBalances ( vmctx , bnd , map [ address . Address ] StorageParticipantBalance {
2019-10-18 06:16:59 +00:00
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
}
2019-10-22 10:09:36 +00:00
b , bnd , err := GetMarketBalances ( vmctx . Context ( ) , vmctx . Ipld ( ) , self . Balances , vmctx . Message ( ) . From )
2019-10-18 06:16:59 +00:00
if err != nil {
return nil , aerrors . Wrap ( err , "could not get balance" )
}
balance := b [ 0 ]
balance . Available = types . BigAdd ( balance . Available , vmctx . Message ( ) . Value )
2019-10-19 04:54:22 +00:00
bcid , err := setMarketBalances ( vmctx , bnd , map [ address . Address ] StorageParticipantBalance {
2019-10-18 06:16:59 +00:00
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 )
}
2019-10-19 04:54:22 +00:00
func setMarketBalances ( vmctx types . VMContext , nd * hamt . Node , set map [ address . Address ] StorageParticipantBalance ) ( cid . Cid , ActorError ) {
2019-10-18 06:16:59 +00:00
for addr , b := range set {
2019-10-23 17:39:14 +00:00
if err := nd . Set ( vmctx . Context ( ) , string ( addr . Bytes ( ) ) , & b ) ; err != nil {
2019-10-18 06:16:59 +00:00
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
}
2019-10-22 10:09:36 +00:00
func GetMarketBalances ( ctx context . Context , store * hamt . CborIpldStore , rcid cid . Cid , addrs ... address . Address ) ( [ ] StorageParticipantBalance , * hamt . Node , ActorError ) {
nd , err := hamt . LoadNode ( ctx , store , rcid )
2019-10-18 06:16:59 +00:00
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
2019-10-22 10:09:36 +00:00
err = nd . Find ( ctx , string ( a . Bytes ( ) ) , & balance )
2019-10-18 06:16:59 +00:00
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 ) {
}
2019-10-19 04:54:22 +00:00
* /
type PublishStorageDealsParams struct {
Deals [ ] StorageDeal
}
type PublishStorageDealResponse struct {
DealIDs [ ] uint64
}
2019-10-19 10:20:33 +00:00
// TODO: spec says 'call by CommitSector in StorageMiningSubsystem', and then
// says that this should be called before CommitSector. For now assuming that
// they meant 2 separate methods, See 'ActivateStorageDeals' below
2019-10-19 04:54:22 +00:00
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
2019-10-18 06:16:59 +00:00
2019-10-19 04:54:22 +00:00
out := PublishStorageDealResponse {
DealIDs : make ( [ ] uint64 , len ( params . Deals ) ) ,
}
for i , deal := range params . Deals {
if err := self . validateDeal ( vmctx , deal ) ; err != nil {
return nil , err
}
2019-10-23 17:39:14 +00:00
err := deals . Set ( self . NextDealID , & OnChainDeal { Deal : deal } )
2019-10-19 04:54:22 +00:00
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" )
}
2019-10-18 06:16:59 +00:00
2019-10-19 04:54:22 +00:00
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
2019-10-18 06:16:59 +00:00
}
2019-10-19 04:54:22 +00:00
func ( self * StorageMarketState ) validateDeal ( vmctx types . VMContext , deal StorageDeal ) aerrors . ActorError {
// REVIEW: just > ?
if vmctx . BlockHeight ( ) >= deal . Proposal . ProposalExpiration {
return aerrors . New ( 1 , "deal proposal already expired" )
}
2019-10-23 17:39:14 +00:00
if err := deal . Proposal . Verify ( ) ; err != nil {
return aerrors . Absorb ( err , 2 , "verifying proposer signature" )
2019-10-19 04:54:22 +00:00
}
2019-10-23 17:39:14 +00:00
workerBytes , aerr := vmctx . Send ( deal . Proposal . Provider , MAMethods . GetWorkerAddr , types . NewInt ( 0 ) , nil )
if aerr != nil {
return aerr
2019-10-19 04:54:22 +00:00
}
2019-10-23 17:39:14 +00:00
providerWorker , err := address . NewFromBytes ( workerBytes )
2019-10-19 04:54:22 +00:00
if err != nil {
2019-10-23 17:39:14 +00:00
return aerrors . HandleExternalError ( err , "parsing provider worker address bytes" )
2019-10-19 04:54:22 +00:00
}
2019-10-23 17:39:14 +00:00
err = deal . Verify ( providerWorker )
2019-10-19 04:54:22 +00:00
if err != nil {
2019-10-23 17:39:14 +00:00
return aerrors . Absorb ( err , 2 , "verifying provider signature" )
2019-10-19 04:54:22 +00:00
}
// TODO: maybe this is actually fine
2019-10-23 17:39:14 +00:00
if vmctx . Message ( ) . From != providerWorker && vmctx . Message ( ) . From != deal . Proposal . Client {
2019-10-19 10:20:33 +00:00
return aerrors . New ( 4 , "message not sent by deal participant" )
2019-10-19 04:54:22 +00:00
}
// 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)
2019-10-23 17:39:14 +00:00
b , bnd , aerr := GetMarketBalances ( vmctx . Context ( ) , vmctx . Ipld ( ) , self . Balances , deal . Proposal . Client , providerWorker )
2019-10-19 04:54:22 +00:00
if aerr != nil {
return aerrors . Wrap ( aerr , "getting client, and provider balances" )
}
clientBalance := b [ 0 ]
providerBalance := b [ 1 ]
if clientBalance . Available . LessThan ( deal . Proposal . StoragePrice ) {
2019-10-19 10:20:33 +00:00
return aerrors . Newf ( 5 , "client doesn't have enough available funds to cover StoragePrice; %d < %d" , clientBalance . Available , deal . Proposal . StoragePrice )
2019-10-19 04:54:22 +00:00
}
clientBalance = lockFunds ( clientBalance , deal . Proposal . StoragePrice )
// TODO: REVIEW: Not clear who pays for this
if providerBalance . Available . LessThan ( deal . Proposal . StorageCollateral ) {
2019-10-19 10:20:33 +00:00
return aerrors . Newf ( 6 , "provider doesn't have enough available funds to cover StorageCollateral; %d < %d" , providerBalance . Available , deal . Proposal . StorageCollateral )
2019-10-19 04:54:22 +00:00
}
providerBalance = lockFunds ( providerBalance , deal . Proposal . StorageCollateral )
// TODO: piece checks (e.g. size > sectorSize)?
bcid , aerr := setMarketBalances ( vmctx , bnd , map [ address . Address ] StorageParticipantBalance {
2019-10-24 14:24:31 +00:00
deal . Proposal . Client : clientBalance ,
providerWorker : providerBalance ,
2019-10-19 04:54:22 +00:00
} )
if aerr != nil {
return aerr
}
self . Balances = bcid
return nil
}
2019-10-19 10:20:33 +00:00
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 {
// TODO: kind of annoying that this can be caused by gas, otherwise could be fatal
return nil , aerrors . HandleExternalError ( err , "loading deals amt" )
}
for _ , deal := range params . Deals {
var dealInfo OnChainDeal
if err := deals . Get ( deal , & dealInfo ) ; err != nil {
return nil , aerrors . HandleExternalError ( err , "getting del info failed" )
}
2019-10-24 14:24:31 +00:00
if vmctx . Message ( ) . From != dealInfo . Deal . Proposal . Provider {
return nil , aerrors . New ( 1 , "ActivateStorageDeals can only be called by the deal provider" )
2019-10-19 10:20:33 +00:00
}
if vmctx . BlockHeight ( ) > dealInfo . Deal . Proposal . 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 ( )
2019-10-24 14:24:31 +00:00
if err := deals . Set ( deal , & dealInfo ) ; err != nil {
2019-10-19 10:20:33 +00:00
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 {
// TODO: kind of annoying that this can be caused by gas, otherwise could be fatal
return nil , aerrors . HandleExternalError ( err , "loading deals amt" )
}
for _ , deal := range params . DealIDs {
var dealInfo OnChainDeal
if err := deals . Get ( deal , & dealInfo ) ; err != nil {
return nil , aerrors . HandleExternalError ( err , "getting del info failed" )
}
encoded , err := CreateExecParams ( StorageMinerCodeCid , & IsMinerParam {
Addr : vmctx . Message ( ) . From ,
} )
if err != nil {
return nil , err
}
ret , err := vmctx . Send ( StoragePowerAddress , SPAMethods . IsMiner , types . NewInt ( 0 ) , encoded )
if err != nil {
return nil , err
}
if bytes . Equal ( ret , cbg . CborBoolTrue ) {
return nil , aerrors . New ( 1 , "ProcessStorageDealsPayment can only be called by storage miner actors" )
}
if vmctx . BlockHeight ( ) > dealInfo . Deal . Proposal . ProposalExpiration {
// TODO: ???
return nil , nil
}
// todo: check math (written on a plane, also tired)
// TODO: division is hard, this more than likely has some off-by-one issue
2019-10-22 10:09:36 +00:00
toPay := types . BigDiv ( types . BigMul ( dealInfo . Deal . Proposal . StoragePrice , types . NewInt ( build . ProvingPeriodDuration ) ) , types . NewInt ( dealInfo . Deal . Proposal . Duration ) )
2019-10-19 10:20:33 +00:00
2019-10-24 14:24:31 +00:00
// TODO: cache somehow to conserve gas
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" )
}
b , bnd , err := GetMarketBalances ( vmctx . Context ( ) , vmctx . Ipld ( ) , self . Balances , dealInfo . Deal . Proposal . Client , providerWorker )
2019-10-19 10:20:33 +00:00
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 {
2019-10-24 14:24:31 +00:00
dealInfo . Deal . Proposal . Client : clientBal ,
providerWorker : providerBal ,
2019-10-19 10:20:33 +00:00
} )
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
}
2019-10-19 04:54:22 +00:00
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 ) {
2019-10-19 10:20:33 +00:00
// TODO: some asserts
2019-10-19 04:54:22 +00:00
return types . BigSub ( from , amt ) , types . BigAdd ( to , amt )
}
/ *
2019-10-18 06:16:59 +00:00
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 ) {
}
* /