From ef5b54fe7ff56e400518093076dfe4afb8f479d8 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Mon, 15 Jul 2019 23:07:03 -0700 Subject: [PATCH] implement commit sector and some storage market methods --- chain/actors/actor_miner.go | 152 +++++++++++++++++++++++++++- chain/actors/actor_storagemarket.go | 69 +++++++++++++ 2 files changed, 216 insertions(+), 5 deletions(-) diff --git a/chain/actors/actor_miner.go b/chain/actors/actor_miner.go index 1364628c4..33620441c 100644 --- a/chain/actors/actor_miner.go +++ b/chain/actors/actor_miner.go @@ -1,9 +1,13 @@ package actors import ( + "context" + "github.com/filecoin-project/go-lotus/chain/address" "github.com/filecoin-project/go-lotus/chain/types" + cid "github.com/ipfs/go-cid" + hamt "github.com/ipfs/go-hamt-ipld" cbor "github.com/ipfs/go-ipld-cbor" "github.com/libp2p/go-libp2p-core/peer" ) @@ -11,8 +15,12 @@ import ( func init() { cbor.RegisterCborType(StorageMinerActorState{}) cbor.RegisterCborType(StorageMinerConstructorParams{}) + cbor.RegisterCborType(CommitSectorParams{}) } +var ProvingPeriodDuration = uint64(2 * 60) // an hour, for now +const POST_SECTORS_COUNT = 8192 + type StorageMinerActor struct{} type StorageMinerActorState struct { @@ -33,9 +41,6 @@ type StorageMinerActorState struct { // Amount of space in each sector committed to the network by this miner. SectorSize types.BigInt - // Collateral currently committed to live storage. - ActiveCollateral types.BigInt - // Collateral that is waiting to be withdrawn. DePledgedCollateral types.BigInt @@ -43,11 +48,13 @@ type StorageMinerActorState struct { DePledgeTime types.BigInt // All sectors this miner has committed. - //Sectors SectorSet + Sectors cid.Cid // TODO: Using a HAMT for now, needs to be an AMT once we implement it + SectorSetSize uint64 // TODO: the AMT should be able to tell us how many items are in it. This field won't be needed at that point // Sectors this miner is currently mining. It is only updated // when a PoSt is submitted (not as each new sector commitment is added). - //ProvingSet SectorSet + ProvingSet cid.Cid + ProvingSetSize uint64 // 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 @@ -61,6 +68,8 @@ type StorageMinerActorState struct { // Amount of power this miner has. Power types.BigInt + ProvingPeriodEnd uint64 + // List of sectors that this miner was slashed for. //SlashedSet SectorSet @@ -81,6 +90,7 @@ type StorageMinerConstructorParams struct { func (sma StorageMinerActor) Exports() []interface{} { return []interface{}{ sma.StorageMinerActor, + sma.CommitSector, } } @@ -91,6 +101,14 @@ func (sma StorageMinerActor) StorageMinerActor(act *types.Actor, vmctx types.VMC self.PeerID = params.PeerID self.SectorSize = params.SectorSize + nd := hamt.NewNode(vmctx.Ipld()) + sectors, err := vmctx.Ipld().Put(context.TODO(), nd) + if err != nil { + return types.InvokeRet{}, err + } + self.Sectors = sectors + self.ProvingSet = sectors + storage := vmctx.Storage() c, err := storage.Put(self) if err != nil { @@ -103,3 +121,127 @@ func (sma StorageMinerActor) StorageMinerActor(act *types.Actor, vmctx types.VMC return types.InvokeRet{}, nil } + +type CommitSectorParams struct { + SectorId types.BigInt + CommD []byte + CommR []byte + CommRStar []byte + Proof []byte +} + +func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContext, params *CommitSectorParams) (types.InvokeRet, error) { + var self StorageMinerActorState + oldstate := vmctx.Storage().GetHead() + if err := vmctx.Storage().Get(oldstate, &self); err != nil { + return types.InvokeRet{}, err + } + + if !ValidatePoRep(self.SectorSize, params) { + //Fatal("bad proof!") + return types.InvokeRet{ + ReturnCode: 1, + }, nil + } + + // make sure the miner isnt trying to submit a pre-existing sector + unique, err := SectorIsUnique(vmctx.Ipld(), self.Sectors, params.SectorId) + if err != nil { + return types.InvokeRet{}, err + } + if !unique { + //Fatal("sector already committed!") + return types.InvokeRet{ + ReturnCode: 2, + }, nil + } + + // Power of the miner after adding this sector + futurePower := types.BigAdd(self.Power, self.SectorSize) + collateralRequired := CollateralForPower(futurePower) + + if types.BigCmp(collateralRequired, act.Balance) < 0 { + //Fatal("not enough collateral") + return types.InvokeRet{ + ReturnCode: 3, + }, nil + } + + // ensure that the miner cannot commit more sectors than can be proved with a single PoSt + if self.SectorSetSize >= POST_SECTORS_COUNT { + // Fatal("too many sectors") + return types.InvokeRet{ + ReturnCode: 4, + }, nil + } + + // 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. + nssroot, err := AddToSectorSet(self.Sectors, params.SectorId, params.CommR, params.CommD) + if err != nil { + return types.InvokeRet{}, err + } + 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 + // could simply make the 'CommitSector' call take multiple sectors at a time. + // + // 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. + if self.ProvingSetSize == 0 { + self.ProvingSet = self.Sectors + self.ProvingSetSize = self.SectorSetSize + self.ProvingPeriodEnd = vmctx.BlockHeight() + ProvingPeriodDuration + } + + nstate, err := vmctx.Storage().Put(self) + if err != nil { + return types.InvokeRet{}, err + } + if err := vmctx.Storage().Commit(oldstate, nstate); err != nil { + return types.InvokeRet{}, err + } + + return types.InvokeRet{}, nil +} + +func SectorIsUnique(cst *hamt.CborIpldStore, sroot cid.Cid, sid types.BigInt) (bool, error) { + nd, err := hamt.LoadNode(context.TODO(), cst, sroot) + if err != nil { + return false, err + } + + if _, err := nd.Find(context.TODO(), sid.String()); err != nil { + if err == hamt.ErrNotFound { + return true, nil + } + return false, err + } + + return false, nil +} + +func AddToSectorSet(ss cid.Cid, sectorID types.BigInt, commR, commD []byte) (cid.Cid, error) { + panic("NYI") +} + +func ValidatePoRep(ssize types.BigInt, params *CommitSectorParams) bool { + return true +} + +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 + */ +} diff --git a/chain/actors/actor_storagemarket.go b/chain/actors/actor_storagemarket.go index ce5ab2397..872288465 100644 --- a/chain/actors/actor_storagemarket.go +++ b/chain/actors/actor_storagemarket.go @@ -21,6 +21,8 @@ func (sma StorageMarketActor) Exports() []interface{} { return []interface{}{ nil, sma.CreateStorageMiner, + nil, // TODO: slash consensus fault + sma.UpdateStorage, } } @@ -98,3 +100,70 @@ func SupportedSectorSize(ssize types.BigInt) bool { } return false } + +type UpdateStorageParams struct { + Delta types.BigInt +} + +func (sma StorageMarketActor) UpdateStorage(act *types.Actor, vmctx types.VMContext, params *UpdateStorageParams) (types.InvokeRet, error) { + var self StorageMarketState + if err := vmctx.Storage().Get(vmctx.Storage().GetHead(), &self); err != nil { + return types.InvokeRet{}, err + } + + _, ok := self.Miners[vmctx.Message().From] + if !ok { + //Fatal("update storage must only be called by a miner actor") + return types.InvokeRet{ + ReturnCode: 1, + }, nil + } + + self.TotalStorage = types.BigAdd(self.TotalStorage, params.Delta) + return types.InvokeRet{}, nil +} + +func (sma StorageMarketActor) GetTotalStorage(act *types.Actor, vmctx types.VMContext, params struct{}) (types.InvokeRet, error) { + var self StorageMarketState + if err := vmctx.Storage().Get(vmctx.Storage().GetHead(), &self); err != nil { + return types.InvokeRet{}, err + } + + return types.InvokeRet{ + Result: self.TotalStorage.Bytes(), + }, nil +} + +type PowerLookupParams struct { + Miner address.Address +} + +func (sma StorageMarketActor) PowerLookup(act *types.Actor, vmctx types.VMContext, params *PowerLookupParams) (types.InvokeRet, error) { + var self StorageMarketState + if err := vmctx.Storage().Get(vmctx.Storage().GetHead(), &self); err != nil { + return types.InvokeRet{}, err + } + + if _, ok := self.Miners[params.Miner]; !ok { + //Fatal("miner not registered with storage market") + return types.InvokeRet{ + ReturnCode: 1, + }, nil + } + + ret, code, err := vmctx.Send(params.Miner, 9999, types.NewInt(0), nil) + if err != nil { + return types.InvokeRet{}, err + } + + if code != 0 { + return types.InvokeRet{ + // TODO: error handling... these codes really don't tell us what the problem is very well + ReturnCode: code, + }, nil + } + + return types.InvokeRet{ + Result: ret, + }, nil +}