2019-07-12 23:52:25 +00:00
package actors
2019-07-12 20:56:41 +00:00
import (
2019-11-14 11:56:17 +00:00
"bytes"
2019-07-16 06:07:03 +00:00
"context"
2019-10-24 13:39:13 +00:00
"encoding/binary"
2019-09-19 13:32:00 +00:00
"fmt"
2019-09-10 19:58:45 +00:00
2019-10-18 04:47:41 +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"
"github.com/filecoin-project/lotus/lib/sectorbuilder"
2019-08-29 00:01:46 +00:00
2019-09-06 22:40:24 +00:00
"github.com/filecoin-project/go-amt-ipld"
"github.com/ipfs/go-cid"
2019-07-12 20:56:41 +00:00
cbor "github.com/ipfs/go-ipld-cbor"
"github.com/libp2p/go-libp2p-core/peer"
2019-09-18 15:10:03 +00:00
cbg "github.com/whyrusleeping/cbor-gen"
2019-11-12 19:54:25 +00:00
"go.opencensus.io/trace"
2019-08-15 14:07:45 +00:00
"golang.org/x/xerrors"
2019-07-12 20:56:41 +00:00
)
type StorageMinerActor struct { }
type StorageMinerActorState struct {
2019-10-30 15:55:55 +00:00
// PreCommittedSectors is the set of sectors that have been committed to but not
// yet had their proofs submitted
2019-11-07 12:03:18 +00:00
PreCommittedSectors map [ string ] * PreCommittedSector
2019-07-12 20:56:41 +00:00
// All sectors this miner has committed.
2019-09-19 20:24:01 +00:00
Sectors cid . Cid
2019-07-12 20:56:41 +00:00
2019-10-30 15:55:55 +00:00
// TODO: Spec says 'StagedCommittedSectors', which one is it?
2019-07-12 20:56:41 +00:00
// Sectors this miner is currently mining. It is only updated
// when a PoSt is submitted (not as each new sector commitment is added).
2019-09-19 18:31:25 +00:00
ProvingSet cid . Cid
2019-07-12 20:56:41 +00:00
2019-10-30 15:55:55 +00:00
// TODO: these:
// SectorTable
// SectorExpirationQueue
// ChallengeStatus
// Contains mostly static info about this miner
Info cid . Cid
2019-09-17 14:20:08 +00:00
// Faulty sectors reported since last SubmitPost,
// up to the current proving period's challenge time.
CurrentFaultSet types . BitField
// Faults submitted after the current proving period's challenge time,
// but before the PoSt for that period is submitted.
// These become the currentFaultSet when a PoSt is submitted.
NextFaultSet types . BitField
// Sectors reported during the last PoSt submission as being 'done'.
// The collateral for them is still being held until
// the next PoSt submission in case early sector
2019-07-12 20:56:41 +00:00
// removal penalization is needed.
2019-09-17 14:20:08 +00:00
NextDoneSet types . BitField
2019-07-12 20:56:41 +00:00
// Amount of power this miner has.
Power types . BigInt
2019-11-14 16:14:52 +00:00
// Active is set to true after the miner has submitted their first PoSt
Active bool
2019-07-12 20:56:41 +00:00
// The height at which this miner was slashed at.
2019-11-13 22:40:51 +00:00
SlashedAt uint64
2019-08-06 00:01:49 +00:00
ProvingPeriodEnd uint64
}
type MinerInfo struct {
// Account that owns this miner.
// - Income and returned collateral are paid to this address.
// - This address is also allowed to change the worker address for the miner.
Owner address . Address
// Worker account for this miner.
// This will be the key that is used to sign blocks created by this miner, and
// sign messages sent on behalf of this miner to commit sectors, submit PoSts, and
// other day to day miner activities.
Worker address . Address
// Libp2p identity that should be used when connecting to this miner.
PeerID peer . ID
// Amount of space in each sector committed to the network by this miner.
2019-10-16 07:07:16 +00:00
SectorSize uint64
2019-10-30 15:55:55 +00:00
// SubsectorCount
2019-07-12 20:56:41 +00:00
}
2019-11-07 12:03:18 +00:00
type PreCommittedSector struct {
Info SectorPreCommitInfo
ReceivedEpoch uint64
2019-10-24 13:39:13 +00:00
}
2019-07-12 20:56:41 +00:00
type StorageMinerConstructorParams struct {
2019-07-16 16:40:25 +00:00
Owner address . Address
2019-07-12 20:56:41 +00:00
Worker address . Address
2019-10-16 07:07:16 +00:00
SectorSize uint64
2019-07-12 20:56:41 +00:00
PeerID peer . ID
}
2019-11-07 12:03:18 +00:00
type SectorPreCommitInfo struct {
SectorNumber uint64
CommR [ ] byte // TODO: Spec says CID
SealEpoch uint64
DealIDs [ ] uint64
}
2019-07-26 21:42:38 +00:00
type maMethods struct {
2019-10-21 18:12:11 +00:00
Constructor uint64
2019-10-30 15:55:55 +00:00
PreCommitSector uint64
ProveCommitSector uint64
2019-10-21 18:12:11 +00:00
SubmitPoSt uint64
SlashStorageFault uint64
GetCurrentProvingSet uint64
ArbitrateDeal uint64
DePledge uint64
GetOwner uint64
GetWorkerAddr uint64
GetPower uint64
GetPeerID uint64
GetSectorSize uint64
UpdatePeerID uint64
ChangeWorker uint64
2019-11-14 16:14:52 +00:00
IsSlashed uint64
2019-11-13 23:14:02 +00:00
CheckMiner uint64
2019-10-30 15:55:55 +00:00
DeclareFaults uint64
2019-10-21 18:12:11 +00:00
SlashConsensusFault uint64
}
2019-11-13 23:00:11 +00:00
var MAMethods = maMethods { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 }
2019-07-26 21:42:38 +00:00
2019-07-15 20:27:45 +00:00
func ( sma StorageMinerActor ) Exports ( ) [ ] interface { } {
return [ ] interface { } {
2019-07-26 21:42:38 +00:00
1 : sma . StorageMinerConstructor ,
2019-10-30 15:55:55 +00:00
2 : sma . PreCommitSector ,
3 : sma . ProveCommitSector ,
4 : sma . SubmitPoSt ,
//5: sma.SlashStorageFault,
//6: sma.GetCurrentProvingSet,
//7: sma.ArbitrateDeal,
//8: sma.DePledge,
9 : sma . GetOwner ,
10 : sma . GetWorkerAddr ,
11 : sma . GetPower , // TODO: Remove
12 : sma . GetPeerID ,
13 : sma . GetSectorSize ,
14 : sma . UpdatePeerID ,
//15: sma.ChangeWorker,
2019-11-14 16:14:52 +00:00
16 : sma . IsSlashed ,
2019-11-13 23:00:11 +00:00
17 : sma . CheckMiner ,
18 : sma . DeclareFaults ,
19 : sma . SlashConsensusFault ,
2019-07-15 20:27:45 +00:00
}
}
2019-07-30 22:05:27 +00:00
func loadState ( vmctx types . VMContext ) ( cid . Cid , * StorageMinerActorState , ActorError ) {
var self StorageMinerActorState
oldstate := vmctx . Storage ( ) . GetHead ( )
if err := vmctx . Storage ( ) . Get ( oldstate , & self ) ; err != nil {
return cid . Undef , nil , err
}
return oldstate , & self , nil
}
2019-08-06 00:01:49 +00:00
func loadMinerInfo ( vmctx types . VMContext , m * StorageMinerActorState ) ( * MinerInfo , ActorError ) {
var mi MinerInfo
if err := vmctx . Storage ( ) . Get ( m . Info , & mi ) ; err != nil {
return nil , err
}
return & mi , nil
}
2019-07-23 13:01:52 +00:00
func ( sma StorageMinerActor ) StorageMinerConstructor ( act * types . Actor , vmctx types . VMContext , params * StorageMinerConstructorParams ) ( [ ] byte , ActorError ) {
2019-08-06 00:01:49 +00:00
minerInfo := & MinerInfo {
Owner : params . Owner ,
Worker : params . Worker ,
PeerID : params . PeerID ,
SectorSize : params . SectorSize ,
}
2019-07-12 20:56:41 +00:00
2019-08-06 00:01:49 +00:00
minfocid , err := vmctx . Storage ( ) . Put ( minerInfo )
if err != nil {
return nil , err
}
var self StorageMinerActorState
2019-09-06 22:40:24 +00:00
sectors := amt . NewAMT ( types . WrapStorage ( vmctx . Storage ( ) ) )
scid , serr := sectors . Flush ( )
if serr != nil {
2019-10-15 05:19:37 +00:00
return nil , aerrors . HandleExternalError ( serr , "initializing AMT" )
2019-07-16 06:07:03 +00:00
}
2019-09-06 22:40:24 +00:00
self . Sectors = scid
self . ProvingSet = scid
2019-08-06 04:17:50 +00:00
self . Info = minfocid
2019-07-16 06:07:03 +00:00
2019-07-12 20:56:41 +00:00
storage := vmctx . Storage ( )
2019-09-10 19:58:45 +00:00
c , err := storage . Put ( & self )
2019-07-12 20:56:41 +00:00
if err != nil {
2019-07-23 13:01:52 +00:00
return nil , err
2019-07-12 20:56:41 +00:00
}
2019-07-15 20:27:45 +00:00
if err := storage . Commit ( EmptyCBOR , c ) ; err != nil {
2019-07-23 13:01:52 +00:00
return nil , err
2019-07-12 20:56:41 +00:00
}
2019-07-23 13:01:52 +00:00
return nil , nil
2019-07-12 20:56:41 +00:00
}
2019-07-16 06:07:03 +00:00
2019-10-30 15:55:55 +00:00
func ( sma StorageMinerActor ) PreCommitSector ( act * types . Actor , vmctx types . VMContext , params * SectorPreCommitInfo ) ( [ ] byte , ActorError ) {
2019-10-24 13:39:13 +00:00
ctx := vmctx . Context ( )
2019-07-30 22:05:27 +00:00
oldstate , self , err := loadState ( vmctx )
if err != nil {
2019-07-23 13:01:52 +00:00
return nil , err
2019-07-16 06:07:03 +00:00
}
2019-11-07 12:03:18 +00:00
if params . SealEpoch >= vmctx . BlockHeight ( ) + build . SealRandomnessLookback {
return nil , aerrors . Newf ( 1 , "sector commitment must be based off past randomness (%d >= %d)" , params . SealEpoch , vmctx . BlockHeight ( ) + build . SealRandomnessLookback )
2019-10-31 01:22:50 +00:00
}
2019-11-07 12:03:18 +00:00
if vmctx . BlockHeight ( ) - params . SealEpoch + build . SealRandomnessLookback > build . SealRandomnessLookbackLimit {
return nil , aerrors . Newf ( 2 , "sector commitment must be recent enough (was %d)" , vmctx . BlockHeight ( ) - params . SealEpoch + build . SealRandomnessLookback )
2019-10-31 01:22:50 +00:00
}
2019-08-06 00:01:49 +00:00
mi , err := loadMinerInfo ( vmctx , self )
if err != nil {
return nil , err
}
2019-10-23 03:51:48 +00:00
if vmctx . Message ( ) . From != mi . Worker {
return nil , aerrors . New ( 1 , "not authorized to commit sector for miner" )
}
2019-07-16 06:07:03 +00:00
// make sure the miner isnt trying to submit a pre-existing sector
2019-10-22 17:34:59 +00:00
unique , err := SectorIsUnique ( ctx , vmctx . Storage ( ) , self . Sectors , params . SectorNumber )
2019-07-16 06:07:03 +00:00
if err != nil {
2019-07-23 13:01:52 +00:00
return nil , err
2019-07-16 06:07:03 +00:00
}
if ! unique {
2019-10-23 03:51:48 +00:00
return nil , aerrors . New ( 3 , "sector already committed!" )
2019-07-16 06:07:03 +00:00
}
// Power of the miner after adding this sector
2019-10-16 07:07:16 +00:00
futurePower := types . BigAdd ( self . Power , types . NewInt ( mi . SectorSize ) )
2019-07-16 06:07:03 +00:00
collateralRequired := CollateralForPower ( futurePower )
2019-10-22 17:34:59 +00:00
// TODO: grab from market?
2019-09-23 17:11:44 +00:00
if act . Balance . LessThan ( collateralRequired ) {
2019-10-23 03:51:48 +00:00
return nil , aerrors . New ( 4 , "not enough collateral" )
2019-07-16 06:07:03 +00:00
}
2019-11-07 12:03:18 +00:00
self . PreCommittedSectors [ uintToStringKey ( params . SectorNumber ) ] = & PreCommittedSector {
Info : * params ,
ReceivedEpoch : vmctx . BlockHeight ( ) ,
2019-10-24 13:39:13 +00:00
}
nstate , err := vmctx . Storage ( ) . Put ( self )
if err != nil {
return nil , err
}
if err := vmctx . Storage ( ) . Commit ( oldstate , nstate ) ; err != nil {
return nil , err
}
return nil , nil
}
func uintToStringKey ( i uint64 ) string {
buf := make ( [ ] byte , 10 )
n := binary . PutUvarint ( buf , i )
return string ( buf [ : n ] )
}
2019-10-30 15:55:55 +00:00
type SectorProveCommitInfo struct {
2019-10-24 13:39:13 +00:00
Proof [ ] byte
SectorID uint64
DealIDs [ ] uint64
}
2019-10-30 15:55:55 +00:00
func ( sma StorageMinerActor ) ProveCommitSector ( act * types . Actor , vmctx types . VMContext , params * SectorProveCommitInfo ) ( [ ] byte , ActorError ) {
2019-10-24 13:39:13 +00:00
ctx := vmctx . Context ( )
oldstate , self , err := loadState ( vmctx )
if err != nil {
return nil , err
}
mi , err := loadMinerInfo ( vmctx , self )
if err != nil {
return nil , err
}
2019-10-30 15:55:55 +00:00
us , ok := self . PreCommittedSectors [ uintToStringKey ( params . SectorID ) ]
2019-10-24 13:39:13 +00:00
if ! ok {
return nil , aerrors . New ( 1 , "no pre-commitment found for sector" )
}
2019-11-01 20:27:59 +00:00
2019-11-07 22:55:24 +00:00
if us . ReceivedEpoch + build . InteractivePoRepDelay >= vmctx . BlockHeight ( ) {
2019-11-01 20:27:59 +00:00
return nil , aerrors . New ( 2 , "too early for proof submission" )
}
2019-10-30 15:55:55 +00:00
delete ( self . PreCommittedSectors , uintToStringKey ( params . SectorID ) )
2019-10-24 13:39:13 +00:00
// TODO: ensure normalization to ID address
maddr := vmctx . Message ( ) . To
2019-11-07 12:03:18 +00:00
ticket , err := vmctx . GetRandomness ( us . Info . SealEpoch - build . SealRandomnessLookback )
2019-10-31 01:22:50 +00:00
if err != nil {
return nil , aerrors . Wrap ( err , "failed to get ticket randomness" )
}
2019-11-07 12:03:18 +00:00
seed , err := vmctx . GetRandomness ( us . ReceivedEpoch + build . InteractivePoRepDelay )
2019-10-31 01:22:50 +00:00
if err != nil {
return nil , aerrors . Wrap ( err , "failed to get randomness for prove sector commitment" )
}
2019-10-31 16:55:35 +00:00
enc , err := SerializeParams ( & ComputeDataCommitmentParams {
DealIDs : params . DealIDs ,
SectorSize : mi . SectorSize ,
} )
if err != nil {
return nil , aerrors . Wrap ( err , "failed to serialize ComputeDataCommitmentParams" )
}
commD , err := vmctx . Send ( StorageMarketAddress , SMAMethods . ComputeDataCommitment , types . NewInt ( 0 ) , enc )
if err != nil {
return nil , aerrors . Wrap ( err , "failed to compute data commitment" )
}
2019-11-12 19:54:25 +00:00
if ok , err := ValidatePoRep ( ctx , maddr , mi . SectorSize , commD , us . Info . CommR , ticket , params . Proof , seed , params . SectorID ) ; err != nil {
2019-10-24 13:39:13 +00:00
return nil , err
} else if ! ok {
2019-11-07 22:55:24 +00:00
return nil , aerrors . Newf ( 2 , "porep proof was invalid (t:%x; s:%x(%d); p:%x)" , ticket , seed , us . ReceivedEpoch + build . InteractivePoRepDelay , params . Proof )
2019-10-24 13:39:13 +00:00
}
2019-07-16 06:07:03 +00:00
// Note: There must exist a unique index in the miner's sector set for each
// sector ID. The `faults`, `recovered`, and `done` parameters of the
// SubmitPoSt method express indices into this sector set.
2019-11-07 12:03:18 +00:00
nssroot , err := AddToSectorSet ( ctx , vmctx . Storage ( ) , self . Sectors , params . SectorID , us . Info . CommR , commD )
2019-07-16 06:07:03 +00:00
if err != nil {
2019-07-23 13:01:52 +00:00
return nil , err
2019-07-16 06:07:03 +00:00
}
self . Sectors = nssroot
// if miner is not mining, start their proving period now
// Note: As written here, every miners first PoSt will only be over one sector.
// We could set up a 'grace period' for starting mining that would allow miners
// to submit several sectors for their first proving period. Alternatively, we
2019-10-30 15:55:55 +00:00
// could simply make the 'PreCommitSector' call take multiple sectors at a time.
2019-07-16 06:07:03 +00:00
//
// Note: Proving period is a function of sector size; small sectors take less
// time to prove than large sectors do. Sector size is selected when pledging.
2019-09-19 18:31:25 +00:00
pss , lerr := amt . LoadAMT ( types . WrapStorage ( vmctx . Storage ( ) ) , self . ProvingSet )
if lerr != nil {
2019-10-15 05:19:37 +00:00
return nil , aerrors . HandleExternalError ( lerr , "could not load proving set node" )
2019-09-19 18:31:25 +00:00
}
if pss . Count == 0 {
2019-07-16 06:07:03 +00:00
self . ProvingSet = self . Sectors
2019-09-19 13:32:00 +00:00
self . ProvingPeriodEnd = vmctx . BlockHeight ( ) + build . ProvingPeriodDuration
2019-07-16 06:07:03 +00:00
}
nstate , err := vmctx . Storage ( ) . Put ( self )
if err != nil {
2019-07-23 13:01:52 +00:00
return nil , err
2019-07-16 06:07:03 +00:00
}
if err := vmctx . Storage ( ) . Commit ( oldstate , nstate ) ; err != nil {
2019-07-23 13:01:52 +00:00
return nil , err
2019-07-16 06:07:03 +00:00
}
2019-10-22 17:34:59 +00:00
activateParams , err := SerializeParams ( & ActivateStorageDealsParams {
Deals : params . DealIDs ,
} )
if err != nil {
return nil , err
}
_ , err = vmctx . Send ( StorageMarketAddress , SMAMethods . ActivateStorageDeals , types . NewInt ( 0 ) , activateParams )
return nil , err
2019-07-16 06:07:03 +00:00
}
2019-08-06 00:01:49 +00:00
type SubmitPoStParams struct {
2019-09-18 15:10:03 +00:00
Proof [ ] byte
DoneSet types . BitField
2019-08-06 00:01:49 +00:00
// TODO: once the spec changes finish, we have more work to do here...
}
2019-09-27 19:47:47 +00:00
func ProvingPeriodEnd ( setPeriodEnd , height uint64 ) ( uint64 , uint64 ) {
offset := setPeriodEnd % build . ProvingPeriodDuration
period := ( ( height - offset - 1 ) / build . ProvingPeriodDuration ) + 1
end := ( period * build . ProvingPeriodDuration ) + offset
return end , period
}
2019-08-06 04:17:50 +00:00
// TODO: this is a dummy method that allows us to plumb in other parts of the
// system for now.
2019-09-19 20:24:01 +00:00
func ( sma StorageMinerActor ) SubmitPoSt ( act * types . Actor , vmctx types . VMContext , params * SubmitPoStParams ) ( [ ] byte , ActorError ) {
2019-08-06 00:01:49 +00:00
oldstate , self , err := loadState ( vmctx )
if err != nil {
return nil , err
}
mi , err := loadMinerInfo ( vmctx , self )
if err != nil {
return nil , err
}
if vmctx . Message ( ) . From != mi . Worker {
return nil , aerrors . New ( 1 , "not authorized to submit post for miner" )
}
2019-09-27 19:47:47 +00:00
currentProvingPeriodEnd , _ := ProvingPeriodEnd ( self . ProvingPeriodEnd , vmctx . BlockHeight ( ) )
2019-09-26 19:23:11 +00:00
2019-09-18 15:10:03 +00:00
feesRequired := types . NewInt ( 0 )
2019-08-06 00:01:49 +00:00
2019-09-26 19:23:11 +00:00
if currentProvingPeriodEnd > self . ProvingPeriodEnd {
2019-09-18 15:10:03 +00:00
//TODO late fee calc
feesRequired = types . BigAdd ( feesRequired , types . NewInt ( 1000 ) )
}
//TODO temporary sector failure fees
msgVal := vmctx . Message ( ) . Value
2019-09-23 17:11:44 +00:00
if msgVal . LessThan ( feesRequired ) {
2019-09-18 15:10:03 +00:00
return nil , aerrors . New ( 2 , "not enough funds to pay post submission fees" )
}
2019-09-23 17:11:44 +00:00
if msgVal . GreaterThan ( feesRequired ) {
2019-09-18 15:10:03 +00:00
_ , err := vmctx . Send ( vmctx . Message ( ) . From , 0 ,
types . BigSub ( msgVal , feesRequired ) , nil )
if err != nil {
return nil , aerrors . Wrap ( err , "could not refund excess fees" )
}
}
var seed [ sectorbuilder . CommLen ] byte
2019-09-19 13:32:00 +00:00
{
2019-10-28 08:15:08 +00:00
randHeight := currentProvingPeriodEnd - build . PoStChallangeTime - build . PoStRandomnessLookback
2019-09-26 19:23:11 +00:00
if vmctx . BlockHeight ( ) <= randHeight {
// TODO: spec, retcode
2019-10-04 18:30:30 +00:00
return nil , aerrors . Newf ( 1 , "submit PoSt called outside submission window (%d < %d)" , vmctx . BlockHeight ( ) , randHeight )
2019-09-19 13:32:00 +00:00
}
2019-09-26 19:23:11 +00:00
rand , err := vmctx . GetRandomness ( randHeight )
2019-09-19 13:32:00 +00:00
if err != nil {
return nil , aerrors . Wrap ( err , "could not get randomness for PoST" )
}
if len ( rand ) < len ( seed ) {
return nil , aerrors . Escalate ( fmt . Errorf ( "randomness too small (%d < %d)" ,
len ( rand ) , len ( seed ) ) , "improper randomness" )
}
copy ( seed [ : ] , rand )
2019-09-18 15:10:03 +00:00
}
pss , lerr := amt . LoadAMT ( types . WrapStorage ( vmctx . Storage ( ) ) , self . ProvingSet )
if lerr != nil {
2019-10-15 05:19:37 +00:00
return nil , aerrors . HandleExternalError ( lerr , "could not load proving set node" )
2019-09-18 15:10:03 +00:00
}
var sectorInfos [ ] sectorbuilder . SectorInfo
if err := pss . ForEach ( func ( id uint64 , v * cbg . Deferred ) error {
var comms [ ] [ ] byte
if err := cbor . DecodeInto ( v . Raw , & comms ) ; err != nil {
return xerrors . New ( "could not decode comms" )
}
si := sectorbuilder . SectorInfo {
SectorID : id ,
}
commR := comms [ 0 ]
if len ( commR ) != len ( si . CommR ) {
return xerrors . Errorf ( "commR length is wrong: %d" , len ( commR ) )
}
copy ( si . CommR [ : ] , commR )
sectorInfos = append ( sectorInfos , si )
return nil
} ) ; err != nil {
return nil , aerrors . Absorb ( err , 3 , "could not decode sectorset" )
}
faults := self . CurrentFaultSet . All ( )
2019-11-12 19:54:25 +00:00
if ok , lerr := sectorbuilder . VerifyPost ( vmctx . Context ( ) , mi . SectorSize ,
2019-09-18 15:10:03 +00:00
sectorbuilder . NewSortedSectorInfo ( sectorInfos ) , seed , params . Proof ,
faults ) ; ! ok || lerr != nil {
if lerr != nil {
2019-09-19 13:57:48 +00:00
// TODO: study PoST errors
2019-09-18 15:10:03 +00:00
return nil , aerrors . Absorb ( lerr , 4 , "PoST error" )
}
2019-09-19 13:57:48 +00:00
if ! ok {
return nil , aerrors . New ( 4 , "PoST invalid" )
}
2019-09-18 15:10:03 +00:00
}
self . CurrentFaultSet = self . NextFaultSet
self . NextFaultSet = types . NewBitField ( )
ss , lerr := amt . LoadAMT ( types . WrapStorage ( vmctx . Storage ( ) ) , self . ProvingSet )
if lerr != nil {
2019-10-15 05:19:37 +00:00
return nil , aerrors . HandleExternalError ( lerr , "could not load proving set node" )
2019-09-18 15:10:03 +00:00
}
2019-09-19 04:56:40 +00:00
if err := ss . BatchDelete ( params . DoneSet . All ( ) ) ; err != nil {
// TODO: this could fail for system reasons (block not found) or for
// bad user input reasons (e.g. bad doneset). The latter should be a
// non-fatal error
2019-10-15 05:19:37 +00:00
return nil , aerrors . HandleExternalError ( err , "failed to delete sectors in done set" )
2019-09-19 04:56:40 +00:00
}
2019-09-18 15:10:03 +00:00
self . ProvingSet , lerr = ss . Flush ( )
if lerr != nil {
2019-10-15 05:19:37 +00:00
return nil , aerrors . HandleExternalError ( lerr , "could not flush AMT" )
2019-09-18 15:10:03 +00:00
}
2019-08-06 00:01:49 +00:00
oldPower := self . Power
2019-09-19 18:31:25 +00:00
self . Power = types . BigMul ( types . NewInt ( pss . Count - uint64 ( len ( faults ) ) ) ,
2019-10-16 07:07:16 +00:00
types . NewInt ( mi . SectorSize ) )
2019-08-06 00:01:49 +00:00
2019-11-13 22:40:51 +00:00
delta := types . BigSub ( self . Power , oldPower )
if self . SlashedAt != 0 {
self . SlashedAt = 0
delta = self . Power
}
2019-11-14 16:14:52 +00:00
prevPE := self . ProvingPeriodEnd
if ! self . Active {
self . Active = true
prevPE = 0
}
2019-11-13 21:16:17 +00:00
enc , err := SerializeParams ( & UpdateStorageParams {
2019-11-13 22:40:51 +00:00
Delta : delta ,
2019-11-13 21:16:17 +00:00
NextProvingPeriodEnd : currentProvingPeriodEnd + build . ProvingPeriodDuration ,
2019-11-14 16:14:52 +00:00
PreviousProvingPeriodEnd : prevPE ,
2019-11-13 21:16:17 +00:00
} )
2019-08-06 04:17:50 +00:00
if err != nil {
return nil , err
}
2019-10-19 08:06:41 +00:00
_ , err = vmctx . Send ( StoragePowerAddress , SPAMethods . UpdateStorage , types . NewInt ( 0 ) , enc )
2019-08-06 04:17:50 +00:00
if err != nil {
return nil , err
}
2019-09-18 15:10:03 +00:00
self . ProvingSet = self . Sectors
2019-09-26 19:23:11 +00:00
self . ProvingPeriodEnd = currentProvingPeriodEnd + build . ProvingPeriodDuration
2019-09-18 15:10:03 +00:00
self . NextDoneSet = params . DoneSet
2019-08-06 04:17:50 +00:00
c , err := vmctx . Storage ( ) . Put ( self )
if err != nil {
return nil , err
}
if err := vmctx . Storage ( ) . Commit ( oldstate , c ) ; err != nil {
return nil , err
}
return nil , nil
2019-08-06 00:01:49 +00:00
}
2019-07-23 13:01:52 +00:00
func ( sma StorageMinerActor ) GetPower ( act * types . Actor , vmctx types . VMContext , params * struct { } ) ( [ ] byte , ActorError ) {
2019-07-30 22:05:27 +00:00
_ , self , err := loadState ( vmctx )
if err != nil {
2019-07-23 13:01:52 +00:00
return nil , err
2019-07-17 13:48:20 +00:00
}
2019-07-23 13:01:52 +00:00
return self . Power . Bytes ( ) , nil
2019-07-17 13:48:20 +00:00
}
2019-08-29 00:01:46 +00:00
func SectorIsUnique ( ctx context . Context , s types . Storage , sroot cid . Cid , sid uint64 ) ( bool , ActorError ) {
found , _ , _ , err := GetFromSectorSet ( ctx , s , sroot , sid )
2019-07-16 06:07:03 +00:00
if err != nil {
2019-08-29 00:01:46 +00:00
return false , err
2019-07-16 06:07:03 +00:00
}
2019-08-29 00:01:46 +00:00
return ! found , nil
2019-07-16 06:07:03 +00:00
}
2019-08-29 00:01:46 +00:00
func AddToSectorSet ( ctx context . Context , s types . Storage , ss cid . Cid , sectorID uint64 , commR , commD [ ] byte ) ( cid . Cid , ActorError ) {
ssr , err := amt . LoadAMT ( types . WrapStorage ( s ) , ss )
2019-08-07 06:35:57 +00:00
if err != nil {
2019-10-15 05:19:37 +00:00
return cid . Undef , aerrors . HandleExternalError ( err , "could not load sector set node" )
2019-08-07 06:35:57 +00:00
}
2019-11-07 12:03:18 +00:00
// TODO: Spec says to use SealCommitment, and construct commD from deals each time,
// but that would make SubmitPoSt way, way more expensive
2019-08-29 00:01:46 +00:00
if err := ssr . Set ( sectorID , [ ] [ ] byte { commR , commD } ) ; err != nil {
2019-10-15 05:19:37 +00:00
return cid . Undef , aerrors . HandleExternalError ( err , "failed to set commitment in sector set" )
2019-08-07 06:35:57 +00:00
}
2019-08-29 00:01:46 +00:00
ncid , err := ssr . Flush ( )
2019-08-07 06:35:57 +00:00
if err != nil {
2019-10-15 05:19:37 +00:00
return cid . Undef , aerrors . HandleExternalError ( err , "failed to flush sector set" )
2019-08-07 06:35:57 +00:00
}
2019-08-29 00:01:46 +00:00
return ncid , nil
2019-07-16 06:07:03 +00:00
}
2019-08-29 00:01:46 +00:00
func GetFromSectorSet ( ctx context . Context , s types . Storage , ss cid . Cid , sectorID uint64 ) ( bool , [ ] byte , [ ] byte , ActorError ) {
ssr , err := amt . LoadAMT ( types . WrapStorage ( s ) , ss )
2019-08-15 13:52:14 +00:00
if err != nil {
2019-10-15 05:19:37 +00:00
return false , nil , nil , aerrors . HandleExternalError ( err , "could not load sector set node" )
2019-08-15 13:52:14 +00:00
}
2019-08-29 00:01:46 +00:00
var comms [ ] [ ] byte
err = ssr . Get ( sectorID , & comms )
2019-08-15 13:52:14 +00:00
if err != nil {
2019-09-09 11:22:09 +00:00
if _ , ok := err . ( * amt . ErrNotFound ) ; ok {
2019-08-29 00:01:46 +00:00
return false , nil , nil , nil
}
2019-10-15 05:19:37 +00:00
return false , nil , nil , aerrors . HandleExternalError ( err , "failed to find sector in sector set" )
2019-08-15 13:52:14 +00:00
}
if len ( comms ) != 2 {
2019-10-15 05:19:37 +00:00
return false , nil , nil , aerrors . Newf ( 20 , "sector set entry should only have 2 elements" )
2019-08-15 13:52:14 +00:00
}
return true , comms [ 0 ] , comms [ 1 ] , nil
}
2019-11-12 19:54:25 +00:00
func ValidatePoRep ( ctx context . Context , maddr address . Address , ssize uint64 , commD , commR , ticket , proof , seed [ ] byte , sectorID uint64 ) ( bool , ActorError ) {
_ , span := trace . StartSpan ( ctx , "ValidatePoRep" )
defer span . End ( )
2019-10-31 16:55:35 +00:00
ok , err := sectorbuilder . VerifySeal ( ssize , commR , commD , maddr , ticket , seed , sectorID , proof )
2019-08-07 06:35:57 +00:00
if err != nil {
2019-10-15 05:19:37 +00:00
return false , aerrors . Absorb ( err , 25 , "verify seal failed" )
2019-08-07 06:35:57 +00:00
}
return ok , nil
2019-07-16 06:07:03 +00:00
}
func CollateralForPower ( power types . BigInt ) types . BigInt {
return types . BigMul ( power , types . NewInt ( 10 ) )
/ * TODO : this
availableFil = FakeGlobalMethods . GetAvailableFil ( )
totalNetworkPower = StorageMinerActor . GetTotalStorage ( )
numMiners = StorageMarket . GetMinerCount ( )
powerCollateral = availableFil * NetworkConstants . POWER_COLLATERAL_PROPORTION * power / totalNetworkPower
perCapitaCollateral = availableFil * NetworkConstants . PER_CAPITA_COLLATERAL_PROPORTION / numMiners
collateralRequired = math . Ceil ( minerPowerCollateral + minerPerCapitaCollateral )
return collateralRequired
* /
}
2019-07-30 00:46:56 +00:00
func ( sma StorageMinerActor ) GetWorkerAddr ( act * types . Actor , vmctx types . VMContext , params * struct { } ) ( [ ] byte , ActorError ) {
2019-07-30 22:05:27 +00:00
_ , self , err := loadState ( vmctx )
if err != nil {
2019-07-30 00:46:56 +00:00
return nil , err
}
2019-08-06 04:17:50 +00:00
mi , err := loadMinerInfo ( vmctx , self )
if err != nil {
return nil , err
}
return mi . Worker . Bytes ( ) , nil
2019-07-30 00:46:56 +00:00
}
2019-07-30 22:05:27 +00:00
func ( sma StorageMinerActor ) GetOwner ( act * types . Actor , vmctx types . VMContext , params * struct { } ) ( [ ] byte , ActorError ) {
_ , self , err := loadState ( vmctx )
if err != nil {
return nil , err
}
2019-08-06 04:17:50 +00:00
mi , err := loadMinerInfo ( vmctx , self )
if err != nil {
return nil , err
}
return mi . Owner . Bytes ( ) , nil
2019-07-30 22:05:27 +00:00
}
func ( sma StorageMinerActor ) GetPeerID ( act * types . Actor , vmctx types . VMContext , params * struct { } ) ( [ ] byte , ActorError ) {
_ , self , err := loadState ( vmctx )
if err != nil {
return nil , err
}
2019-08-06 04:17:50 +00:00
mi , err := loadMinerInfo ( vmctx , self )
if err != nil {
return nil , err
}
return [ ] byte ( mi . PeerID ) , nil
2019-07-30 22:05:27 +00:00
}
type UpdatePeerIDParams struct {
PeerID peer . ID
}
func ( sma StorageMinerActor ) UpdatePeerID ( act * types . Actor , vmctx types . VMContext , params * UpdatePeerIDParams ) ( [ ] byte , ActorError ) {
oldstate , self , err := loadState ( vmctx )
if err != nil {
return nil , err
}
2019-08-06 04:17:50 +00:00
mi , err := loadMinerInfo ( vmctx , self )
if err != nil {
return nil , err
}
if vmctx . Message ( ) . From != mi . Worker {
2019-07-30 22:05:27 +00:00
return nil , aerrors . New ( 2 , "only the mine worker may update the peer ID" )
}
2019-08-06 04:17:50 +00:00
mi . PeerID = params . PeerID
mic , err := vmctx . Storage ( ) . Put ( mi )
if err != nil {
return nil , err
}
self . Info = mic
2019-07-30 22:05:27 +00:00
c , err := vmctx . Storage ( ) . Put ( self )
if err != nil {
return nil , err
}
if err := vmctx . Storage ( ) . Commit ( oldstate , c ) ; err != nil {
return nil , err
}
return nil , nil
}
func ( sma StorageMinerActor ) GetSectorSize ( act * types . Actor , vmctx types . VMContext , params * struct { } ) ( [ ] byte , ActorError ) {
_ , self , err := loadState ( vmctx )
if err != nil {
return nil , err
}
2019-08-06 04:17:50 +00:00
mi , err := loadMinerInfo ( vmctx , self )
if err != nil {
return nil , err
}
2019-10-16 07:07:16 +00:00
return types . NewInt ( mi . SectorSize ) . Bytes ( ) , nil
2019-07-30 22:05:27 +00:00
}
2019-08-15 13:52:14 +00:00
2019-11-13 23:00:11 +00:00
func isLate ( height uint64 , self * StorageMinerActorState ) bool {
2019-11-14 16:14:52 +00:00
return self . ProvingPeriodEnd > 0 && height >= self . ProvingPeriodEnd // TODO: review: maybe > ?
2019-11-13 23:00:11 +00:00
}
2019-11-14 16:14:52 +00:00
func ( sma StorageMinerActor ) IsSlashed ( act * types . Actor , vmctx types . VMContext , params * struct { } ) ( [ ] byte , ActorError ) {
2019-11-13 23:00:11 +00:00
_ , self , err := loadState ( vmctx )
if err != nil {
return nil , err
}
2019-11-14 16:14:52 +00:00
return cbg . EncodeBool ( self . SlashedAt != 0 ) , nil
2019-11-13 23:00:11 +00:00
}
2019-11-14 11:56:17 +00:00
type CheckMinerParams struct {
NetworkPower types . BigInt
}
2019-11-13 22:40:51 +00:00
// TODO: better name
2019-11-14 11:56:17 +00:00
func ( sma StorageMinerActor ) CheckMiner ( act * types . Actor , vmctx types . VMContext , params * CheckMinerParams ) ( [ ] byte , ActorError ) {
2019-11-13 22:40:51 +00:00
if vmctx . Message ( ) . From != StoragePowerAddress {
return nil , aerrors . New ( 2 , "only the storage power actor can check miner" )
}
oldstate , self , err := loadState ( vmctx )
if err != nil {
return nil , err
}
2019-11-13 23:00:11 +00:00
if ! isLate ( vmctx . BlockHeight ( ) , self ) {
2019-11-13 22:40:51 +00:00
// Everything's fine
2019-11-14 11:56:17 +00:00
return nil , nil
2019-11-13 22:40:51 +00:00
}
if self . SlashedAt != 0 {
// Don't slash more than necessary
return nil , nil
}
2019-11-14 11:56:17 +00:00
if params . NetworkPower . Equals ( self . Power ) {
// Don't break the network when there's only one miner left
log . Warnf ( "can't slash miner %s for missed PoSt, no power would be left in the network" , vmctx . Message ( ) . To )
return nil , nil
}
2019-11-13 22:40:51 +00:00
// Slash for being late
self . SlashedAt = vmctx . BlockHeight ( )
nstate , err := vmctx . Storage ( ) . Put ( self )
if err != nil {
return nil , err
}
if err := vmctx . Storage ( ) . Commit ( oldstate , nstate ) ; err != nil {
return nil , err
}
2019-11-14 11:56:17 +00:00
var out bytes . Buffer
if err := self . Power . MarshalCBOR ( & out ) ; err != nil {
return nil , aerrors . HandleExternalError ( err , "marshaling return value" )
}
return out . Bytes ( ) , nil
2019-08-15 20:57:14 +00:00
}
2019-10-30 15:55:55 +00:00
type DeclareFaultsParams struct {
2019-09-23 18:41:53 +00:00
Faults types . BitField
}
2019-10-30 15:55:55 +00:00
func ( sma StorageMinerActor ) DeclareFaults ( act * types . Actor , vmctx types . VMContext , params * DeclareFaultsParams ) ( [ ] byte , ActorError ) {
2019-09-23 18:41:53 +00:00
oldstate , self , aerr := loadState ( vmctx )
if aerr != nil {
return nil , aerr
}
2019-10-28 08:15:08 +00:00
challengeHeight := self . ProvingPeriodEnd - build . PoStChallangeTime
2019-09-23 18:41:53 +00:00
if vmctx . BlockHeight ( ) < challengeHeight {
// TODO: optimized bitfield methods
for _ , v := range params . Faults . All ( ) {
self . CurrentFaultSet . Set ( v )
}
} else {
for _ , v := range params . Faults . All ( ) {
self . NextFaultSet . Set ( v )
}
}
nstate , err := vmctx . Storage ( ) . Put ( self )
if err != nil {
return nil , err
}
if err := vmctx . Storage ( ) . Commit ( oldstate , nstate ) ; err != nil {
return nil , err
}
return nil , nil
}
2019-09-12 23:48:03 +00:00
type MinerSlashConsensusFault struct {
Slasher address . Address
AtHeight uint64
SlashedCollateral types . BigInt
}
func ( sma StorageMinerActor ) SlashConsensusFault ( act * types . Actor , vmctx types . VMContext , params * MinerSlashConsensusFault ) ( [ ] byte , ActorError ) {
2019-10-19 08:06:41 +00:00
if vmctx . Message ( ) . From != StoragePowerAddress {
2019-09-12 23:48:03 +00:00
return nil , aerrors . New ( 1 , "SlashConsensusFault may only be called by the storage market actor" )
}
slashedCollateral := params . SlashedCollateral
2019-09-23 17:11:44 +00:00
if slashedCollateral . LessThan ( act . Balance ) {
2019-09-12 23:48:03 +00:00
slashedCollateral = act . Balance
}
// Some of the slashed collateral should be paid to the slasher
// GROWTH_RATE determines how fast the slasher share of slashed collateral will increase as block elapses
// current GROWTH_RATE results in SLASHER_SHARE reaches 1 after 30 blocks
// TODO: define arithmetic precision and rounding for this operation
blockElapsed := vmctx . BlockHeight ( ) - params . AtHeight
2019-09-13 00:12:45 +00:00
slasherShare := slasherShare ( params . SlashedCollateral , blockElapsed )
2019-09-12 23:48:03 +00:00
burnPortion := types . BigSub ( slashedCollateral , slasherShare )
_ , err := vmctx . Send ( vmctx . Message ( ) . From , 0 , slasherShare , nil )
if err != nil {
return nil , aerrors . Wrap ( err , "failed to pay slasher" )
}
_ , err = vmctx . Send ( BurntFundsAddress , 0 , burnPortion , nil )
if err != nil {
return nil , aerrors . Wrap ( err , "failed to burn funds" )
}
// TODO: this still allows the miner to commit sectors and submit posts,
// their users could potentially be unaffected, but the miner will never be
// able to mine a block again
// One potential issue: the miner will have to pay back the slashed
// collateral to continue submitting PoSts, which includes pledge
// collateral that they no longer really 'need'
return nil , nil
}
2019-09-13 00:12:45 +00:00
func slasherShare ( total types . BigInt , elapsed uint64 ) types . BigInt {
// [int(pow(1.26, n) * 10) for n in range(30)]
fracs := [ ] uint64 { 10 , 12 , 15 , 20 , 25 , 31 , 40 , 50 , 63 , 80 , 100 , 127 , 160 , 201 , 254 , 320 , 403 , 508 , 640 , 807 , 1017 , 1281 , 1614 , 2034 , 2563 , 3230 , 4070 , 5128 , 6462 , 8142 }
const precision = 10000
var frac uint64
if elapsed >= uint64 ( len ( fracs ) ) {
2019-09-20 14:21:00 +00:00
return total
2019-09-13 00:12:45 +00:00
} else {
frac = fracs [ elapsed ]
}
return types . BigDiv (
types . BigMul (
types . NewInt ( frac ) ,
total ,
) ,
types . NewInt ( precision ) ,
)
}