actors: Wire up specs-actors init
This commit is contained in:
parent
ca3eabafef
commit
22047d20ef
@ -1,237 +1,12 @@
|
|||||||
package actors
|
package actors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
|
||||||
"golang.org/x/xerrors"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
|
||||||
"github.com/ipfs/go-hamt-ipld"
|
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
|
||||||
logging "github.com/ipfs/go-log/v2"
|
logging "github.com/ipfs/go-log/v2"
|
||||||
mh "github.com/multiformats/go-multihash"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = logging.Logger("actors")
|
var log = logging.Logger("actors")
|
||||||
|
|
||||||
var EmptyCBOR cid.Cid
|
type InitActor = init_.Actor
|
||||||
|
|
||||||
const (
|
|
||||||
GasCreateActor = 100
|
|
||||||
)
|
|
||||||
|
|
||||||
var BuiltInActors map[cid.Cid]bool
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
|
|
||||||
n, err := cbor.WrapObject(map[string]string{}, mh.SHA2_256, -1)
|
|
||||||
if err != nil {
|
|
||||||
panic(err) // ok
|
|
||||||
}
|
|
||||||
|
|
||||||
EmptyCBOR = n.Cid()
|
|
||||||
}
|
|
||||||
|
|
||||||
type InitActor struct{}
|
|
||||||
|
|
||||||
type InitActorState = init_.State
|
type InitActorState = init_.State
|
||||||
|
|
||||||
type iAMethods struct {
|
|
||||||
Exec uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
var IAMethods = iAMethods{2}
|
|
||||||
|
|
||||||
func (ia InitActor) Exports() []interface{} {
|
|
||||||
return []interface{}{
|
|
||||||
1: nil,
|
|
||||||
2: ia.Exec,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ExecParams struct {
|
|
||||||
Code cid.Cid
|
|
||||||
Params []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func CreateExecParams(act cid.Cid, obj cbg.CBORMarshaler) ([]byte, aerrors.ActorError) {
|
|
||||||
encparams, err := SerializeParams(obj)
|
|
||||||
if err != nil {
|
|
||||||
return nil, aerrors.Wrap(err, "creating ExecParams")
|
|
||||||
}
|
|
||||||
|
|
||||||
return SerializeParams(&ExecParams{
|
|
||||||
Code: act,
|
|
||||||
Params: encparams,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ia InitActor) Exec(act *types.Actor, vmctx types.VMContext, p *ExecParams) ([]byte, aerrors.ActorError) {
|
|
||||||
beginState := vmctx.Storage().GetHead()
|
|
||||||
|
|
||||||
var self InitActorState
|
|
||||||
if err := vmctx.Storage().Get(beginState, &self); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := vmctx.ChargeGas(GasCreateActor); err != nil {
|
|
||||||
return nil, aerrors.Wrap(err, "run out of gas")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure that only the actors defined in the spec can be launched.
|
|
||||||
if !IsBuiltinActor(p.Code) {
|
|
||||||
return nil, aerrors.New(1,
|
|
||||||
"cannot launch actor instance that is not a builtin actor")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that singletons can be only launched once.
|
|
||||||
// TODO: do we want to enforce this? If so how should actors be marked as such?
|
|
||||||
if IsSingletonActor(p.Code) {
|
|
||||||
return nil, aerrors.New(1, "cannot launch another actor of this type")
|
|
||||||
}
|
|
||||||
|
|
||||||
// This generates a unique address for this actor that is stable across message
|
|
||||||
// reordering
|
|
||||||
creator := vmctx.Message().From
|
|
||||||
nonce := vmctx.Message().Nonce
|
|
||||||
addr, err := ComputeActorAddress(creator, nonce)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up the actor itself
|
|
||||||
actor := types.Actor{
|
|
||||||
Code: p.Code,
|
|
||||||
Balance: types.NewInt(0),
|
|
||||||
Head: EmptyCBOR,
|
|
||||||
Nonce: 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
// The call to the actors constructor will set up the initial state
|
|
||||||
// from the given parameters, setting `actor.Head` to a new value when successful.
|
|
||||||
// TODO: can constructors fail?
|
|
||||||
//actor.Constructor(p.Params)
|
|
||||||
|
|
||||||
// Store the mapping of address to actor ID.
|
|
||||||
idAddr, nerr := self.AddActor(vmctx.Ipld(), addr)
|
|
||||||
if nerr != nil {
|
|
||||||
return nil, aerrors.Escalate(err, "adding new actor mapping")
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: This is a privileged call that only the init actor is allowed to make
|
|
||||||
// FIXME: Had to comment this because state is not in interface
|
|
||||||
state, err := vmctx.StateTree()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := state.SetActor(idAddr, &actor); err != nil {
|
|
||||||
if xerrors.Is(err, types.ErrActorNotFound) {
|
|
||||||
return nil, aerrors.Absorb(err, 1, "SetActor, actor not found")
|
|
||||||
}
|
|
||||||
return nil, aerrors.Escalate(err, "inserting new actor into state tree")
|
|
||||||
}
|
|
||||||
|
|
||||||
// '1' is reserved for constructor methods
|
|
||||||
_, err = vmctx.Send(idAddr, 1, vmctx.Message().Value, p.Params)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := vmctx.Storage().Put(&self)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := vmctx.Storage().Commit(beginState, c); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return idAddr.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsBuiltinActor(code cid.Cid) bool {
|
|
||||||
return BuiltInActors[code]
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsSingletonActor(code cid.Cid) bool {
|
|
||||||
return code == StoragePowerCodeCid || code == StorageMarketCodeCid || code == InitCodeCid || code == CronCodeCid
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ias *InitActorState) AddActor(cst cbor.IpldStore, addr address.Address) (address.Address, error) {
|
|
||||||
nid := ias.NextID
|
|
||||||
|
|
||||||
amap, err := hamt.LoadNode(context.TODO(), cst, ias.AddressMap)
|
|
||||||
if err != nil {
|
|
||||||
return address.Undef, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := amap.Set(context.TODO(), string(addr.Bytes()), nid); err != nil {
|
|
||||||
return address.Undef, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := amap.Flush(context.TODO()); err != nil {
|
|
||||||
return address.Undef, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ncid, err := cst.Put(context.TODO(), amap)
|
|
||||||
if err != nil {
|
|
||||||
return address.Undef, err
|
|
||||||
}
|
|
||||||
ias.AddressMap = ncid
|
|
||||||
ias.NextID++
|
|
||||||
|
|
||||||
return NewIDAddress(nid)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ias *InitActorState) Lookup(cst cbor.IpldStore, addr address.Address) (address.Address, error) {
|
|
||||||
amap, err := hamt.LoadNode(context.TODO(), cst, ias.AddressMap)
|
|
||||||
if err != nil {
|
|
||||||
return address.Undef, xerrors.Errorf("ias lookup failed loading hamt node: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var val interface{}
|
|
||||||
err = amap.Find(context.TODO(), string(addr.Bytes()), &val)
|
|
||||||
if err != nil {
|
|
||||||
return address.Undef, xerrors.Errorf("ias lookup failed to do find: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ival, ok := val.(uint64)
|
|
||||||
if !ok {
|
|
||||||
return address.Undef, fmt.Errorf("invalid value in init actor state, expected uint64, got %T", val)
|
|
||||||
}
|
|
||||||
|
|
||||||
return address.NewIDAddress(ival)
|
|
||||||
}
|
|
||||||
|
|
||||||
type AccountActorState struct {
|
|
||||||
Address address.Address
|
|
||||||
}
|
|
||||||
|
|
||||||
func ComputeActorAddress(creator address.Address, nonce uint64) (address.Address, ActorError) {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
_, err := buf.Write(creator.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
return address.Undef, aerrors.Escalate(err, "could not write address")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = binary.Write(buf, binary.BigEndian, nonce)
|
|
||||||
if err != nil {
|
|
||||||
return address.Undef, aerrors.Escalate(err, "could not write nonce")
|
|
||||||
}
|
|
||||||
|
|
||||||
addr, err := address.NewActorAddress(buf.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
return address.Undef, aerrors.Escalate(err, "could not create address")
|
|
||||||
}
|
|
||||||
return addr, nil
|
|
||||||
}
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
package actors
|
package actors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var AccountCodeCid = builtin.AccountActorCodeID
|
var AccountCodeCid = builtin.AccountActorCodeID
|
||||||
@ -23,34 +20,3 @@ var CronAddress = builtin.CronActorAddr
|
|||||||
var StoragePowerAddress = builtin.StoragePowerActorAddr
|
var StoragePowerAddress = builtin.StoragePowerActorAddr
|
||||||
var StorageMarketAddress = builtin.StorageMarketActorAddr
|
var StorageMarketAddress = builtin.StorageMarketActorAddr
|
||||||
var BurntFundsAddress = builtin.BurntFundsActorAddr
|
var BurntFundsAddress = builtin.BurntFundsActorAddr
|
||||||
|
|
||||||
/*
|
|
||||||
SystemActorAddr = mustMakeAddress(0)
|
|
||||||
InitActorAddr = mustMakeAddress(1)
|
|
||||||
RewardActorAddr = mustMakeAddress(2)
|
|
||||||
CronActorAddr = mustMakeAddress(3)
|
|
||||||
StoragePowerActorAddr = mustMakeAddress(4)
|
|
||||||
StorageMarketActorAddr = mustMakeAddress(5)
|
|
||||||
// Distinguished AccountActor that is the destination of all burnt funds.
|
|
||||||
BurntFundsActorAddr = mustMakeAddress(99)
|
|
||||||
*/
|
|
||||||
|
|
||||||
func mustIDAddress(i uint64) address.Address {
|
|
||||||
a, err := address.NewIDAddress(i)
|
|
||||||
if err != nil {
|
|
||||||
panic(err) // ok
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
BuiltInActors = map[cid.Cid]bool{
|
|
||||||
StorageMarketCodeCid: true,
|
|
||||||
StoragePowerCodeCid: true,
|
|
||||||
StorageMinerCodeCid: true,
|
|
||||||
AccountCodeCid: true,
|
|
||||||
InitCodeCid: true,
|
|
||||||
MultisigCodeCid: true,
|
|
||||||
PaymentChannelCodeCid: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||||
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ActorType string
|
type ActorType string
|
||||||
@ -24,6 +25,7 @@ type PreSeal struct {
|
|||||||
type Miner struct {
|
type Miner struct {
|
||||||
Owner address.Address
|
Owner address.Address
|
||||||
Worker address.Address
|
Worker address.Address
|
||||||
|
PeerId peer.ID
|
||||||
|
|
||||||
MarketBalance abi.TokenAmount
|
MarketBalance abi.TokenAmount
|
||||||
PowerBalance abi.TokenAmount
|
PowerBalance abi.TokenAmount
|
||||||
|
Loading…
Reference in New Issue
Block a user