diff --git a/chain/actors/actor_storagepower.go b/chain/actors/actor_storagepower.go index 9502037d7..e76cdd054 100644 --- a/chain/actors/actor_storagepower.go +++ b/chain/actors/actor_storagepower.go @@ -53,6 +53,7 @@ type StoragePowerState struct { Miners cid.Cid ProvingBuckets cid.Cid // amt[ProvingPeriodBucket]hamt[minerAddress]struct{} MinerCount uint64 + LastMinerCheck uint64 TotalStorage types.BigInt } @@ -570,32 +571,56 @@ func (spa StoragePowerActor) CheckProofSubmissions(act *types.Actor, vmctx types 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 } + for i := self.LastMinerCheck; i < vmctx.BlockHeight(); i++ { + height := i + 1 + + err := checkProofSubmissionsAtH(vmctx, &self, height) + if err != nil { + return nil, err + } + } + + self.LastMinerCheck = vmctx.BlockHeight() + + nroot, aerr := vmctx.Storage().Put(&self) + if aerr != nil { + return nil, aerr + } + + if err := vmctx.Storage().Commit(old, nroot); err != nil { + return nil, err + } + + return nil, nil +} + +func checkProofSubmissionsAtH(vmctx types.VMContext, self *StoragePowerState, height uint64) aerrors.ActorError { + bucketID := height % build.ProvingPeriodDuration + buckets, eerr := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.ProvingBuckets) if eerr != nil { - return nil, aerrors.HandleExternalError(eerr, "loading proving buckets amt") + return 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 + return nil // nothing to do case nil: default: - return nil, aerrors.HandleExternalError(err, "getting proving bucket") + return 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") + return aerrors.HandleExternalError(err, "failed to load proving bucket") } err = bhamt.ForEach(vmctx.Context(), func(k string, val interface{}) error { @@ -629,26 +654,18 @@ func (spa StoragePowerActor) CheckProofSubmissions(act *types.Actor, vmctx types } if power.GreaterThan(types.NewInt(0)) { - log.Warnf("slashing miner %s for missed PoSt (%s B, H: %d, Bucket: %d)", maddr, power, vmctx.BlockHeight(), bucketID) + log.Warnf("slashing miner %s for missed PoSt (%s B, H: %d, Bucket: %d)", maddr, power, height, bucketID) self.TotalStorage = types.BigSub(self.TotalStorage, power) } return nil }) + if err != nil { - return nil, aerrors.HandleExternalError(err, "iterating miners in proving bucket") + return aerrors.HandleExternalError(err, "iterating miners in proving bucket") } - nroot, aerr := vmctx.Storage().Put(&self) - if aerr != nil { - return nil, aerr - } - - if err := vmctx.Storage().Commit(old, nroot); err != nil { - return nil, err - } - - return nil, nil + return nil } func MinerSetHas(vmctx types.VMContext, rcid cid.Cid, maddr address.Address) (bool, aerrors.ActorError) { diff --git a/chain/actors/cbor_gen.go b/chain/actors/cbor_gen.go index 7b76b1e8b..53de185e1 100644 --- a/chain/actors/cbor_gen.go +++ b/chain/actors/cbor_gen.go @@ -2417,7 +2417,7 @@ func (t *StoragePowerState) MarshalCBOR(w io.Writer) error { _, err := w.Write(cbg.CborNull) return err } - if _, err := w.Write([]byte{132}); err != nil { + if _, err := w.Write([]byte{133}); err != nil { return err } @@ -2438,6 +2438,11 @@ func (t *StoragePowerState) MarshalCBOR(w io.Writer) error { return err } + // t.t.LastMinerCheck (uint64) (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.LastMinerCheck))); err != nil { + return err + } + // t.t.TotalStorage (types.BigInt) (struct) if err := t.TotalStorage.MarshalCBOR(w); err != nil { return err @@ -2456,7 +2461,7 @@ func (t *StoragePowerState) UnmarshalCBOR(r io.Reader) error { return fmt.Errorf("cbor input should be of type array") } - if extra != 4 { + if extra != 5 { return fmt.Errorf("cbor input had wrong number of fields") } @@ -2494,6 +2499,16 @@ func (t *StoragePowerState) UnmarshalCBOR(r io.Reader) error { return fmt.Errorf("wrong type for uint64 field") } t.MinerCount = uint64(extra) + // t.t.LastMinerCheck (uint64) (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.LastMinerCheck = uint64(extra) // t.t.TotalStorage (types.BigInt) (struct) {