From e094ace303c59c8df0f3b88fd0e0cabcabd18746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Wed, 13 Nov 2019 23:40:51 +0100 Subject: [PATCH] actors: CheckMiner methods on Miner/Power actors --- chain/actors/actor_miner.go | 65 +++++++++++++----- chain/actors/actor_storagepower.go | 75 ++++++++++++++++++--- chain/actors/cbor_gen.go | 103 ----------------------------- 3 files changed, 114 insertions(+), 129 deletions(-) diff --git a/chain/actors/actor_miner.go b/chain/actors/actor_miner.go index e8fa2c38f..367cb753e 100644 --- a/chain/actors/actor_miner.go +++ b/chain/actors/actor_miner.go @@ -62,14 +62,8 @@ type StorageMinerActorState struct { // Amount of power this miner has. Power types.BigInt - // List of sectors that this miner was slashed for. - //SlashedSet SectorSet - // The height at which this miner was slashed at. - SlashedAt types.BigInt - - // The amount of storage collateral that is owed to clients, and cannot be used for collateral anymore. - OwedStorageCollateral types.BigInt + SlashedAt uint64 ProvingPeriodEnd uint64 } @@ -131,13 +125,12 @@ type maMethods struct { GetSectorSize uint64 UpdatePeerID uint64 ChangeWorker uint64 - IsSlashed uint64 - IsLate uint64 + CheckMiner uint64 DeclareFaults uint64 SlashConsensusFault uint64 } -var MAMethods = maMethods{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19} +var MAMethods = maMethods{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} func (sma StorageMinerActor) Exports() []interface{} { return []interface{}{ @@ -156,10 +149,9 @@ func (sma StorageMinerActor) Exports() []interface{} { 13: sma.GetSectorSize, 14: sma.UpdatePeerID, //15: sma.ChangeWorker, - //16: sma.IsSlashed, - //17: sma.IsLate, - 18: sma.DeclareFaults, - 19: sma.SlashConsensusFault, + 16: sma.CheckMiner, + 17: sma.DeclareFaults, + 18: sma.SlashConsensusFault, } } @@ -529,8 +521,14 @@ func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext, self.Power = types.BigMul(types.NewInt(pss.Count-uint64(len(faults))), types.NewInt(mi.SectorSize)) + delta := types.BigSub(self.Power, oldPower) + if self.SlashedAt != 0 { + self.SlashedAt = 0 + delta = self.Power + } + enc, err := SerializeParams(&UpdateStorageParams{ - Delta: types.BigSub(self.Power, oldPower), + Delta: delta, NextProvingPeriodEnd: currentProvingPeriodEnd + build.ProvingPeriodDuration, PreviousProvingPeriodEnd: currentProvingPeriodEnd, }) @@ -738,9 +736,40 @@ func (sma StorageMinerActor) GetSectorSize(act *types.Actor, vmctx types.VMConte return types.NewInt(mi.SectorSize).Bytes(), nil } -type PaymentVerifyParams struct { - Extra []byte - Proof []byte +// TODO: better name +func (sma StorageMinerActor) CheckMiner(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) { + 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 + } + + if vmctx.BlockHeight() < self.ProvingPeriodEnd { + // Everything's fine + return cbg.EncodeBool(true), nil + } + + if self.SlashedAt != 0 { + // Don't slash more than necessary + return nil, nil + } + + // 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 + } + + return self.Power.Bytes(), nil } type DeclareFaultsParams struct { diff --git a/chain/actors/actor_storagepower.go b/chain/actors/actor_storagepower.go index 13551f695..e97c769b8 100644 --- a/chain/actors/actor_storagepower.go +++ b/chain/actors/actor_storagepower.go @@ -27,9 +27,10 @@ type spaMethods struct { PowerLookup uint64 IsMiner uint64 PledgeCollateralForSize uint64 + CheckProofSubmissions uint64 } -var SPAMethods = spaMethods{1, 2, 3, 4, 5, 6, 7, 8} +var SPAMethods = spaMethods{1, 2, 3, 4, 5, 6, 7, 8, 9} func (spa StoragePowerActor) Exports() []interface{} { return []interface{}{ @@ -41,6 +42,7 @@ func (spa StoragePowerActor) Exports() []interface{} { 6: spa.PowerLookup, 7: spa.IsMiner, 8: spa.PledgeCollateralForSize, + 9: spa.CheckProofSubmissions, } } @@ -273,13 +275,8 @@ func (spa StoragePowerActor) UpdateStorage(act *types.Actor, vmctx types.VMConte return nil, err } - has, err := MinerSetHas(vmctx, self.Miners, vmctx.Message().From) - if err != nil { - return nil, err - } - - if !has { - return nil, aerrors.New(1, "update storage must only be called by a miner actor") + if vmctx.Message().From.Protocol() != address.Actor { + return nil, aerrors.New(1, "update storage must only be called by an actor") } self.TotalStorage = types.BigAdd(self.TotalStorage, params.Delta) @@ -529,6 +526,68 @@ func pledgeCollateralForSize(vmctx types.VMContext, size, totalStorage types.Big return types.BigAdd(powerCollateral, perCapCollateral), nil } +func (spa StoragePowerActor) CheckProofSubmissions(act *types.Actor, vmctx types.VMContext, param *struct{}) ([]byte, ActorError) { + if vmctx.Message().From != StoragePowerAddress { + return nil, aerrors.New(1, "CheckProofSubmissions is only callable as a part of tipset state computation") + } + + bucketID := vmctx.BlockHeight() % build.ProvingPeriodDuration + + var self StoragePowerState + old := vmctx.Storage().GetHead() + if err := vmctx.Storage().Get(old, &self); err != nil { + return nil, err + } + + buckets, eerr := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.ProvingBuckets) + if eerr != nil { + return nil, aerrors.HandleExternalError(eerr, "loading proving buckets amt") + } + + var bucket cid.Cid + err := buckets.Get(bucketID, &bucket) + switch err.(type) { + case amt.ErrNotFound: + return nil, nil // nothing to do + case nil: + default: + return nil, aerrors.HandleExternalError(err, "getting proving bucket") + } + + bhamt, err := hamt.LoadNode(vmctx.Context(), vmctx.Ipld(), bucket) + if err != nil { + return nil, aerrors.HandleExternalError(err, "failed to load proving bucket") + } + + err = bhamt.ForEach(vmctx.Context(), func(k string, val interface{}) error { + maddr, err := address.NewFromBytes([]byte(k)) + if err != nil { + return aerrors.Escalate(err, "parsing miner address") + } + + ret, err := vmctx.Send(maddr, MAMethods.CheckMiner, vmctx.Message().Value, nil) + if err != nil { + return err + } + + if len(ret) == 0 { + return nil // miner is fine + } + + power := types.NewInt(0) + power.SetBytes(ret) + + self.TotalStorage = types.BigSub(self.TotalStorage, power) + + return nil + }) + if err != nil { + return nil, aerrors.HandleExternalError(err, "iterating miners in proving bucket") + } + + return nil, nil +} + func MinerSetHas(vmctx types.VMContext, rcid cid.Cid, maddr address.Address) (bool, aerrors.ActorError) { nd, err := hamt.LoadNode(vmctx.Context(), vmctx.Ipld(), rcid) if err != nil { diff --git a/chain/actors/cbor_gen.go b/chain/actors/cbor_gen.go index fbb289fd2..d41cd3749 100644 --- a/chain/actors/cbor_gen.go +++ b/chain/actors/cbor_gen.go @@ -268,15 +268,6 @@ func (t *StorageMinerActorState) MarshalCBOR(w io.Writer) error { return err } - // t.t.SlashedAt (types.BigInt) (struct) - if err := t.SlashedAt.MarshalCBOR(w); err != nil { - return err - } - - // t.t.OwedStorageCollateral (types.BigInt) (struct) - if err := t.OwedStorageCollateral.MarshalCBOR(w); err != nil { - return err - } // t.t.ProvingPeriodEnd (uint64) (uint64) if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.ProvingPeriodEnd))); err != nil { @@ -427,22 +418,7 @@ func (t *StorageMinerActorState) UnmarshalCBOR(r io.Reader) error { } // t.t.SlashedAt (types.BigInt) (struct) - { - if err := t.SlashedAt.UnmarshalCBOR(br); err != nil { - return err - } - - } - // t.t.OwedStorageCollateral (types.BigInt) (struct) - - { - - if err := t.OwedStorageCollateral.UnmarshalCBOR(br); err != nil { - return err - } - - } // t.t.ProvingPeriodEnd (uint64) (uint64) maj, extra, err = cbg.CborReadHeader(br) @@ -886,85 +862,6 @@ func (t *SubmitPoStParams) UnmarshalCBOR(r io.Reader) error { return nil } -func (t *PaymentVerifyParams) MarshalCBOR(w io.Writer) error { - if t == nil { - _, err := w.Write(cbg.CborNull) - return err - } - if _, err := w.Write([]byte{130}); err != nil { - return err - } - - // t.t.Extra ([]uint8) (slice) - if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Extra)))); err != nil { - return err - } - if _, err := w.Write(t.Extra); err != nil { - return err - } - - // t.t.Proof ([]uint8) (slice) - if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Proof)))); err != nil { - return err - } - if _, err := w.Write(t.Proof); err != nil { - return err - } - return nil -} - -func (t *PaymentVerifyParams) UnmarshalCBOR(r io.Reader) error { - br := cbg.GetPeeker(r) - - maj, extra, err := cbg.CborReadHeader(br) - if err != nil { - return err - } - if maj != cbg.MajArray { - return fmt.Errorf("cbor input should be of type array") - } - - if extra != 2 { - return fmt.Errorf("cbor input had wrong number of fields") - } - - // t.t.Extra ([]uint8) (slice) - - maj, extra, err = cbg.CborReadHeader(br) - if err != nil { - return err - } - if extra > 8192 { - return fmt.Errorf("t.Extra: array too large (%d)", extra) - } - - if maj != cbg.MajByteString { - return fmt.Errorf("expected byte array") - } - t.Extra = make([]byte, extra) - if _, err := io.ReadFull(br, t.Extra); err != nil { - return err - } - // t.t.Proof ([]uint8) (slice) - - maj, extra, err = cbg.CborReadHeader(br) - if err != nil { - return err - } - if extra > 8192 { - return fmt.Errorf("t.Proof: array too large (%d)", extra) - } - - if maj != cbg.MajByteString { - return fmt.Errorf("expected byte array") - } - t.Proof = make([]byte, extra) - if _, err := io.ReadFull(br, t.Proof); err != nil { - return err - } - return nil -} - func (t *UpdatePeerIDParams) MarshalCBOR(w io.Writer) error { if t == nil { _, err := w.Write(cbg.CborNull)