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-12-08 22:39:08 +00:00
"sort"
2019-12-07 14:12:10 +00:00
2019-12-12 18:25:15 +00:00
"go.opencensus.io/trace"
2019-11-29 19:11:01 +00:00
"golang.org/x/xerrors"
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-12-19 20:13:17 +00:00
"github.com/filecoin-project/go-address"
2020-01-21 19:02:51 +00:00
cborutil "github.com/filecoin-project/go-cbor-util"
2020-01-07 16:18:35 +00:00
"github.com/filecoin-project/go-sectorbuilder"
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/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-31 01:22:50 +00:00
ComputeDataCommitment uint64
2019-10-18 06:16:59 +00:00
}
2019-10-31 01:22:50 +00:00
var SMAMethods = smaMethods { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 }
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-31 01:22:50 +00:00
12 : sma . ComputeDataCommitment ,
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>
2019-10-24 15:12:50 +00:00
NextDealID uint64 // TODO: spec
2019-10-19 04:54:22 +00:00
}
2019-10-24 15:12:50 +00:00
// TODO: Drop in favour of car storage
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-12-08 22:39:08 +00:00
PieceRef [ ] byte // cid bytes // TODO: spec says to use cid.Cid, probably not a good idea
PieceSize uint64
2019-10-21 18:12:11 +00:00
Client address . Address
Provider address . Address
2019-10-19 04:54:22 +00:00
ProposalExpiration uint64
2019-10-29 12:02:13 +00:00
Duration uint64 // TODO: spec
2019-10-21 18:12:11 +00:00
2019-10-29 10:01:18 +00:00
StoragePricePerEpoch types . BigInt
StorageCollateral types . BigInt
2019-10-21 18:12:11 +00:00
ProposerSignature * types . Signature
}
2019-10-29 10:01:18 +00:00
func ( sdp * StorageDealProposal ) TotalStoragePrice ( ) types . BigInt {
return types . BigMul ( sdp . StoragePricePerEpoch , types . NewInt ( sdp . Duration ) )
}
2019-10-21 18:12:11 +00:00
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
}
2019-11-29 19:11:01 +00:00
func ( sdp * StorageDealProposal ) Cid ( ) ( cid . Cid , error ) {
nd , err := cborutil . AsIpld ( sdp )
if err != nil {
return cid . Undef , err
}
return nd . Cid ( ) , nil
}
2020-01-09 22:18:06 +00:00
func ( sdp * StorageDealProposal ) Verify ( worker address . Address ) error {
if sdp . Client != worker || worker == address . Undef {
unsigned := * sdp
unsigned . ProposerSignature = nil
var buf bytes . Buffer
if err := unsigned . MarshalCBOR ( & buf ) ; err != nil {
return err
}
if err := sdp . ProposerSignature . Verify ( sdp . Client , buf . Bytes ( ) ) ; err != nil {
return err
}
2019-10-21 18:12:11 +00:00
}
2020-01-09 22:18:06 +00:00
return nil
2019-10-19 04:54:22 +00:00
}
2019-12-07 14:12:10 +00:00
type OnChainDeal struct {
2019-12-08 22:39:08 +00:00
PieceRef [ ] byte // cid bytes // TODO: spec says to use cid.Cid, probably not a good idea
PieceSize uint64
2019-10-23 17:39:14 +00:00
2019-12-07 14:12:10 +00:00
Client address . Address
Provider address . Address
2019-10-23 17:39:14 +00:00
2019-12-07 14:12:10 +00:00
ProposalExpiration uint64
Duration uint64 // TODO: spec
2019-10-18 06:16:59 +00:00
2019-12-07 14:12:10 +00:00
StoragePricePerEpoch types . BigInt
StorageCollateral types . BigInt
ActivationEpoch uint64 // 0 = inactive
2019-10-19 10:20:33 +00:00
}
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-12-08 22:39:08 +00:00
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 ]
2019-10-24 15:46:21 +00:00
if err := nd . Set ( vmctx . Context ( ) , string ( addr . Bytes ( ) ) , & balance ) ; 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 ) {
2019-12-12 18:25:15 +00:00
ctx , span := trace . StartSpan ( ctx , "GetMarketBalances" )
defer span . End ( )
2019-10-22 10:09:36 +00:00
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 {
2019-12-07 14:12:10 +00:00
Deals [ ] StorageDealProposal
2019-10-19 04:54:22 +00:00
}
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
2019-10-18 06:16:59 +00:00
2019-10-24 15:12:50 +00:00
if len ( params . Deals ) == 0 {
return nil , aerrors . New ( 1 , "no storage deals in params.Deals" )
}
2019-10-19 04:54:22 +00:00
out := PublishStorageDealResponse {
DealIDs : make ( [ ] uint64 , len ( params . Deals ) ) ,
}
2019-12-07 14:12:10 +00:00
workerBytes , aerr := vmctx . Send ( params . Deals [ 0 ] . Provider , MAMethods . GetWorkerAddr , types . NewInt ( 0 ) , nil )
2019-10-24 15:12:50 +00:00
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?
2019-10-19 04:54:22 +00:00
for i , deal := range params . Deals {
2019-10-24 15:12:50 +00:00
if err := self . validateDeal ( vmctx , deal , providerWorker ) ; err != nil {
2019-10-19 04:54:22 +00:00
return nil , err
}
2019-12-07 14:12:10 +00:00
err := deals . Set ( self . NextDealID , & OnChainDeal {
2019-12-08 22:39:08 +00:00
PieceRef : deal . PieceRef ,
PieceSize : deal . PieceSize ,
2019-12-07 14:12:10 +00:00
Client : deal . Client ,
Provider : deal . Provider ,
ProposalExpiration : deal . ProposalExpiration ,
Duration : deal . Duration ,
StoragePricePerEpoch : deal . StoragePricePerEpoch ,
StorageCollateral : deal . StorageCollateral ,
ActivationEpoch : 0 ,
} )
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" )
}
2019-10-24 15:12:50 +00:00
aerr = vmctx . Storage ( ) . Commit ( old , nroot )
2019-10-19 04:54:22 +00:00
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-12-07 14:12:10 +00:00
func ( st * StorageMarketState ) validateDeal ( vmctx types . VMContext , deal StorageDealProposal , providerWorker address . Address ) aerrors . ActorError {
2019-12-12 18:25:15 +00:00
ctx , span := trace . StartSpan ( vmctx . Context ( ) , "validateDeal" )
defer span . End ( )
2019-12-07 14:12:10 +00:00
if vmctx . BlockHeight ( ) > deal . ProposalExpiration {
2019-10-19 04:54:22 +00:00
return aerrors . New ( 1 , "deal proposal already expired" )
}
2019-12-07 14:12:10 +00:00
if vmctx . Message ( ) . From != providerWorker {
return aerrors . New ( 2 , "Deals must be submitted by the miner worker" )
2019-10-19 04:54:22 +00:00
}
2020-01-09 22:18:06 +00:00
if err := deal . Verify ( providerWorker ) ; err != nil {
2019-12-07 14:12:10 +00:00
return aerrors . Absorb ( err , 3 , "verifying proposer signature" )
2019-10-19 04:54:22 +00:00
}
// TODO: do some caching (changes gas so needs to be in spec too)
2019-12-12 18:25:15 +00:00
b , bnd , aerr := GetMarketBalances ( ctx , vmctx . Ipld ( ) , st . Balances , deal . 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 ]
2019-12-07 14:12:10 +00:00
totalPrice := deal . TotalStoragePrice ( )
2019-10-29 10:01:18 +00:00
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 )
2019-10-19 04:54:22 +00:00
}
2019-10-29 10:01:18 +00:00
clientBalance = lockFunds ( clientBalance , totalPrice )
2019-10-19 04:54:22 +00:00
// TODO: REVIEW: Not clear who pays for this
2019-12-07 14:12:10 +00:00
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 )
2019-10-19 04:54:22 +00:00
}
2019-12-07 14:12:10 +00:00
providerBalance = lockFunds ( providerBalance , deal . StorageCollateral )
2019-10-19 04:54:22 +00:00
// TODO: piece checks (e.g. size > sectorSize)?
bcid , aerr := setMarketBalances ( vmctx , bnd , map [ address . Address ] StorageParticipantBalance {
2019-12-07 14:12:10 +00:00
deal . Client : clientBalance ,
providerWorker : providerBalance ,
2019-10-19 04:54:22 +00:00
} )
if aerr != nil {
return aerr
}
2019-10-24 15:46:21 +00:00
st . Balances = bcid
2019-10-19 04:54:22 +00:00
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 {
return nil , aerrors . HandleExternalError ( err , "loading deals amt" )
}
for _ , deal := range params . Deals {
var dealInfo OnChainDeal
if err := deals . Get ( deal , & dealInfo ) ; err != nil {
2019-10-24 15:56:32 +00:00
if _ , is := err . ( * amt . ErrNotFound ) ; is {
return nil , aerrors . New ( 3 , "deal not found" )
}
return nil , aerrors . HandleExternalError ( err , "getting deal info failed" )
2019-10-19 10:20:33 +00:00
}
2019-12-07 14:12:10 +00:00
if vmctx . Message ( ) . From != dealInfo . Provider {
2019-10-24 14:24:31 +00:00
return nil , aerrors . New ( 1 , "ActivateStorageDeals can only be called by the deal provider" )
2019-10-19 10:20:33 +00:00
}
2019-12-07 14:12:10 +00:00
if vmctx . BlockHeight ( ) > dealInfo . ProposalExpiration {
2019-10-19 10:20:33 +00:00
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 {
return nil , aerrors . HandleExternalError ( err , "loading deals amt" )
}
2019-10-24 15:12:50 +00:00
// 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" )
}
2019-10-19 10:20:33 +00:00
for _ , deal := range params . DealIDs {
var dealInfo OnChainDeal
if err := deals . Get ( deal , & dealInfo ) ; err != nil {
2019-10-24 15:56:32 +00:00
if _ , is := err . ( * amt . ErrNotFound ) ; is {
return nil , aerrors . New ( 2 , "deal not found" )
}
2019-10-24 15:12:50 +00:00
return nil , aerrors . HandleExternalError ( err , "getting deal info failed" )
2019-10-19 10:20:33 +00:00
}
2019-12-07 14:12:10 +00:00
if dealInfo . Provider != vmctx . Message ( ) . From {
2019-10-24 15:56:32 +00:00
return nil , aerrors . New ( 3 , "ProcessStorageDealsPayment can only be called by deal provider" )
2019-10-19 10:20:33 +00:00
}
2019-10-24 15:12:50 +00:00
if vmctx . BlockHeight ( ) < dealInfo . ActivationEpoch {
// TODO: This is probably fatal
2019-10-24 15:56:32 +00:00
return nil , aerrors . New ( 4 , "ActivationEpoch lower than block height" )
2019-10-19 10:20:33 +00:00
}
2019-12-07 14:12:10 +00:00
if vmctx . BlockHeight ( ) > dealInfo . ActivationEpoch + dealInfo . Duration {
2019-10-24 15:12:50 +00:00
// Deal expired, miner should drop it
// TODO: process payment for the remainder of last proving period
2019-10-19 10:20:33 +00:00
return nil , nil
}
2019-12-07 14:12:10 +00:00
toPay := types . BigMul ( dealInfo . StoragePricePerEpoch , types . NewInt ( build . SlashablePowerDelay ) )
2019-10-19 10:20:33 +00:00
2019-12-07 14:12:10 +00:00
b , bnd , aerr := GetMarketBalances ( vmctx . Context ( ) , vmctx . Ipld ( ) , self . Balances , dealInfo . Client , providerWorker )
2019-10-24 15:12:50 +00:00
if aerr != nil {
return nil , aerr
2019-10-24 14:24:31 +00:00
}
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-12-07 14:12:10 +00:00
dealInfo . 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" )
}
2019-10-24 15:12:50 +00:00
aerr = vmctx . Storage ( ) . Commit ( old , nroot )
2019-10-19 10:20:33 +00:00
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-31 16:55:35 +00:00
type ComputeDataCommitmentParams struct {
2019-10-31 01:22:50 +00:00
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" )
}
2019-12-01 20:07:42 +00:00
if len ( params . DealIDs ) == 0 {
return nil , aerrors . New ( 3 , "no deal IDs" )
}
2019-11-01 03:57:10 +00:00
var pieces [ ] sectorbuilder . PublicPieceInfo
2019-10-31 01:22:50 +00:00
for _ , deal := range params . DealIDs {
var dealInfo OnChainDeal
if err := deals . Get ( deal , & dealInfo ) ; err != nil {
if _ , is := err . ( * amt . ErrNotFound ) ; is {
2019-12-01 20:07:42 +00:00
return nil , aerrors . New ( 4 , "deal not found" )
2019-10-31 01:22:50 +00:00
}
return nil , aerrors . HandleExternalError ( err , "getting deal info failed" )
}
2019-12-07 14:12:10 +00:00
if dealInfo . Provider != vmctx . Message ( ) . From {
2019-12-01 20:07:42 +00:00
return nil , aerrors . New ( 5 , "referenced deal was not from caller" )
2019-11-07 22:55:24 +00:00
}
2019-11-01 03:57:10 +00:00
var commP [ 32 ] byte
2019-12-07 14:12:10 +00:00
copy ( commP [ : ] , dealInfo . PieceRef )
2019-11-01 03:57:10 +00:00
pieces = append ( pieces , sectorbuilder . PublicPieceInfo {
2019-12-07 14:12:10 +00:00
Size : dealInfo . PieceSize ,
2019-11-01 03:57:10 +00:00
CommP : commP ,
} )
2019-10-31 01:22:50 +00:00
}
2019-11-01 03:57:10 +00:00
commd , err := sectorbuilder . GenerateDataCommitment ( params . SectorSize , pieces )
if err != nil {
2019-12-01 20:07:42 +00:00
return nil , aerrors . Absorb ( err , 6 , "failed to generate data commitment from pieces" )
2019-11-01 03:57:10 +00:00
}
2019-10-31 01:22:50 +00:00
2019-11-01 03:57:10 +00:00
return commd [ : ] , nil
2019-10-31 01:22:50 +00:00
}
2019-10-19 04:54:22 +00:00
/ *
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 ) {
}
* /