From 96023d415efcc3dd191c555ea48821ea5df0b809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Fri, 22 Nov 2019 23:51:44 +0100 Subject: [PATCH] actors: Implement cron actor --- chain/actors/actor_cron.go | 48 ++++++++++++++++++++++++++++++ chain/actors/actor_init.go | 2 +- chain/actors/actor_storagepower.go | 4 +-- chain/actors/actors.go | 3 ++ chain/actors/cbor_gen.go | 29 ++++++++++++++++++ chain/blocksync/cbor_gen.go | 2 +- chain/gen/utils.go | 26 ++++++++++++++++ chain/stmgr/stmgr.go | 13 ++++---- chain/types/cbor_gen.go | 2 +- chain/vm/invoker.go | 1 + gen/main.go | 1 + 11 files changed, 119 insertions(+), 12 deletions(-) create mode 100644 chain/actors/actor_cron.go diff --git a/chain/actors/actor_cron.go b/chain/actors/actor_cron.go new file mode 100644 index 000000000..8f9a08ade --- /dev/null +++ b/chain/actors/actor_cron.go @@ -0,0 +1,48 @@ +package actors + +import ( + "github.com/filecoin-project/lotus/chain/actors/aerrors" + "github.com/filecoin-project/lotus/chain/address" + "github.com/filecoin-project/lotus/chain/types" +) + +type CronActor struct{} + +type callTuple struct { + 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 +} diff --git a/chain/actors/actor_init.go b/chain/actors/actor_init.go index 66d9d98fa..e040e5899 100644 --- a/chain/actors/actor_init.go +++ b/chain/actors/actor_init.go @@ -170,7 +170,7 @@ func IsBuiltinActor(code cid.Cid) bool { } func IsSingletonActor(code cid.Cid) bool { - return code == StoragePowerCodeCid || code == StorageMarketCodeCid || code == InitCodeCid + return code == StoragePowerCodeCid || code == StorageMarketCodeCid || code == InitCodeCid || code == CronCodeCid } func (ias *InitActorState) AddActor(cst *hamt.CborIpldStore, addr address.Address) (address.Address, error) { diff --git a/chain/actors/actor_storagepower.go b/chain/actors/actor_storagepower.go index e76cdd054..1e2b1915b 100644 --- a/chain/actors/actor_storagepower.go +++ b/chain/actors/actor_storagepower.go @@ -567,8 +567,8 @@ func pledgeCollateralForSize(vmctx types.VMContext, size, totalStorage types.Big } 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") + if vmctx.Message().From != CronAddress { + return nil, aerrors.New(1, "CheckProofSubmissions is only callable from the cron actor") } var self StoragePowerState diff --git a/chain/actors/actors.go b/chain/actors/actors.go index fe111c125..19de6a383 100644 --- a/chain/actors/actors.go +++ b/chain/actors/actors.go @@ -8,6 +8,7 @@ import ( ) var AccountCodeCid cid.Cid +var CronCodeCid cid.Cid var StoragePowerCodeCid cid.Cid var StorageMarketCodeCid cid.Cid var StorageMinerCodeCid cid.Cid @@ -19,6 +20,7 @@ var InitAddress = mustIDAddress(0) var NetworkAddress = mustIDAddress(1) var StoragePowerAddress = mustIDAddress(2) var StorageMarketAddress = mustIDAddress(3) // TODO: missing from spec +var CronAddress = mustIDAddress(4) var BurntFundsAddress = mustIDAddress(99) func mustIDAddress(i uint64) address.Address { @@ -40,6 +42,7 @@ func init() { } AccountCodeCid = mustSum("fil/1/account") // TODO: spec + CronCodeCid = mustSum("fil/1/cron") StoragePowerCodeCid = mustSum("fil/1/power") StorageMarketCodeCid = mustSum("fil/1/market") StorageMinerCodeCid = mustSum("fil/1/miner") diff --git a/chain/actors/cbor_gen.go b/chain/actors/cbor_gen.go index 53de185e1..2dee0debd 100644 --- a/chain/actors/cbor_gen.go +++ b/chain/actors/cbor_gen.go @@ -3976,3 +3976,32 @@ func (t *CheckMinerParams) UnmarshalCBOR(r io.Reader) error { } return nil } + +func (t *CronActorState) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{128}); err != nil { + return err + } + return nil +} + +func (t *CronActorState) 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 != 0 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + return nil +} diff --git a/chain/blocksync/cbor_gen.go b/chain/blocksync/cbor_gen.go index 579b3f857..4af61a490 100644 --- a/chain/blocksync/cbor_gen.go +++ b/chain/blocksync/cbor_gen.go @@ -5,7 +5,7 @@ import ( "io" "github.com/filecoin-project/lotus/chain/types" - cid "github.com/ipfs/go-cid" + "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" xerrors "golang.org/x/xerrors" ) diff --git a/chain/gen/utils.go b/chain/gen/utils.go index f60da262d..cd7f6834b 100644 --- a/chain/gen/utils.go +++ b/chain/gen/utils.go @@ -89,6 +89,15 @@ func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types return nil, xerrors.Errorf("set init actor: %w", err) } + cronact, err := SetupCronActor(bs) + if err != nil { + return nil, xerrors.Errorf("setup cron actor: %w", err) + } + + if err := state.SetActor(actors.CronAddress, cronact); err != nil { + return nil, xerrors.Errorf("set cron actor: %w", err) + } + spact, err := SetupStoragePowerActor(bs) if err != nil { return nil, xerrors.Errorf("setup storage market actor: %w", err) @@ -144,6 +153,23 @@ func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types return state, nil } +func SetupCronActor(bs bstore.Blockstore) (*types.Actor, error) { + cst := hamt.CSTFromBstore(bs) + cas := &actors.CronActorState{} + + stcid, err := cst.Put(context.TODO(), cas) + if err != nil { + return nil, err + } + + return &types.Actor{ + Code: actors.CronCodeCid, + Head: stcid, + Nonce: 0, + Balance: types.NewInt(0), + }, nil +} + func SetupStoragePowerActor(bs bstore.Blockstore) (*types.Actor, error) { cst := hamt.CSTFromBstore(bs) nd := hamt.NewNode(cst) diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index eaaa4fc13..62efca8a6 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -197,21 +197,20 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.Bl } } - // TODO: this nonce-getting is a ting bit ugly - spa, err := vmi.StateTree().GetActor(actors.StoragePowerAddress) + // TODO: this nonce-getting is a tiny bit ugly + ca, err := vmi.StateTree().GetActor(actors.CronAddress) if err != nil { return cid.Undef, cid.Undef, err } - // TODO: cron actor ret, err := vmi.ApplyMessage(ctx, &types.Message{ - To: actors.StoragePowerAddress, - From: actors.StoragePowerAddress, - Nonce: spa.Nonce, + To: actors.CronAddress, + From: actors.CronAddress, + Nonce: ca.Nonce, Value: types.NewInt(0), GasPrice: types.NewInt(0), GasLimit: types.NewInt(1 << 30), // Make super sure this is never too little - Method: actors.SPAMethods.CheckProofSubmissions, + Method: actors.CAMethods.EpochTick, Params: nil, }) if err != nil { diff --git a/chain/types/cbor_gen.go b/chain/types/cbor_gen.go index fa3cddaf4..1ebe94a13 100644 --- a/chain/types/cbor_gen.go +++ b/chain/types/cbor_gen.go @@ -5,7 +5,7 @@ import ( "io" "math" - cid "github.com/ipfs/go-cid" + "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" xerrors "golang.org/x/xerrors" ) diff --git a/chain/vm/invoker.go b/chain/vm/invoker.go index 3fa02d4c1..d33f70750 100644 --- a/chain/vm/invoker.go +++ b/chain/vm/invoker.go @@ -31,6 +31,7 @@ func newInvoker() *invoker { // add builtInCode using: register(cid, singleton) inv.register(actors.InitCodeCid, actors.InitActor{}, actors.InitActorState{}) + inv.register(actors.CronCodeCid, actors.CronActor{}, actors.CronActorState{}) inv.register(actors.StoragePowerCodeCid, actors.StoragePowerActor{}, actors.StoragePowerState{}) inv.register(actors.StorageMarketCodeCid, actors.StorageMarketActor{}, actors.StorageMarketState{}) inv.register(actors.StorageMinerCodeCid, actors.StorageMinerActor{}, actors.StorageMinerActorState{}) diff --git a/gen/main.go b/gen/main.go index c74a10f0f..98f4424ca 100644 --- a/gen/main.go +++ b/gen/main.go @@ -129,6 +129,7 @@ func main() { actors.ComputeDataCommitmentParams{}, actors.SectorProveCommitInfo{}, actors.CheckMinerParams{}, + actors.CronActorState{}, ) if err != nil { fmt.Println(err)