specs-actors: Import miner/power/cron/paych code
This commit is contained in:
parent
07ae3e49a3
commit
91ca4a841a
@ -1,48 +1,9 @@
|
|||||||
package actors
|
package actors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/specs-actors/actors/builtin/cron"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type CronActor struct{}
|
type CronActor = cron.Actor
|
||||||
|
|
||||||
type callTuple struct {
|
type CronActorState = cron.State
|
||||||
addr address.Address
|
|
||||||
method uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
var CronActors = []callTuple{
|
|
||||||
{StoragePowerAddress, SPAMethods.CheckProofSubmissions},
|
|
||||||
}
|
|
||||||
|
|
||||||
type CronActorState struct{}
|
|
||||||
|
|
||||||
type cAMethods struct {
|
|
||||||
EpochTick uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
var CAMethods = cAMethods{2}
|
|
||||||
|
|
||||||
func (ca CronActor) Exports() []interface{} {
|
|
||||||
return []interface{}{
|
|
||||||
1: nil,
|
|
||||||
2: ca.EpochTick,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ca CronActor) EpochTick(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
|
||||||
if vmctx.Message().From != CronAddress {
|
|
||||||
return nil, aerrors.New(1, "EpochTick is only callable as a part of tipset state computation")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, call := range CronActors {
|
|
||||||
_, err := vmctx.Send(call.addr, call.method, types.NewInt(0), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err // todo: this very bad?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,302 +1,9 @@
|
|||||||
package actors
|
package actors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
|
||||||
"github.com/minio/blake2b-simd"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type PaymentChannelActor struct{}
|
type PaymentChannelActor = paych.Actor
|
||||||
|
|
||||||
type PaymentInfo struct {
|
type PaymentChannelActorState = paych.State
|
||||||
PayChActor address.Address
|
|
||||||
Payer address.Address
|
|
||||||
ChannelMessage *cid.Cid
|
|
||||||
|
|
||||||
Vouchers []*types.SignedVoucher
|
|
||||||
}
|
|
||||||
|
|
||||||
type LaneState struct {
|
|
||||||
Closed bool
|
|
||||||
Redeemed types.BigInt
|
|
||||||
Nonce uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type PaymentChannelActorState struct {
|
|
||||||
From address.Address
|
|
||||||
To address.Address
|
|
||||||
|
|
||||||
ToSend types.BigInt
|
|
||||||
|
|
||||||
ClosingAt uint64
|
|
||||||
MinCloseHeight uint64
|
|
||||||
|
|
||||||
// TODO: needs to be map[uint64]*laneState
|
|
||||||
// waiting on refmt#35 to be fixed
|
|
||||||
LaneStates map[string]*LaneState
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pca PaymentChannelActor) Exports() []interface{} {
|
|
||||||
return []interface{}{
|
|
||||||
1: pca.Constructor,
|
|
||||||
2: pca.UpdateChannelState,
|
|
||||||
3: pca.Close,
|
|
||||||
4: pca.Collect,
|
|
||||||
5: pca.GetOwner,
|
|
||||||
6: pca.GetToSend,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type pcaMethods struct {
|
|
||||||
Constructor uint64
|
|
||||||
UpdateChannelState uint64
|
|
||||||
Close uint64
|
|
||||||
Collect uint64
|
|
||||||
GetOwner uint64
|
|
||||||
GetToSend uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
var PCAMethods = pcaMethods{1, 2, 3, 4, 5, 6}
|
|
||||||
|
|
||||||
type PCAConstructorParams struct {
|
|
||||||
To address.Address
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pca PaymentChannelActor) Constructor(act *types.Actor, vmctx types.VMContext, params *PCAConstructorParams) ([]byte, ActorError) {
|
|
||||||
var self PaymentChannelActorState
|
|
||||||
self.From = vmctx.Origin()
|
|
||||||
self.To = params.To
|
|
||||||
self.LaneStates = make(map[string]*LaneState)
|
|
||||||
|
|
||||||
storage := vmctx.Storage()
|
|
||||||
c, err := storage.Put(&self)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := storage.Commit(EmptyCBOR, c); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type PCAUpdateChannelStateParams struct {
|
|
||||||
Sv types.SignedVoucher
|
|
||||||
Secret []byte
|
|
||||||
Proof []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func hash(b []byte) []byte {
|
|
||||||
s := blake2b.Sum256(b)
|
|
||||||
return s[:]
|
|
||||||
}
|
|
||||||
|
|
||||||
type PaymentVerifyParams struct {
|
|
||||||
Extra []byte
|
|
||||||
Proof []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pca PaymentChannelActor) UpdateChannelState(act *types.Actor, vmctx types.VMContext, params *PCAUpdateChannelStateParams) ([]byte, ActorError) {
|
|
||||||
var self PaymentChannelActorState
|
|
||||||
oldstate := vmctx.Storage().GetHead()
|
|
||||||
storage := vmctx.Storage()
|
|
||||||
if err := storage.Get(oldstate, &self); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
sv := params.Sv
|
|
||||||
|
|
||||||
vb, nerr := sv.SigningBytes()
|
|
||||||
if nerr != nil {
|
|
||||||
return nil, aerrors.Absorb(nerr, 1, "failed to serialize signedvoucher")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := vmctx.VerifySignature(sv.Signature, self.From, vb); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if uint64(vmctx.BlockHeight()) < sv.TimeLock {
|
|
||||||
return nil, aerrors.New(2, "cannot use this voucher yet!")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(sv.SecretPreimage) > 0 {
|
|
||||||
if !bytes.Equal(hash(params.Secret), sv.SecretPreimage) {
|
|
||||||
return nil, aerrors.New(3, "incorrect secret!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if sv.Extra != nil {
|
|
||||||
encoded, err := SerializeParams(&PaymentVerifyParams{sv.Extra.Data, params.Proof})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = vmctx.Send(sv.Extra.Actor, sv.Extra.Method, types.NewInt(0), encoded)
|
|
||||||
if err != nil {
|
|
||||||
return nil, aerrors.Newf(4, "spend voucher verification failed: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ls, ok := self.LaneStates[fmt.Sprint(sv.Lane)]
|
|
||||||
if !ok {
|
|
||||||
ls = new(LaneState)
|
|
||||||
ls.Redeemed = types.NewInt(0) // TODO: kinda annoying that this doesnt default to a usable value
|
|
||||||
self.LaneStates[fmt.Sprint(sv.Lane)] = ls
|
|
||||||
}
|
|
||||||
if ls.Closed {
|
|
||||||
return nil, aerrors.New(5, "cannot redeem a voucher on a closed lane")
|
|
||||||
}
|
|
||||||
|
|
||||||
if ls.Nonce > sv.Nonce {
|
|
||||||
return nil, aerrors.New(6, "voucher has an outdated nonce, cannot redeem")
|
|
||||||
}
|
|
||||||
|
|
||||||
mergeValue := types.NewInt(0)
|
|
||||||
for _, merge := range sv.Merges {
|
|
||||||
if merge.Lane == sv.Lane {
|
|
||||||
return nil, aerrors.New(7, "voucher cannot merge its own lane")
|
|
||||||
}
|
|
||||||
|
|
||||||
ols := self.LaneStates[fmt.Sprint(merge.Lane)]
|
|
||||||
|
|
||||||
if ols.Nonce >= merge.Nonce {
|
|
||||||
return nil, aerrors.New(8, "merge in voucher has outdated nonce, cannot redeem")
|
|
||||||
}
|
|
||||||
|
|
||||||
mergeValue = types.BigAdd(mergeValue, ols.Redeemed)
|
|
||||||
ols.Nonce = merge.Nonce
|
|
||||||
}
|
|
||||||
|
|
||||||
ls.Nonce = sv.Nonce
|
|
||||||
balanceDelta := types.BigSub(sv.Amount, types.BigAdd(mergeValue, ls.Redeemed))
|
|
||||||
ls.Redeemed = sv.Amount
|
|
||||||
|
|
||||||
newSendBalance := types.BigAdd(self.ToSend, balanceDelta)
|
|
||||||
if newSendBalance.LessThan(types.NewInt(0)) {
|
|
||||||
// TODO: is this impossible?
|
|
||||||
return nil, aerrors.New(9, "voucher would leave channel balance negative")
|
|
||||||
}
|
|
||||||
|
|
||||||
if newSendBalance.GreaterThan(act.Balance) {
|
|
||||||
return nil, aerrors.New(10, "not enough funds in channel to cover voucher")
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("vals: ", newSendBalance, sv.Amount, balanceDelta, mergeValue, ls.Redeemed)
|
|
||||||
self.ToSend = newSendBalance
|
|
||||||
|
|
||||||
if sv.MinCloseHeight != 0 {
|
|
||||||
if self.ClosingAt != 0 && self.ClosingAt < sv.MinCloseHeight {
|
|
||||||
self.ClosingAt = sv.MinCloseHeight
|
|
||||||
}
|
|
||||||
if self.MinCloseHeight < sv.MinCloseHeight {
|
|
||||||
self.MinCloseHeight = sv.MinCloseHeight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ncid, err := storage.Put(&self)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := storage.Commit(oldstate, ncid); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pca PaymentChannelActor) Close(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, aerrors.ActorError) {
|
|
||||||
var self PaymentChannelActorState
|
|
||||||
storage := vmctx.Storage()
|
|
||||||
oldstate := storage.GetHead()
|
|
||||||
if err := storage.Get(oldstate, &self); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if vmctx.Message().From != self.From && vmctx.Message().From != self.To {
|
|
||||||
return nil, aerrors.New(1, "not authorized to close channel")
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.ClosingAt != 0 {
|
|
||||||
return nil, aerrors.New(2, "channel already closing")
|
|
||||||
}
|
|
||||||
|
|
||||||
self.ClosingAt = uint64(vmctx.BlockHeight()) + build.PaymentChannelClosingDelay
|
|
||||||
if self.ClosingAt < self.MinCloseHeight {
|
|
||||||
self.ClosingAt = self.MinCloseHeight
|
|
||||||
}
|
|
||||||
|
|
||||||
ncid, err := storage.Put(&self)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := storage.Commit(oldstate, ncid); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pca PaymentChannelActor) Collect(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, aerrors.ActorError) {
|
|
||||||
var self PaymentChannelActorState
|
|
||||||
storage := vmctx.Storage()
|
|
||||||
oldstate := storage.GetHead()
|
|
||||||
if err := storage.Get(oldstate, &self); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.ClosingAt == 0 {
|
|
||||||
return nil, aerrors.New(1, "payment channel not closing or closed")
|
|
||||||
}
|
|
||||||
|
|
||||||
if uint64(vmctx.BlockHeight()) < self.ClosingAt {
|
|
||||||
return nil, aerrors.New(2, "payment channel not closed yet")
|
|
||||||
}
|
|
||||||
_, err := vmctx.Send(self.From, 0, types.BigSub(act.Balance, self.ToSend), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
_, err = vmctx.Send(self.To, 0, self.ToSend, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
self.ToSend = types.NewInt(0)
|
|
||||||
|
|
||||||
ncid, err := storage.Put(&self)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := storage.Commit(oldstate, ncid); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pca PaymentChannelActor) GetOwner(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, aerrors.ActorError) {
|
|
||||||
var self PaymentChannelActorState
|
|
||||||
storage := vmctx.Storage()
|
|
||||||
if err := storage.Get(storage.GetHead(), &self); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return self.From.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pca PaymentChannelActor) GetToSend(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, aerrors.ActorError) {
|
|
||||||
var self PaymentChannelActorState
|
|
||||||
storage := vmctx.Storage()
|
|
||||||
if err := storage.Get(storage.GetHead(), &self); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
@ -1,832 +1,12 @@
|
|||||||
package actors
|
package actors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
"context"
|
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-amt-ipld/v2"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
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"
|
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
xerrors "golang.org/x/xerrors"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
|
||||||
"github.com/filecoin-project/lotus/lib/sigs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type StoragePowerActor struct{}
|
type StoragePowerActor = power.Actor
|
||||||
|
|
||||||
type spaMethods struct {
|
var SPAMethods = builtin.MethodsPower
|
||||||
Constructor uint64
|
|
||||||
CreateStorageMiner uint64
|
|
||||||
ArbitrateConsensusFault uint64
|
|
||||||
UpdateStorage uint64
|
|
||||||
GetTotalStorage uint64
|
|
||||||
PowerLookup uint64
|
|
||||||
IsValidMiner uint64
|
|
||||||
PledgeCollateralForSize uint64
|
|
||||||
CheckProofSubmissions uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
var SPAMethods = spaMethods{1, 2, 3, 4, 5, 6, 7, 8, 9}
|
type StoragePowerState = power.State
|
||||||
|
|
||||||
func (spa StoragePowerActor) Exports() []interface{} {
|
|
||||||
return []interface{}{
|
|
||||||
//1: spa.StoragePowerConstructor,
|
|
||||||
2: spa.CreateStorageMiner,
|
|
||||||
3: spa.ArbitrateConsensusFault,
|
|
||||||
4: spa.UpdateStorage,
|
|
||||||
5: spa.GetTotalStorage,
|
|
||||||
6: spa.PowerLookup,
|
|
||||||
7: spa.IsValidMiner,
|
|
||||||
8: spa.PledgeCollateralForSize,
|
|
||||||
9: spa.CheckProofSubmissions,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type StoragePowerState struct {
|
|
||||||
Miners cid.Cid
|
|
||||||
ProvingBuckets cid.Cid // amt[ProvingPeriodBucket]hamt[minerAddress]struct{}
|
|
||||||
MinerCount uint64
|
|
||||||
LastMinerCheck uint64
|
|
||||||
|
|
||||||
TotalStorage types.BigInt
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreateStorageMinerParams struct {
|
|
||||||
Owner address.Address
|
|
||||||
Worker address.Address
|
|
||||||
SectorSize abi.SectorSize
|
|
||||||
PeerID peer.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func (spa StoragePowerActor) CreateStorageMiner(act *types.Actor, vmctx types.VMContext, params *CreateStorageMinerParams) ([]byte, ActorError) {
|
|
||||||
if !build.SupportedSectorSize(params.SectorSize) {
|
|
||||||
return nil, aerrors.Newf(1, "Unsupported sector size: %d", params.SectorSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
var self StoragePowerState
|
|
||||||
old := vmctx.Storage().GetHead()
|
|
||||||
if err := vmctx.Storage().Get(old, &self); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
reqColl, err := pledgeCollateralForSize(vmctx, types.NewInt(0), self.TotalStorage, self.MinerCount+1)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if vmctx.Message().Value.LessThan(reqColl) {
|
|
||||||
return nil, aerrors.Newf(1, "not enough funds passed to cover required miner collateral (needed %s, got %s)", reqColl, vmctx.Message().Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
minerCid := StorageMinerCodeCid
|
|
||||||
|
|
||||||
encoded, err := CreateExecParams(minerCid, &StorageMinerConstructorParams{
|
|
||||||
Owner: params.Owner,
|
|
||||||
Worker: params.Worker,
|
|
||||||
SectorSize: params.SectorSize,
|
|
||||||
PeerID: params.PeerID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ret, err := vmctx.Send(InitAddress, IAMethods.Exec, vmctx.Message().Value, encoded)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
naddr, nerr := address.NewFromBytes(ret)
|
|
||||||
if nerr != nil {
|
|
||||||
return nil, aerrors.Absorb(nerr, 2, "could not read address of new actor")
|
|
||||||
}
|
|
||||||
|
|
||||||
ncid, err := MinerSetAdd(context.TODO(), vmctx, self.Miners, naddr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
self.Miners = ncid
|
|
||||||
self.MinerCount++
|
|
||||||
|
|
||||||
nroot, err := vmctx.Storage().Put(&self)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := vmctx.Storage().Commit(old, nroot); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return naddr.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ArbitrateConsensusFaultParams struct {
|
|
||||||
Block1 *types.BlockHeader
|
|
||||||
Block2 *types.BlockHeader
|
|
||||||
}
|
|
||||||
|
|
||||||
func (spa StoragePowerActor) ArbitrateConsensusFault(act *types.Actor, vmctx types.VMContext, params *ArbitrateConsensusFaultParams) ([]byte, ActorError) {
|
|
||||||
if params == nil || params.Block1 == nil || params.Block2 == nil {
|
|
||||||
return nil, aerrors.New(1, "failed to parse params")
|
|
||||||
}
|
|
||||||
|
|
||||||
if params.Block1.Miner != params.Block2.Miner {
|
|
||||||
return nil, aerrors.New(2, "blocks must be from the same miner")
|
|
||||||
}
|
|
||||||
|
|
||||||
if params.Block1.Cid() == params.Block2.Cid() {
|
|
||||||
return nil, aerrors.New(3, "blocks must be different")
|
|
||||||
}
|
|
||||||
|
|
||||||
rval, err := vmctx.Send(params.Block1.Miner, MAMethods.GetWorkerAddr, types.NewInt(0), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, aerrors.Wrap(err, "failed to get miner worker")
|
|
||||||
}
|
|
||||||
|
|
||||||
worker, oerr := address.NewFromBytes(rval)
|
|
||||||
if oerr != nil {
|
|
||||||
// REVIEW: should this be fatal? i can't think of a real situation that would get us here
|
|
||||||
return nil, aerrors.Absorb(oerr, 3, "response from 'GetWorkerAddr' was not a valid address")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := sigs.CheckBlockSignature(params.Block1, vmctx.Context(), worker); err != nil {
|
|
||||||
return nil, aerrors.Absorb(err, 4, "block1 did not have valid signature")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := sigs.CheckBlockSignature(params.Block2, vmctx.Context(), worker); err != nil {
|
|
||||||
return nil, aerrors.Absorb(err, 5, "block2 did not have valid signature")
|
|
||||||
}
|
|
||||||
|
|
||||||
// see the "Consensus Faults" section of the faults spec (faults.md)
|
|
||||||
// for details on these slashing conditions.
|
|
||||||
if !shouldSlash(params.Block1, params.Block2) {
|
|
||||||
return nil, aerrors.New(6, "blocks do not prove a slashable offense")
|
|
||||||
}
|
|
||||||
|
|
||||||
var self StoragePowerState
|
|
||||||
old := vmctx.Storage().GetHead()
|
|
||||||
if err := vmctx.Storage().Get(old, &self); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if types.BigCmp(self.TotalStorage, types.NewInt(0)) == 0 {
|
|
||||||
return nil, aerrors.Fatal("invalid state, storage power actor has zero total storage")
|
|
||||||
}
|
|
||||||
|
|
||||||
miner := params.Block1.Miner
|
|
||||||
if has, err := MinerSetHas(vmctx, self.Miners, miner); err != nil {
|
|
||||||
return nil, aerrors.Wrapf(err, "failed to check miner in set")
|
|
||||||
} else if !has {
|
|
||||||
return nil, aerrors.New(7, "either already slashed or not a miner")
|
|
||||||
}
|
|
||||||
|
|
||||||
minerPower, err := powerLookup(context.TODO(), vmctx, &self, miner)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
slashedCollateral, err := pledgeCollateralForSize(vmctx, minerPower, self.TotalStorage, self.MinerCount)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
enc, err := SerializeParams(&MinerSlashConsensusFault{
|
|
||||||
Slasher: vmctx.Message().From,
|
|
||||||
AtHeight: params.Block1.Height,
|
|
||||||
SlashedCollateral: slashedCollateral,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = vmctx.Send(miner, MAMethods.SlashConsensusFault, types.NewInt(0), enc)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the miner from the list of network miners
|
|
||||||
ncid, err := MinerSetRemove(context.TODO(), vmctx, self.Miners, miner)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
self.Miners = ncid
|
|
||||||
self.MinerCount--
|
|
||||||
|
|
||||||
self.TotalStorage = types.BigSub(self.TotalStorage, minerPower)
|
|
||||||
|
|
||||||
nroot, err := vmctx.Storage().Put(&self)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := vmctx.Storage().Commit(old, nroot); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func cidArrContains(a []cid.Cid, b cid.Cid) bool {
|
|
||||||
for _, c := range a {
|
|
||||||
if b == c {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func shouldSlash(block1, block2 *types.BlockHeader) bool {
|
|
||||||
// First slashing condition, blocks have the same ticket round
|
|
||||||
if block1.Height == block2.Height {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Second slashing condition requires having access to the parent tipset blocks
|
|
||||||
// This might not always be available, needs some thought on the best way to deal with this
|
|
||||||
|
|
||||||
|
|
||||||
// Second slashing condition, miner ignored own block when mining
|
|
||||||
// Case A: block2 could have been in block1's parent set but is not
|
|
||||||
b1ParentHeight := block1.Height - len(block1.Tickets)
|
|
||||||
|
|
||||||
block1ParentTipSet := block1.Parents
|
|
||||||
if !cidArrContains(block1.Parents, block2.Cid()) &&
|
|
||||||
b1ParentHeight == block2.Height &&
|
|
||||||
block1ParentTipSet.ParentCids == block2.ParentCids {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Case B: block1 could have been in block2's parent set but is not
|
|
||||||
block2ParentTipSet := parentOf(block2)
|
|
||||||
if !block2Parent.contains(block1) &&
|
|
||||||
block2ParentTipSet.Height == block1.Height &&
|
|
||||||
block2ParentTipSet.ParentCids == block1.ParentCids {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type UpdateStorageParams struct {
|
|
||||||
Delta types.BigInt
|
|
||||||
NextSlashDeadline uint64
|
|
||||||
PreviousSlashDeadline uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (spa StoragePowerActor) UpdateStorage(act *types.Actor, vmctx types.VMContext, params *UpdateStorageParams) ([]byte, ActorError) {
|
|
||||||
ctx := vmctx.Context()
|
|
||||||
var self StoragePowerState
|
|
||||||
old := vmctx.Storage().GetHead()
|
|
||||||
if err := vmctx.Storage().Get(old, &self); err != nil {
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
|
|
||||||
self.TotalStorage = types.BigAdd(self.TotalStorage, params.Delta)
|
|
||||||
|
|
||||||
previousBucket := params.PreviousSlashDeadline % build.SlashablePowerDelay
|
|
||||||
nextBucket := params.NextSlashDeadline % build.SlashablePowerDelay
|
|
||||||
|
|
||||||
if previousBucket == nextBucket && params.PreviousSlashDeadline != 0 {
|
|
||||||
nroot, err := vmctx.Storage().Put(&self)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := vmctx.Storage().Commit(old, nroot); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil // Nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
buckets, eerr := amt.LoadAMT(ctx, vmctx.Ipld(), self.ProvingBuckets)
|
|
||||||
if eerr != nil {
|
|
||||||
return nil, aerrors.HandleExternalError(eerr, "loading proving buckets amt")
|
|
||||||
}
|
|
||||||
|
|
||||||
if params.PreviousSlashDeadline != 0 { // delete from previous bucket
|
|
||||||
err := deleteMinerFromBucket(vmctx, buckets, previousBucket)
|
|
||||||
if err != nil {
|
|
||||||
return nil, aerrors.Wrapf(err, "delete from bucket %d, next %d", previousBucket, nextBucket)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = addMinerToBucket(vmctx, buckets, nextBucket)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
self.ProvingBuckets, eerr = buckets.Flush(ctx)
|
|
||||||
if eerr != nil {
|
|
||||||
return nil, aerrors.HandleExternalError(eerr, "flushing proving buckets")
|
|
||||||
}
|
|
||||||
|
|
||||||
nroot, err := vmctx.Storage().Put(&self)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := vmctx.Storage().Commit(old, nroot); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteMinerFromBucket(vmctx types.VMContext, buckets *amt.Root, previousBucket uint64) aerrors.ActorError {
|
|
||||||
ctx := vmctx.Context()
|
|
||||||
var bucket cid.Cid
|
|
||||||
err := buckets.Get(ctx, previousBucket, &bucket)
|
|
||||||
switch err.(type) {
|
|
||||||
case *amt.ErrNotFound:
|
|
||||||
return aerrors.HandleExternalError(err, "proving bucket missing")
|
|
||||||
case nil: // noop
|
|
||||||
default:
|
|
||||||
return aerrors.HandleExternalError(err, "getting proving bucket")
|
|
||||||
}
|
|
||||||
|
|
||||||
bhamt, err := hamt.LoadNode(vmctx.Context(), vmctx.Ipld(), bucket)
|
|
||||||
if err != nil {
|
|
||||||
return aerrors.HandleExternalError(err, "failed to load proving bucket")
|
|
||||||
}
|
|
||||||
err = bhamt.Delete(vmctx.Context(), string(vmctx.Message().From.Bytes()))
|
|
||||||
if err != nil {
|
|
||||||
return aerrors.HandleExternalError(err, "deleting miner from proving bucket")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bhamt.Flush(vmctx.Context())
|
|
||||||
if err != nil {
|
|
||||||
return aerrors.HandleExternalError(err, "flushing previous proving bucket")
|
|
||||||
}
|
|
||||||
|
|
||||||
bucket, err = vmctx.Ipld().Put(vmctx.Context(), bhamt)
|
|
||||||
if err != nil {
|
|
||||||
return aerrors.HandleExternalError(err, "putting previous proving bucket hamt")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = buckets.Set(ctx, previousBucket, bucket)
|
|
||||||
if err != nil {
|
|
||||||
return aerrors.HandleExternalError(err, "setting previous proving bucket cid in amt")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func addMinerToBucket(vmctx types.VMContext, buckets *amt.Root, nextBucket uint64) aerrors.ActorError {
|
|
||||||
ctx := vmctx.Context()
|
|
||||||
var bhamt *hamt.Node
|
|
||||||
var bucket cid.Cid
|
|
||||||
err := buckets.Get(ctx, nextBucket, &bucket)
|
|
||||||
switch err.(type) {
|
|
||||||
case *amt.ErrNotFound:
|
|
||||||
bhamt = hamt.NewNode(vmctx.Ipld())
|
|
||||||
case nil:
|
|
||||||
bhamt, err = hamt.LoadNode(vmctx.Context(), vmctx.Ipld(), bucket)
|
|
||||||
if err != nil {
|
|
||||||
return aerrors.HandleExternalError(err, "failed to load proving bucket")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return aerrors.HandleExternalError(err, "getting proving bucket")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bhamt.Set(vmctx.Context(), string(vmctx.Message().From.Bytes()), CborNull)
|
|
||||||
if err != nil {
|
|
||||||
return aerrors.HandleExternalError(err, "setting miner in proving bucket")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bhamt.Flush(vmctx.Context())
|
|
||||||
if err != nil {
|
|
||||||
return aerrors.HandleExternalError(err, "flushing previous proving bucket")
|
|
||||||
}
|
|
||||||
|
|
||||||
bucket, err = vmctx.Ipld().Put(vmctx.Context(), bhamt)
|
|
||||||
if err != nil {
|
|
||||||
return aerrors.HandleExternalError(err, "putting previous proving bucket hamt")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = buckets.Set(ctx, nextBucket, bucket)
|
|
||||||
if err != nil {
|
|
||||||
return aerrors.HandleExternalError(err, "setting previous proving bucket cid in amt")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (spa StoragePowerActor) GetTotalStorage(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
|
||||||
var self StoragePowerState
|
|
||||||
if err := vmctx.Storage().Get(vmctx.Storage().GetHead(), &self); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type PowerLookupParams struct {
|
|
||||||
Miner address.Address
|
|
||||||
}
|
|
||||||
|
|
||||||
func (spa StoragePowerActor) PowerLookup(act *types.Actor, vmctx types.VMContext, params *PowerLookupParams) ([]byte, ActorError) {
|
|
||||||
var self StoragePowerState
|
|
||||||
if err := vmctx.Storage().Get(vmctx.Storage().GetHead(), &self); err != nil {
|
|
||||||
return nil, aerrors.Wrap(err, "getting head")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func powerLookup(ctx context.Context, vmctx types.VMContext, self *StoragePowerState, miner address.Address) (types.BigInt, ActorError) {
|
|
||||||
has, err := MinerSetHas(vmctx, self.Miners, miner)
|
|
||||||
if err != nil {
|
|
||||||
return types.EmptyInt, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !has {
|
|
||||||
// A miner could be registered with storage power actor, but removed for some reasons, e.g. consensus fault
|
|
||||||
return types.EmptyInt, aerrors.New(1, "miner not registered with storage power actor, or removed already")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Use local amt
|
|
||||||
ret, err := vmctx.Send(miner, MAMethods.GetPower, types.NewInt(0), nil)
|
|
||||||
if err != nil {
|
|
||||||
return types.EmptyInt, aerrors.Wrap(err, "invoke Miner.GetPower")
|
|
||||||
}
|
|
||||||
|
|
||||||
return types.BigFromBytes(ret), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type IsValidMinerParam struct {
|
|
||||||
Addr address.Address
|
|
||||||
}
|
|
||||||
|
|
||||||
func (spa StoragePowerActor) IsValidMiner(act *types.Actor, vmctx types.VMContext, param *IsValidMinerParam) ([]byte, ActorError) {
|
|
||||||
var self StoragePowerState
|
|
||||||
if err := vmctx.Storage().Get(vmctx.Storage().GetHead(), &self); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
has, err := MinerSetHas(vmctx, self.Miners, param.Addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !has {
|
|
||||||
log.Warnf("Miner INVALID: not in set: %s", param.Addr)
|
|
||||||
|
|
||||||
return cbg.CborBoolFalse, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ret, err := vmctx.Send(param.Addr, MAMethods.IsSlashed, types.NewInt(0), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
slashed := bytes.Equal(ret, cbg.CborBoolTrue)
|
|
||||||
|
|
||||||
if slashed {
|
|
||||||
log.Warnf("Miner INVALID: /SLASHED/ : %s", param.Addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return cbg.EncodeBool(!slashed), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type PledgeCollateralParams struct {
|
|
||||||
Size types.BigInt
|
|
||||||
}
|
|
||||||
|
|
||||||
func (spa StoragePowerActor) PledgeCollateralForSize(act *types.Actor, vmctx types.VMContext, param *PledgeCollateralParams) ([]byte, ActorError) {
|
|
||||||
var self StoragePowerState
|
|
||||||
if err := vmctx.Storage().Get(vmctx.Storage().GetHead(), &self); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func pledgeCollateralForSize(vmctx types.VMContext, size, totalStorage types.BigInt, minerCount uint64) (types.BigInt, aerrors.ActorError) {
|
|
||||||
netBalance, err := vmctx.GetBalance(NetworkAddress)
|
|
||||||
if err != nil {
|
|
||||||
return types.EmptyInt, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: the spec says to also grab 'total vested filecoin' and include it as available
|
|
||||||
// If we don't factor that in, we effectively assume all of the locked up filecoin is 'available'
|
|
||||||
// the blocker on that right now is that its hard to tell how much filecoin is unlocked
|
|
||||||
|
|
||||||
availableFilecoin := types.BigSub(
|
|
||||||
types.BigMul(types.NewInt(build.TotalFilecoin), types.NewInt(build.FilecoinPrecision)),
|
|
||||||
netBalance,
|
|
||||||
)
|
|
||||||
|
|
||||||
totalPowerCollateral := types.BigDiv(
|
|
||||||
types.BigMul(
|
|
||||||
availableFilecoin,
|
|
||||||
types.NewInt(build.PowerCollateralProportion),
|
|
||||||
),
|
|
||||||
types.NewInt(build.CollateralPrecision),
|
|
||||||
)
|
|
||||||
|
|
||||||
totalPerCapitaCollateral := types.BigDiv(
|
|
||||||
types.BigMul(
|
|
||||||
availableFilecoin,
|
|
||||||
types.NewInt(build.PerCapitaCollateralProportion),
|
|
||||||
),
|
|
||||||
types.NewInt(build.CollateralPrecision),
|
|
||||||
)
|
|
||||||
|
|
||||||
// REVIEW: for bootstrapping purposes, we skip the power portion of the
|
|
||||||
// collateral if there is no collateral in the network yet
|
|
||||||
powerCollateral := types.NewInt(0)
|
|
||||||
if types.BigCmp(totalStorage, types.NewInt(0)) != 0 {
|
|
||||||
powerCollateral = types.BigDiv(
|
|
||||||
types.BigMul(
|
|
||||||
totalPowerCollateral,
|
|
||||||
size,
|
|
||||||
),
|
|
||||||
totalStorage,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
perCapCollateral := types.BigDiv(
|
|
||||||
totalPerCapitaCollateral,
|
|
||||||
types.NewInt(minerCount),
|
|
||||||
)
|
|
||||||
|
|
||||||
return types.BigAdd(powerCollateral, perCapCollateral), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (spa StoragePowerActor) CheckProofSubmissions(act *types.Actor, vmctx types.VMContext, param *struct{}) ([]byte, ActorError) {
|
|
||||||
if vmctx.Message().From != CronAddress {
|
|
||||||
return nil, aerrors.New(1, "CheckProofSubmissions is only callable from the cron actor")
|
|
||||||
}
|
|
||||||
|
|
||||||
var self StoragePowerState
|
|
||||||
old := vmctx.Storage().GetHead()
|
|
||||||
if err := vmctx.Storage().Get(old, &self); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := self.LastMinerCheck; i < uint64(vmctx.BlockHeight()); i++ {
|
|
||||||
height := i + 1
|
|
||||||
|
|
||||||
err := checkProofSubmissionsAtH(vmctx, &self, height)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.LastMinerCheck = uint64(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 {
|
|
||||||
ctx := vmctx.Context()
|
|
||||||
bucketID := height % build.SlashablePowerDelay
|
|
||||||
|
|
||||||
buckets, eerr := amt.LoadAMT(ctx, vmctx.Ipld(), self.ProvingBuckets)
|
|
||||||
if eerr != nil {
|
|
||||||
return aerrors.HandleExternalError(eerr, "loading proving buckets amt")
|
|
||||||
}
|
|
||||||
|
|
||||||
var bucket cid.Cid
|
|
||||||
err := buckets.Get(ctx, bucketID, &bucket)
|
|
||||||
switch err.(type) {
|
|
||||||
case *amt.ErrNotFound:
|
|
||||||
return nil // nothing to do
|
|
||||||
case nil:
|
|
||||||
default:
|
|
||||||
return aerrors.HandleExternalError(err, "getting proving bucket")
|
|
||||||
}
|
|
||||||
|
|
||||||
bhamt, err := hamt.LoadNode(vmctx.Context(), vmctx.Ipld(), bucket)
|
|
||||||
if err != nil {
|
|
||||||
return aerrors.HandleExternalError(err, "failed to load proving bucket")
|
|
||||||
}
|
|
||||||
|
|
||||||
forRemoval := make([]address.Address, 0)
|
|
||||||
|
|
||||||
err = bhamt.ForEach(vmctx.Context(), func(k string, val interface{}) error {
|
|
||||||
_, span := trace.StartSpan(vmctx.Context(), "StoragePowerActor.CheckProofSubmissions.loop")
|
|
||||||
defer span.End()
|
|
||||||
|
|
||||||
maddr, err := address.NewFromBytes([]byte(k))
|
|
||||||
if err != nil {
|
|
||||||
return aerrors.Escalate(err, "parsing miner address")
|
|
||||||
}
|
|
||||||
|
|
||||||
has, aerr := MinerSetHas(vmctx, self.Miners, maddr)
|
|
||||||
if aerr != nil {
|
|
||||||
return aerr
|
|
||||||
}
|
|
||||||
|
|
||||||
if !has {
|
|
||||||
forRemoval = append(forRemoval, maddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
span.AddAttributes(trace.StringAttribute("miner", maddr.String()))
|
|
||||||
|
|
||||||
params, err := SerializeParams(&CheckMinerParams{NetworkPower: self.TotalStorage})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ret, err := vmctx.Send(maddr, MAMethods.CheckMiner, types.NewInt(0), params)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(ret) == 0 {
|
|
||||||
return nil // miner is fine
|
|
||||||
}
|
|
||||||
|
|
||||||
var power types.BigInt
|
|
||||||
if err := power.UnmarshalCBOR(bytes.NewReader(ret)); err != nil {
|
|
||||||
return xerrors.Errorf("unmarshaling CheckMiner response (%x): %w", ret, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return aerrors.HandleExternalError(err, "iterating miners in proving bucket")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(forRemoval) > 0 {
|
|
||||||
nBucket, err := MinerSetRemove(vmctx.Context(), vmctx, bucket, forRemoval...)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return aerrors.Wrap(err, "could not remove miners from set")
|
|
||||||
}
|
|
||||||
|
|
||||||
eerr := buckets.Set(ctx, bucketID, nBucket)
|
|
||||||
if err != nil {
|
|
||||||
return aerrors.HandleExternalError(eerr, "could not set the bucket")
|
|
||||||
}
|
|
||||||
ncid, eerr := buckets.Flush(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return aerrors.HandleExternalError(eerr, "could not flush buckets")
|
|
||||||
}
|
|
||||||
self.ProvingBuckets = ncid
|
|
||||||
}
|
|
||||||
|
|
||||||
return 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 {
|
|
||||||
return false, aerrors.HandleExternalError(err, "failed to load miner set")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = nd.Find(vmctx.Context(), string(maddr.Bytes()), nil)
|
|
||||||
switch err {
|
|
||||||
case hamt.ErrNotFound:
|
|
||||||
return false, nil
|
|
||||||
case nil:
|
|
||||||
return true, nil
|
|
||||||
default:
|
|
||||||
return false, aerrors.HandleExternalError(err, "failed to do set lookup")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func MinerSetList(ctx context.Context, cst cbor.IpldStore, rcid cid.Cid) ([]address.Address, error) {
|
|
||||||
nd, err := hamt.LoadNode(ctx, cst, rcid)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to load miner set: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var out []address.Address
|
|
||||||
err = nd.ForEach(ctx, func(k string, val interface{}) error {
|
|
||||||
addr, err := address.NewFromBytes([]byte(k))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
out = append(out, addr)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func MinerSetAdd(ctx context.Context, vmctx types.VMContext, rcid cid.Cid, maddr address.Address) (cid.Cid, aerrors.ActorError) {
|
|
||||||
nd, err := hamt.LoadNode(ctx, vmctx.Ipld(), rcid)
|
|
||||||
if err != nil {
|
|
||||||
return cid.Undef, aerrors.HandleExternalError(err, "failed to load miner set")
|
|
||||||
}
|
|
||||||
|
|
||||||
mkey := string(maddr.Bytes())
|
|
||||||
err = nd.Find(ctx, mkey, nil)
|
|
||||||
if err == nil {
|
|
||||||
return cid.Undef, aerrors.New(20, "miner already in set")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !xerrors.Is(err, hamt.ErrNotFound) {
|
|
||||||
return cid.Undef, aerrors.HandleExternalError(err, "failed to do miner set check")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := nd.Set(ctx, mkey, uint64(1)); err != nil {
|
|
||||||
return cid.Undef, aerrors.HandleExternalError(err, "adding miner address to set failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := nd.Flush(ctx); err != nil {
|
|
||||||
return cid.Undef, aerrors.HandleExternalError(err, "failed to flush miner set")
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := vmctx.Ipld().Put(ctx, nd)
|
|
||||||
if err != nil {
|
|
||||||
return cid.Undef, aerrors.HandleExternalError(err, "failed to persist miner set to storage")
|
|
||||||
}
|
|
||||||
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func MinerSetRemove(ctx context.Context, vmctx types.VMContext, rcid cid.Cid, maddrs ...address.Address) (cid.Cid, aerrors.ActorError) {
|
|
||||||
nd, err := hamt.LoadNode(ctx, vmctx.Ipld(), rcid)
|
|
||||||
if err != nil {
|
|
||||||
return cid.Undef, aerrors.HandleExternalError(err, "failed to load miner set")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, maddr := range maddrs {
|
|
||||||
mkey := string(maddr.Bytes())
|
|
||||||
switch nd.Delete(ctx, mkey) {
|
|
||||||
default:
|
|
||||||
return cid.Undef, aerrors.HandleExternalError(err, "failed to delete miner from set")
|
|
||||||
case hamt.ErrNotFound:
|
|
||||||
return cid.Undef, aerrors.New(1, "miner not found in set on delete")
|
|
||||||
case nil:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := nd.Flush(ctx); err != nil {
|
|
||||||
return cid.Undef, aerrors.HandleExternalError(err, "failed to flush miner set")
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := vmctx.Ipld().Put(ctx, nd)
|
|
||||||
if err != nil {
|
|
||||||
return cid.Undef, aerrors.HandleExternalError(err, "failed to persist miner set to storage")
|
|
||||||
}
|
|
||||||
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type cbgNull struct{}
|
|
||||||
|
|
||||||
var CborNull = &cbgNull{}
|
|
||||||
|
|
||||||
func (cbgNull) MarshalCBOR(w io.Writer) error {
|
|
||||||
n, err := w.Write(cbg.CborNull)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if n != 1 {
|
|
||||||
return xerrors.New("expected to write 1 byte")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cbgNull) UnmarshalCBOR(r io.Reader) error {
|
|
||||||
b := [1]byte{}
|
|
||||||
n, err := r.Read(b[:])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if n != 1 {
|
|
||||||
return xerrors.New("expected 1 byte")
|
|
||||||
}
|
|
||||||
if !bytes.Equal(b[:], cbg.CborNull) {
|
|
||||||
return xerrors.New("expected cbor null")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
@ -178,11 +179,12 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.Bl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// all block miners created a valid post, go update the actor state
|
// all block miners created a valid post, go update the actor state
|
||||||
|
panic("sys actor call")
|
||||||
postSubmitMsg := &types.Message{
|
postSubmitMsg := &types.Message{
|
||||||
From: actors.NetworkAddress,
|
From: actors.NetworkAddress,
|
||||||
Nonce: netact.Nonce,
|
Nonce: netact.Nonce,
|
||||||
To: b.Miner,
|
To: b.Miner,
|
||||||
Method: actors.MAMethods.SubmitElectionPoSt,
|
Method: builtin.MethodsMiner.OnVerifiedElectionPoSt,
|
||||||
GasPrice: types.NewInt(0),
|
GasPrice: types.NewInt(0),
|
||||||
GasLimit: types.NewInt(10000000000),
|
GasLimit: types.NewInt(10000000000),
|
||||||
Value: types.NewInt(0),
|
Value: types.NewInt(0),
|
||||||
@ -274,7 +276,7 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.Bl
|
|||||||
Value: types.NewInt(0),
|
Value: types.NewInt(0),
|
||||||
GasPrice: types.NewInt(0),
|
GasPrice: types.NewInt(0),
|
||||||
GasLimit: types.NewInt(1 << 30), // Make super sure this is never too little
|
GasLimit: types.NewInt(1 << 30), // Make super sure this is never too little
|
||||||
Method: actors.CAMethods.EpochTick,
|
Method: builtin.MethodsCron.EpochTick,
|
||||||
Params: nil,
|
Params: nil,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -23,10 +23,11 @@ func (cs *ChainStore) Weight(ctx context.Context, ts *types.TipSet) (types.BigIn
|
|||||||
|
|
||||||
// >>> wFunction(totalPowerAtTipset(ts)) * 2^8 <<< + (wFunction(totalPowerAtTipset(ts)) * len(ts.blocks) * wRatio_num * 2^8) / (e * wRatio_den)
|
// >>> wFunction(totalPowerAtTipset(ts)) * 2^8 <<< + (wFunction(totalPowerAtTipset(ts)) * len(ts.blocks) * wRatio_num * 2^8) / (e * wRatio_den)
|
||||||
|
|
||||||
|
panic("TODO")
|
||||||
ret, err := cs.call(ctx, &types.Message{
|
ret, err := cs.call(ctx, &types.Message{
|
||||||
From: actors.StoragePowerAddress,
|
From: actors.StoragePowerAddress,
|
||||||
To: actors.StoragePowerAddress,
|
To: actors.StoragePowerAddress,
|
||||||
Method: actors.SPAMethods.GetTotalStorage,
|
Method: 999, // actors.SPAMethods.GetTotalStorage,
|
||||||
}, ts)
|
}, ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.EmptyInt, xerrors.Errorf("failed to get total power from chain: %w", err)
|
return types.EmptyInt, xerrors.Errorf("failed to get total power from chain: %w", err)
|
||||||
|
@ -680,7 +680,6 @@ func (t *Message) UnmarshalCBOR(r io.Reader) error {
|
|||||||
if maj != cbg.MajUnsignedInt {
|
if maj != cbg.MajUnsignedInt {
|
||||||
return fmt.Errorf("wrong type for uint64 field")
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
}
|
}
|
||||||
t.Method = uint64(extra)
|
|
||||||
// t.Params ([]uint8) (slice)
|
// t.Params ([]uint8) (slice)
|
||||||
|
|
||||||
maj, extra, err = cbg.CborReadHeader(br)
|
maj, extra, err = cbg.CborReadHeader(br)
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
block "github.com/ipfs/go-block-format"
|
block "github.com/ipfs/go-block-format"
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/multiformats/go-multihash"
|
"github.com/multiformats/go-multihash"
|
||||||
@ -22,7 +23,7 @@ type Message struct {
|
|||||||
GasPrice BigInt
|
GasPrice BigInt
|
||||||
GasLimit BigInt
|
GasLimit BigInt
|
||||||
|
|
||||||
Method uint64 // TODO: decide
|
Method abi.MethodNum
|
||||||
Params []byte
|
Params []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ type VMContext interface {
|
|||||||
Message() *Message
|
Message() *Message
|
||||||
Origin() address.Address
|
Origin() address.Address
|
||||||
Ipld() cbor.IpldStore
|
Ipld() cbor.IpldStore
|
||||||
Send(to address.Address, method uint64, value BigInt, params []byte) ([]byte, aerrors.ActorError)
|
Send(to address.Address, method abi.MethodNum, value BigInt, params []byte) ([]byte, aerrors.ActorError)
|
||||||
BlockHeight() abi.ChainEpoch
|
BlockHeight() abi.ChainEpoch
|
||||||
GasUsed() BigInt
|
GasUsed() BigInt
|
||||||
Storage() Storage
|
Storage() Storage
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
@ -47,7 +48,7 @@ func NewInvoker() *invoker {
|
|||||||
return inv
|
return inv
|
||||||
}
|
}
|
||||||
|
|
||||||
func (inv *invoker) Invoke(act *types.Actor, vmctx types.VMContext, method uint64, params []byte) ([]byte, aerrors.ActorError) {
|
func (inv *invoker) Invoke(act *types.Actor, vmctx types.VMContext, method abi.MethodNum, params []byte) ([]byte, aerrors.ActorError) {
|
||||||
|
|
||||||
if act.Code == actors.AccountCodeCid {
|
if act.Code == actors.AccountCodeCid {
|
||||||
return nil, aerrors.Newf(254, "cannot invoke methods on account actors")
|
return nil, aerrors.Newf(254, "cannot invoke methods on account actors")
|
||||||
@ -58,7 +59,7 @@ func (inv *invoker) Invoke(act *types.Actor, vmctx types.VMContext, method uint6
|
|||||||
log.Errorf("no code for actor %s (Addr: %s)", act.Code, vmctx.Message().To)
|
log.Errorf("no code for actor %s (Addr: %s)", act.Code, vmctx.Message().To)
|
||||||
return nil, aerrors.Newf(255, "no code for actor %s(%d)(%s)", act.Code, method, hex.EncodeToString(params))
|
return nil, aerrors.Newf(255, "no code for actor %s(%d)(%s)", act.Code, method, hex.EncodeToString(params))
|
||||||
}
|
}
|
||||||
if method >= uint64(len(code)) || code[method] == nil {
|
if method >= abi.MethodNum(len(code)) || code[method] == nil {
|
||||||
return nil, aerrors.Newf(255, "no method %d on actor", method)
|
return nil, aerrors.Newf(255, "no method %d on actor", method)
|
||||||
}
|
}
|
||||||
return code[method](act, vmctx, params)
|
return code[method](act, vmctx, params)
|
||||||
|
@ -128,7 +128,7 @@ func (rs *runtimeShim) Send(to address.Address, method abi.MethodNum, m runtime.
|
|||||||
rs.Abort(exitcode.SysErrInvalidParameters, "failed to marshal input parameters: %s", err)
|
rs.Abort(exitcode.SysErrInvalidParameters, "failed to marshal input parameters: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ret, err := rs.vmctx.Send(to, uint64(method), types.BigInt(value), buf.Bytes())
|
ret, err := rs.vmctx.Send(to, method, types.BigInt(value), buf.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.IsFatal() {
|
if err.IsFatal() {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -134,7 +134,7 @@ func (vmc *VMContext) Origin() address.Address {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send allows the current execution context to invoke methods on other actors in the system
|
// Send allows the current execution context to invoke methods on other actors in the system
|
||||||
func (vmc *VMContext) Send(to address.Address, method uint64, value types.BigInt, params []byte) ([]byte, aerrors.ActorError) {
|
func (vmc *VMContext) Send(to address.Address, method abi.MethodNum, value types.BigInt, params []byte) ([]byte, aerrors.ActorError) {
|
||||||
ctx, span := trace.StartSpan(vmc.ctx, "vmc.Send")
|
ctx, span := trace.StartSpan(vmc.ctx, "vmc.Send")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
if span.IsRecordingEvents() {
|
if span.IsRecordingEvents() {
|
||||||
@ -627,7 +627,7 @@ func (vm *VM) SetBlockHeight(h abi.ChainEpoch) {
|
|||||||
vm.blockHeight = h
|
vm.blockHeight = h
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VM) Invoke(act *types.Actor, vmctx *VMContext, method uint64, params []byte) ([]byte, aerrors.ActorError) {
|
func (vm *VM) Invoke(act *types.Actor, vmctx *VMContext, method abi.MethodNum, params []byte) ([]byte, aerrors.ActorError) {
|
||||||
ctx, span := trace.StartSpan(vmctx.ctx, "vm.Invoke")
|
ctx, span := trace.StartSpan(vmctx.ctx, "vm.Invoke")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
if span.IsRecordingEvents() {
|
if span.IsRecordingEvents() {
|
||||||
|
Loading…
Reference in New Issue
Block a user