Mid rework

License: MIT
Signed-off-by: Jakub Sztandera <kubuxu@protonmail.ch>
This commit is contained in:
Jakub Sztandera 2019-07-22 18:08:54 +02:00
parent 02dab3eb51
commit 020fb6f8a3
7 changed files with 78 additions and 68 deletions

View File

@ -6,6 +6,7 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
"github.com/filecoin-project/go-lotus/chain/address" "github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/types" "github.com/filecoin-project/go-lotus/chain/types"
@ -14,7 +15,6 @@ import (
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
logging "github.com/ipfs/go-log" logging "github.com/ipfs/go-log"
mh "github.com/multiformats/go-multihash" mh "github.com/multiformats/go-multihash"
"github.com/pkg/errors"
) )
var log = logging.Logger("actors") var log = logging.Logger("actors")
@ -54,50 +54,37 @@ type ExecParams struct {
Params []byte Params []byte
} }
func (ep *ExecParams) UnmarshalCBOR(b []byte) (int, error) { func CreateExecParams(act cid.Cid, obj interface{}) ([]byte, aerrors.ActorError) {
if err := cbor.DecodeInto(b, ep); err != nil { encparams, err := SerializeParams(obj)
return 0, err
}
return len(b), nil
}
func CreateExecParams(act cid.Cid, obj interface{}) ([]byte, error) {
encparams, err := cbor.DumpObject(obj)
if err != nil { if err != nil {
return nil, err return nil, aerrors.Wrap(err, "creating ExecParams")
} }
var ep ExecParams var ep ExecParams
ep.Code = act ep.Code = act
ep.Params = encparams ep.Params = encparams
return cbor.DumpObject(ep) return SerializeParams(ep)
} }
func (ia InitActor) Exec(act *types.Actor, vmctx types.VMContext, p *ExecParams) (types.InvokeRet, error) { func (ia InitActor) Exec(act *types.Actor, vmctx types.VMContext, p *ExecParams) ([]byte, aerrors.ActorError) {
beginState := vmctx.Storage().GetHead() beginState := vmctx.Storage().GetHead()
var self InitActorState var self InitActorState
if err := vmctx.Storage().Get(beginState, &self); err != nil { if err := vmctx.Storage().Get(beginState, &self); err != nil {
return types.InvokeRet{}, err return nil, err
} }
// Make sure that only the actors defined in the spec can be launched. // Make sure that only the actors defined in the spec can be launched.
if !IsBuiltinActor(p.Code) { if !IsBuiltinActor(p.Code) {
log.Error("cannot launch actor instance that is not a builtin actor") return nil, aerrors.New(1,
return types.InvokeRet{ "cannot launch actor instance that is not a builtin actor")
ReturnCode: 1,
}, nil
} }
// Ensure that singeltons can be only launched once. // Ensure that singeltons can be only launched once.
// TODO: do we want to enforce this? If so how should actors be marked as such? // TODO: do we want to enforce this? If so how should actors be marked as such?
if IsSingletonActor(p.Code) { if IsSingletonActor(p.Code) {
log.Error("cannot launch another actor of this type") return nil, aerrors.New(1, "cannot launch another actor of this type")
return types.InvokeRet{
ReturnCode: 1,
}, nil
} }
// This generates a unique address for this actor that is stable across message // This generates a unique address for this actor that is stable across message
@ -106,7 +93,7 @@ func (ia InitActor) Exec(act *types.Actor, vmctx types.VMContext, p *ExecParams)
nonce := vmctx.Message().Nonce nonce := vmctx.Message().Nonce
addr, err := ComputeActorAddress(creator, nonce) addr, err := ComputeActorAddress(creator, nonce)
if err != nil { if err != nil {
return types.InvokeRet{}, err return nil, err
} }
// Set up the actor itself // Set up the actor itself
@ -118,7 +105,7 @@ func (ia InitActor) Exec(act *types.Actor, vmctx types.VMContext, p *ExecParams)
} }
_, err = vmctx.Storage().Put(struct{}{}) _, err = vmctx.Storage().Put(struct{}{})
if err != nil { if err != nil {
return types.InvokeRet{}, err return nil, err
} }
// The call to the actors constructor will set up the initial state // The call to the actors constructor will set up the initial state
@ -127,39 +114,37 @@ func (ia InitActor) Exec(act *types.Actor, vmctx types.VMContext, p *ExecParams)
//actor.Constructor(p.Params) //actor.Constructor(p.Params)
// Store the mapping of address to actor ID. // Store the mapping of address to actor ID.
idAddr, err := self.AddActor(vmctx, addr) idAddr, nerr := self.AddActor(vmctx, addr)
if err != nil { if nerr != nil {
return types.InvokeRet{}, errors.Wrap(err, "adding new actor mapping") return nil, aerrors.Escalate(err, "adding new actor mapping")
} }
// NOTE: This is a privileged call that only the init actor is allowed to make // 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 // FIXME: Had to comment this because state is not in interface
state, err := vmctx.StateTree() state, err := vmctx.StateTree()
if err != nil { if err != nil {
return types.InvokeRet{}, err return nil, err
} }
if err := state.SetActor(idAddr, &actor); err != nil { if err := state.SetActor(idAddr, &actor); err != nil {
return types.InvokeRet{}, errors.Wrap(err, "inserting new actor into state tree") return nil, aerrors.Wrap(err, "inserting new actor into state tree")
} }
_, _, err = vmctx.Send(idAddr, 0, vmctx.Message().Value, p.Params) _, err = vmctx.Send(idAddr, 0, vmctx.Message().Value, p.Params)
if err != nil { if err != nil {
return types.InvokeRet{}, err return nil, err
} }
c, err := vmctx.Storage().Put(self) c, err := vmctx.Storage().Put(self)
if err != nil { if err != nil {
return types.InvokeRet{}, err return nil, err
} }
if err := vmctx.Storage().Commit(beginState, c); err != nil { if err := vmctx.Storage().Commit(beginState, c); err != nil {
return types.InvokeRet{}, err return nil, err
} }
return types.InvokeRet{ return idAddr.Bytes(), nil
Result: idAddr.Bytes(),
}, nil
} }
func IsBuiltinActor(code cid.Cid) bool { func IsBuiltinActor(code cid.Cid) bool {
@ -198,7 +183,7 @@ func (ias *InitActorState) AddActor(vmctx types.VMContext, addr address.Address)
} }
ias.AddressMap = ncid ias.AddressMap = ncid
return address.NewIDAddress(nid) return NewIDAddress(nid)
} }
func (ias *InitActorState) Lookup(cst *hamt.CborIpldStore, addr address.Address) (address.Address, error) { func (ias *InitActorState) Lookup(cst *hamt.CborIpldStore, addr address.Address) (address.Address, error) {
@ -224,17 +209,21 @@ type AccountActorState struct {
Address address.Address Address address.Address
} }
func ComputeActorAddress(creator address.Address, nonce uint64) (address.Address, error) { func ComputeActorAddress(creator address.Address, nonce uint64) (address.Address, ActorError) {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
_, err := buf.Write(creator.Bytes()) _, err := buf.Write(creator.Bytes())
if err != nil { if err != nil {
return address.Address{}, err return address.Undef, aerrors.Escalate(err, "could not write address")
} }
err = binary.Write(buf, binary.BigEndian, nonce) err = binary.Write(buf, binary.BigEndian, nonce)
if err != nil { if err != nil {
return address.Address{}, err return address.Undef, aerrors.Escalate(err, "could not write nonce")
} }
return address.NewActorAddress(buf.Bytes()) addr, err := address.NewActorAddress(buf.Bytes())
if err != nil {
return address.Undef, aerrors.Escalate(err, "could not create address")
}
return addr, nil
} }

View File

@ -63,19 +63,13 @@ func (sma StorageMarketActor) CreateStorageMiner(act *types.Actor, vmctx types.V
return types.InvokeRet{}, err return types.InvokeRet{}, err
} }
ret, exit, err := vmctx.Send(InitActorAddress, 1, vmctx.Message().Value, encoded) ret, err := vmctx.Send(InitActorAddress, 1, vmctx.Message().Value, encoded)
if err != nil { if err != nil {
return types.InvokeRet{}, err return types.InvokeRet{}, err
} }
if exit != 0 { naddr, nerr := address.NewFromBytes(ret)
return types.InvokeRet{ if nerr != nil {
ReturnCode: 2,
}, nil
}
naddr, err := address.NewFromBytes(ret)
if err != nil {
return types.InvokeRet{}, err return types.InvokeRet{}, err
} }
@ -158,18 +152,11 @@ func (sma StorageMarketActor) PowerLookup(act *types.Actor, vmctx types.VMContex
}, nil }, nil
} }
ret, code, err := vmctx.Send(params.Miner, 9, types.NewInt(0), EmptyStructCBOR) ret, err := vmctx.Send(params.Miner, 9, types.NewInt(0), EmptyStructCBOR)
if err != nil { if err != nil {
return types.InvokeRet{}, xerrors.Errorf("invoke Miner.GetPower: %w", err) return types.InvokeRet{}, xerrors.Errorf("invoke Miner.GetPower: %w", err)
} }
if code != 0 {
return types.InvokeRet{
// TODO: error handling... these codes really don't tell us what the problem is very well
ReturnCode: code,
}, nil
}
return types.InvokeRet{ return types.InvokeRet{
Result: ret, Result: ret,
}, nil }, nil

14
chain/actors/address.go Normal file
View File

@ -0,0 +1,14 @@
package actors
import (
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
"github.com/filecoin-project/go-lotus/chain/address"
)
func NewIDAddress(id uint64) (address.Address, ActorError) {
a, err := address.NewIDAddress(id)
if err != nil {
return address.Undef, aerrors.Escalate(err, "could not create ID Address")
}
return a, nil
}

View File

@ -6,6 +6,15 @@ import (
"golang.org/x/xerrors" "golang.org/x/xerrors"
) )
func New(retCode uint8, message string) ActorError {
return &actorError{
retCode: retCode,
msg: message,
frame: xerrors.Caller(1),
}
}
func Wrap(err ActorError, message string) ActorError { func Wrap(err ActorError, message string) ActorError {
if err == nil { if err == nil {
return nil return nil

5
chain/actors/error.go Normal file
View File

@ -0,0 +1,5 @@
package actors
import "github.com/filecoin-project/go-lotus/chain/actors/aerrors"
type ActorError = aerrors.ActorError

View File

@ -1,6 +1,7 @@
package actors package actors
import ( import (
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
) )
@ -8,6 +9,10 @@ var (
EmptyStructCBOR = []byte{0xa0} EmptyStructCBOR = []byte{0xa0}
) )
func SerializeParams(i interface{}) ([]byte, error) { func SerializeParams(i interface{}) ([]byte, aerrors.ActorError) {
return cbor.DumpObject(i) dump, err := cbor.DumpObject(i)
if err != nil {
return nil, aerrors.Absorb(err, 1, "failed to encode parameter")
}
return dump, nil
} }

View File

@ -1,34 +1,35 @@
package types package types
import ( import (
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
"github.com/filecoin-project/go-lotus/chain/address" "github.com/filecoin-project/go-lotus/chain/address"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"github.com/ipfs/go-hamt-ipld" "github.com/ipfs/go-hamt-ipld"
) )
type Storage interface { type Storage interface {
Put(interface{}) (cid.Cid, error) Put(interface{}) (cid.Cid, aerrors.ActorError)
Get(cid.Cid, interface{}) error Get(cid.Cid, interface{}) aerrors.ActorError
GetHead() cid.Cid GetHead() cid.Cid
// Commit sets the new head of the actors state as long as the current // Commit sets the new head of the actors state as long as the current
// state matches 'oldh' // state matches 'oldh'
Commit(oldh cid.Cid, newh cid.Cid) error Commit(oldh cid.Cid, newh cid.Cid) aerrors.ActorError
} }
type StateTree interface { type StateTree interface {
SetActor(addr address.Address, act *Actor) error SetActor(addr address.Address, act *Actor) aerrors.ActorError
GetActor(addr address.Address) (*Actor, error) GetActor(addr address.Address) (*Actor, aerrors.ActorError)
} }
type VMContext interface { type VMContext interface {
Message() *Message Message() *Message
Origin() address.Address Origin() address.Address
Ipld() *hamt.CborIpldStore Ipld() *hamt.CborIpldStore
Send(to address.Address, method uint64, value BigInt, params []byte) ([]byte, uint8, error) Send(to address.Address, method uint64, value BigInt, params []byte) ([]byte, aerrors.ActorError)
BlockHeight() uint64 BlockHeight() uint64
GasUsed() BigInt GasUsed() BigInt
Storage() Storage Storage() Storage
StateTree() (StateTree, error) StateTree() (StateTree, aerrors.ActorError)
} }