Merge pull request #66 from filecoin-project/errors/oh-errors
Create actor error type
This commit is contained in:
commit
38102b28c6
@ -6,15 +6,16 @@ import (
|
||||
"encoding/binary"
|
||||
"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/types"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
logging "github.com/ipfs/go-log"
|
||||
mh "github.com/multiformats/go-multihash"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var log = logging.Logger("actors")
|
||||
@ -54,50 +55,37 @@ type ExecParams struct {
|
||||
Params []byte
|
||||
}
|
||||
|
||||
func (ep *ExecParams) UnmarshalCBOR(b []byte) (int, error) {
|
||||
if err := cbor.DecodeInto(b, ep); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func CreateExecParams(act cid.Cid, obj interface{}) ([]byte, error) {
|
||||
encparams, err := cbor.DumpObject(obj)
|
||||
func CreateExecParams(act cid.Cid, obj interface{}) ([]byte, aerrors.ActorError) {
|
||||
encparams, err := SerializeParams(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, aerrors.Wrap(err, "creating ExecParams")
|
||||
}
|
||||
|
||||
var ep ExecParams
|
||||
ep.Code = act
|
||||
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()
|
||||
|
||||
var self InitActorState
|
||||
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.
|
||||
if !IsBuiltinActor(p.Code) {
|
||||
log.Error("cannot launch actor instance that is not a builtin actor")
|
||||
return types.InvokeRet{
|
||||
ReturnCode: 1,
|
||||
}, nil
|
||||
return nil, aerrors.New(1,
|
||||
"cannot launch actor instance that is not a builtin actor")
|
||||
}
|
||||
|
||||
// Ensure that singeltons 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) {
|
||||
log.Error("cannot launch another actor of this type")
|
||||
return types.InvokeRet{
|
||||
ReturnCode: 1,
|
||||
}, nil
|
||||
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
|
||||
@ -106,7 +94,7 @@ func (ia InitActor) Exec(act *types.Actor, vmctx types.VMContext, p *ExecParams)
|
||||
nonce := vmctx.Message().Nonce
|
||||
addr, err := ComputeActorAddress(creator, nonce)
|
||||
if err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set up the actor itself
|
||||
@ -118,7 +106,7 @@ func (ia InitActor) Exec(act *types.Actor, vmctx types.VMContext, p *ExecParams)
|
||||
}
|
||||
_, err = vmctx.Storage().Put(struct{}{})
|
||||
if err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The call to the actors constructor will set up the initial state
|
||||
@ -127,39 +115,40 @@ func (ia InitActor) Exec(act *types.Actor, vmctx types.VMContext, p *ExecParams)
|
||||
//actor.Constructor(p.Params)
|
||||
|
||||
// Store the mapping of address to actor ID.
|
||||
idAddr, err := self.AddActor(vmctx, addr)
|
||||
if err != nil {
|
||||
return types.InvokeRet{}, errors.Wrap(err, "adding new actor mapping")
|
||||
idAddr, nerr := self.AddActor(vmctx, 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 types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := state.SetActor(idAddr, &actor); err != nil {
|
||||
return types.InvokeRet{}, errors.Wrap(err, "inserting new actor into state tree")
|
||||
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")
|
||||
}
|
||||
|
||||
_, _, err = vmctx.Send(idAddr, 0, vmctx.Message().Value, p.Params)
|
||||
_, err = vmctx.Send(idAddr, 0, vmctx.Message().Value, p.Params)
|
||||
if err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c, err := vmctx.Storage().Put(self)
|
||||
if err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := vmctx.Storage().Commit(beginState, c); err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.InvokeRet{
|
||||
Result: idAddr.Bytes(),
|
||||
}, nil
|
||||
return idAddr.Bytes(), nil
|
||||
}
|
||||
|
||||
func IsBuiltinActor(code cid.Cid) bool {
|
||||
@ -198,7 +187,7 @@ func (ias *InitActorState) AddActor(vmctx types.VMContext, addr address.Address)
|
||||
}
|
||||
ias.AddressMap = ncid
|
||||
|
||||
return address.NewIDAddress(nid)
|
||||
return NewIDAddress(nid)
|
||||
}
|
||||
|
||||
func (ias *InitActorState) Lookup(cst *hamt.CborIpldStore, addr address.Address) (address.Address, error) {
|
||||
@ -224,17 +213,21 @@ type AccountActorState struct {
|
||||
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)
|
||||
_, err := buf.Write(creator.Bytes())
|
||||
if err != nil {
|
||||
return address.Address{}, err
|
||||
return address.Undef, aerrors.Escalate(err, "could not write address")
|
||||
}
|
||||
|
||||
err = binary.Write(buf, binary.BigEndian, nonce)
|
||||
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
|
||||
}
|
||||
|
@ -3,8 +3,10 @@ package actors
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
"github.com/filecoin-project/go-lotus/chain/types"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
@ -106,7 +108,7 @@ func (sma StorageMinerActor) Exports() []interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
func (sma StorageMinerActor) StorageMinerConstructor(act *types.Actor, vmctx types.VMContext, params *StorageMinerConstructorParams) (types.InvokeRet, error) {
|
||||
func (sma StorageMinerActor) StorageMinerConstructor(act *types.Actor, vmctx types.VMContext, params *StorageMinerConstructorParams) ([]byte, ActorError) {
|
||||
var self StorageMinerActorState
|
||||
self.Owner = params.Owner
|
||||
self.Worker = params.Worker
|
||||
@ -114,9 +116,9 @@ func (sma StorageMinerActor) StorageMinerConstructor(act *types.Actor, vmctx typ
|
||||
self.SectorSize = params.SectorSize
|
||||
|
||||
nd := hamt.NewNode(vmctx.Ipld())
|
||||
sectors, err := vmctx.Ipld().Put(context.TODO(), nd)
|
||||
if err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
sectors, nerr := vmctx.Ipld().Put(context.TODO(), nd)
|
||||
if nerr != nil {
|
||||
return nil, aerrors.Escalate(nerr, "could not put in storage")
|
||||
}
|
||||
self.Sectors = sectors
|
||||
self.ProvingSet = sectors
|
||||
@ -124,14 +126,14 @@ func (sma StorageMinerActor) StorageMinerConstructor(act *types.Actor, vmctx typ
|
||||
storage := vmctx.Storage()
|
||||
c, err := storage.Put(self)
|
||||
if err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := storage.Commit(EmptyCBOR, c); err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.InvokeRet{}, nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type CommitSectorParams struct {
|
||||
@ -142,30 +144,24 @@ type CommitSectorParams struct {
|
||||
Proof []byte
|
||||
}
|
||||
|
||||
func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContext, params *CommitSectorParams) (types.InvokeRet, error) {
|
||||
func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContext, params *CommitSectorParams) ([]byte, ActorError) {
|
||||
var self StorageMinerActorState
|
||||
oldstate := vmctx.Storage().GetHead()
|
||||
if err := vmctx.Storage().Get(oldstate, &self); err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !ValidatePoRep(self.SectorSize, params) {
|
||||
//Fatal("bad proof!")
|
||||
return types.InvokeRet{
|
||||
ReturnCode: 1,
|
||||
}, nil
|
||||
return nil, aerrors.New(1, "bad proof!")
|
||||
}
|
||||
|
||||
// make sure the miner isnt trying to submit a pre-existing sector
|
||||
unique, err := SectorIsUnique(vmctx.Ipld(), self.Sectors, params.SectorId)
|
||||
if err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
if !unique {
|
||||
//Fatal("sector already committed!")
|
||||
return types.InvokeRet{
|
||||
ReturnCode: 2,
|
||||
}, nil
|
||||
return nil, aerrors.New(2, "sector already committed!")
|
||||
}
|
||||
|
||||
// Power of the miner after adding this sector
|
||||
@ -173,18 +169,12 @@ func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContex
|
||||
collateralRequired := CollateralForPower(futurePower)
|
||||
|
||||
if types.BigCmp(collateralRequired, act.Balance) < 0 {
|
||||
//Fatal("not enough collateral")
|
||||
return types.InvokeRet{
|
||||
ReturnCode: 3,
|
||||
}, nil
|
||||
return nil, aerrors.New(3, "not enough collateral")
|
||||
}
|
||||
|
||||
// ensure that the miner cannot commit more sectors than can be proved with a single PoSt
|
||||
if self.SectorSetSize >= POST_SECTORS_COUNT {
|
||||
// Fatal("too many sectors")
|
||||
return types.InvokeRet{
|
||||
ReturnCode: 4,
|
||||
}, nil
|
||||
return nil, aerrors.New(4, "too many sectors")
|
||||
}
|
||||
|
||||
// Note: There must exist a unique index in the miner's sector set for each
|
||||
@ -192,7 +182,7 @@ func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContex
|
||||
// SubmitPoSt method express indices into this sector set.
|
||||
nssroot, err := AddToSectorSet(self.Sectors, params.SectorId, params.CommR, params.CommD)
|
||||
if err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
self.Sectors = nssroot
|
||||
|
||||
@ -212,43 +202,41 @@ func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContex
|
||||
|
||||
nstate, err := vmctx.Storage().Put(self)
|
||||
if err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
if err := vmctx.Storage().Commit(oldstate, nstate); err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.InvokeRet{}, nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (sma StorageMinerActor) GetPower(act *types.Actor, vmctx types.VMContext, params *struct{}) (types.InvokeRet, error) {
|
||||
func (sma StorageMinerActor) GetPower(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
||||
var self StorageMinerActorState
|
||||
state := vmctx.Storage().GetHead()
|
||||
if err := vmctx.Storage().Get(state, &self); err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
return types.InvokeRet{
|
||||
Result: self.Power.Bytes(),
|
||||
}, nil
|
||||
return self.Power.Bytes(), nil
|
||||
}
|
||||
|
||||
func SectorIsUnique(cst *hamt.CborIpldStore, sroot cid.Cid, sid types.BigInt) (bool, error) {
|
||||
func SectorIsUnique(cst *hamt.CborIpldStore, sroot cid.Cid, sid types.BigInt) (bool, ActorError) {
|
||||
nd, err := hamt.LoadNode(context.TODO(), cst, sroot)
|
||||
if err != nil {
|
||||
return false, err
|
||||
return false, aerrors.Absorb(err, 1, "could not load node in HAMT")
|
||||
}
|
||||
|
||||
if _, err := nd.Find(context.TODO(), sid.String()); err != nil {
|
||||
if err == hamt.ErrNotFound {
|
||||
if xerrors.Is(err, hamt.ErrNotFound) {
|
||||
return true, nil
|
||||
}
|
||||
return false, err
|
||||
return false, aerrors.Absorb(err, 1, "could not find node in HAMT")
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func AddToSectorSet(ss cid.Cid, sectorID types.BigInt, commR, commD []byte) (cid.Cid, error) {
|
||||
func AddToSectorSet(ss cid.Cid, sectorID types.BigInt, commR, commD []byte) (cid.Cid, ActorError) {
|
||||
panic("NYI")
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
package actors
|
||||
|
||||
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/types"
|
||||
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
const SectorSize = 1024
|
||||
@ -45,12 +45,9 @@ type CreateStorageMinerParams struct {
|
||||
PeerID peer.ID
|
||||
}
|
||||
|
||||
func (sma StorageMarketActor) CreateStorageMiner(act *types.Actor, vmctx types.VMContext, params *CreateStorageMinerParams) (types.InvokeRet, error) {
|
||||
func (sma StorageMarketActor) CreateStorageMiner(act *types.Actor, vmctx types.VMContext, params *CreateStorageMinerParams) ([]byte, ActorError) {
|
||||
if !SupportedSectorSize(params.SectorSize) {
|
||||
//Fatal("Unsupported sector size")
|
||||
return types.InvokeRet{
|
||||
ReturnCode: 1,
|
||||
}, nil
|
||||
return nil, aerrors.New(1, "Unsupported sector size")
|
||||
}
|
||||
|
||||
encoded, err := CreateExecParams(StorageMinerCodeCid, &StorageMinerConstructorParams{
|
||||
@ -60,45 +57,37 @@ func (sma StorageMarketActor) CreateStorageMiner(act *types.Actor, vmctx types.V
|
||||
PeerID: params.PeerID,
|
||||
})
|
||||
if err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, 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 {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if exit != 0 {
|
||||
return types.InvokeRet{
|
||||
ReturnCode: 2,
|
||||
}, nil
|
||||
}
|
||||
|
||||
naddr, err := address.NewFromBytes(ret)
|
||||
if err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
naddr, nerr := address.NewFromBytes(ret)
|
||||
if nerr != nil {
|
||||
return nil, aerrors.Absorb(nerr, 1, "could not read address of new actor")
|
||||
}
|
||||
|
||||
var self StorageMarketState
|
||||
old := vmctx.Storage().GetHead()
|
||||
if err := vmctx.Storage().Get(old, &self); err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
self.Miners[naddr] = struct{}{}
|
||||
|
||||
nroot, err := vmctx.Storage().Put(self)
|
||||
if err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := vmctx.Storage().Commit(old, nroot); err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.InvokeRet{
|
||||
Result: naddr.Bytes(),
|
||||
}, nil
|
||||
return naddr.Bytes(), nil
|
||||
}
|
||||
|
||||
func SupportedSectorSize(ssize types.BigInt) bool {
|
||||
@ -112,84 +101,65 @@ type UpdateStorageParams struct {
|
||||
Delta types.BigInt
|
||||
}
|
||||
|
||||
func (sma StorageMarketActor) UpdateStorage(act *types.Actor, vmctx types.VMContext, params *UpdateStorageParams) (types.InvokeRet, error) {
|
||||
func (sma StorageMarketActor) UpdateStorage(act *types.Actor, vmctx types.VMContext, params *UpdateStorageParams) ([]byte, ActorError) {
|
||||
var self StorageMarketState
|
||||
if err := vmctx.Storage().Get(vmctx.Storage().GetHead(), &self); err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, ok := self.Miners[vmctx.Message().From]
|
||||
if !ok {
|
||||
//Fatal("update storage must only be called by a miner actor")
|
||||
return types.InvokeRet{
|
||||
ReturnCode: 1,
|
||||
}, nil
|
||||
return nil, aerrors.New(1, "update storage must only be called by a miner actor")
|
||||
}
|
||||
|
||||
self.TotalStorage = types.BigAdd(self.TotalStorage, params.Delta)
|
||||
return types.InvokeRet{}, nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (sma StorageMarketActor) GetTotalStorage(act *types.Actor, vmctx types.VMContext, params *struct{}) (types.InvokeRet, error) {
|
||||
func (sma StorageMarketActor) GetTotalStorage(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
||||
var self StorageMarketState
|
||||
if err := vmctx.Storage().Get(vmctx.Storage().GetHead(), &self); err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.InvokeRet{
|
||||
Result: self.TotalStorage.Bytes(),
|
||||
}, nil
|
||||
return self.TotalStorage.Bytes(), nil
|
||||
}
|
||||
|
||||
type PowerLookupParams struct {
|
||||
Miner address.Address
|
||||
}
|
||||
|
||||
func (sma StorageMarketActor) PowerLookup(act *types.Actor, vmctx types.VMContext, params *PowerLookupParams) (types.InvokeRet, error) {
|
||||
func (sma StorageMarketActor) PowerLookup(act *types.Actor, vmctx types.VMContext, params *PowerLookupParams) ([]byte, ActorError) {
|
||||
var self StorageMarketState
|
||||
if err := vmctx.Storage().Get(vmctx.Storage().GetHead(), &self); err != nil {
|
||||
return types.InvokeRet{}, xerrors.Errorf("getting head: %w", err)
|
||||
return nil, aerrors.Wrap(err, "getting head")
|
||||
}
|
||||
|
||||
if _, ok := self.Miners[params.Miner]; !ok {
|
||||
//Fatal("miner not registered with storage market")
|
||||
return types.InvokeRet{
|
||||
ReturnCode: 1,
|
||||
}, nil
|
||||
return nil, aerrors.New(1, "miner not registered with storage market")
|
||||
}
|
||||
|
||||
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 {
|
||||
return types.InvokeRet{}, xerrors.Errorf("invoke Miner.GetPower: %w", err)
|
||||
return nil, aerrors.Wrap(err, "invoke Miner.GetPower")
|
||||
}
|
||||
|
||||
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{
|
||||
Result: ret,
|
||||
}, nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
type IsMinerParam struct {
|
||||
Addr address.Address
|
||||
}
|
||||
|
||||
func (sma StorageMarketActor) IsMiner(act *types.Actor, vmctx types.VMContext, param *IsMinerParam) (types.InvokeRet, error) {
|
||||
func (sma StorageMarketActor) IsMiner(act *types.Actor, vmctx types.VMContext, param *IsMinerParam) ([]byte, ActorError) {
|
||||
var self StorageMarketState
|
||||
if err := vmctx.Storage().Get(vmctx.Storage().GetHead(), &self); err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
_, ok := self.Miners[param.Addr]
|
||||
out, err := SerializeParams(ok)
|
||||
if err != nil {
|
||||
return types.InvokeRet{}, err
|
||||
return nil, err
|
||||
}
|
||||
return types.InvokeRet{
|
||||
Result: out,
|
||||
}, nil
|
||||
return out, nil
|
||||
}
|
||||
|
14
chain/actors/address.go
Normal file
14
chain/actors/address.go
Normal 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
|
||||
}
|
68
chain/actors/aerrors/error.go
Normal file
68
chain/actors/aerrors/error.go
Normal file
@ -0,0 +1,68 @@
|
||||
package aerrors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func IsFatal(err ActorError) bool {
|
||||
return err != nil && err.IsFatal()
|
||||
}
|
||||
func RetCode(err ActorError) uint8 {
|
||||
if err == nil {
|
||||
return 0
|
||||
}
|
||||
return err.RetCode()
|
||||
}
|
||||
|
||||
type internalActorError interface {
|
||||
ActorError
|
||||
FormatError(p xerrors.Printer) (next error)
|
||||
Unwrap() error
|
||||
}
|
||||
|
||||
type ActorError interface {
|
||||
error
|
||||
IsFatal() bool
|
||||
RetCode() uint8
|
||||
}
|
||||
|
||||
type actorError struct {
|
||||
fatal bool
|
||||
retCode uint8
|
||||
|
||||
msg string
|
||||
frame xerrors.Frame
|
||||
err error
|
||||
}
|
||||
|
||||
func (e *actorError) IsFatal() bool {
|
||||
return e.fatal
|
||||
}
|
||||
|
||||
func (e *actorError) RetCode() uint8 {
|
||||
return e.retCode
|
||||
}
|
||||
|
||||
func (e *actorError) Error() string {
|
||||
return fmt.Sprint(e)
|
||||
}
|
||||
func (e *actorError) Format(s fmt.State, v rune) { xerrors.FormatError(e, s, v) }
|
||||
func (e *actorError) FormatError(p xerrors.Printer) (next error) {
|
||||
p.Print(e.msg)
|
||||
if e.fatal {
|
||||
p.Print(" (FATAL)")
|
||||
} else {
|
||||
p.Printf(" (RetCode=%d)", e.retCode)
|
||||
}
|
||||
|
||||
e.frame.Format(p)
|
||||
return e.err
|
||||
}
|
||||
|
||||
func (e *actorError) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
var _ internalActorError = (*actorError)(nil)
|
35
chain/actors/aerrors/error_test.go
Normal file
35
chain/actors/aerrors/error_test.go
Normal file
@ -0,0 +1,35 @@
|
||||
package aerrors_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func TestFatalError(t *testing.T) {
|
||||
e1 := xerrors.New("out of disk space")
|
||||
e2 := xerrors.Errorf("could not put node: %w", e1)
|
||||
e3 := xerrors.Errorf("could not save head: %w", e2)
|
||||
ae := Escalate(e3, "failed to save the head")
|
||||
aw1 := Wrap(ae, "saving head of new miner actor")
|
||||
aw2 := Absorb(aw1, 1, "try to absorb fatal error")
|
||||
aw3 := Wrap(aw2, "initializing actor")
|
||||
aw4 := Wrap(aw3, "creating miner in storage market")
|
||||
t.Logf("Verbose error: %+v", aw4)
|
||||
t.Logf("Normal error: %v", aw4)
|
||||
assert.True(t, IsFatal(aw4), "should be fatal")
|
||||
}
|
||||
func TestAbsorbeError(t *testing.T) {
|
||||
e1 := xerrors.New("EOF")
|
||||
e2 := xerrors.Errorf("could not decode: %w", e1)
|
||||
ae := Absorb(e2, 35, "failed to decode CBOR")
|
||||
aw1 := Wrap(ae, "saving head of new miner actor")
|
||||
aw2 := Wrap(aw1, "initializing actor")
|
||||
aw3 := Wrap(aw2, "creating miner in storage market")
|
||||
t.Logf("Verbose error: %+v", aw3)
|
||||
t.Logf("Normal error: %v", aw3)
|
||||
assert.Equal(t, uint8(35), RetCode(aw3))
|
||||
}
|
128
chain/actors/aerrors/wrap.go
Normal file
128
chain/actors/aerrors/wrap.go
Normal file
@ -0,0 +1,128 @@
|
||||
package aerrors
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// New creates a new non-fatal error
|
||||
func New(retCode uint8, message string) ActorError {
|
||||
if retCode == 0 {
|
||||
return &actorError{
|
||||
fatal: true,
|
||||
retCode: 0,
|
||||
|
||||
msg: "tried creating an error and setting RetCode to 0",
|
||||
frame: xerrors.Caller(1),
|
||||
err: errors.New(message),
|
||||
}
|
||||
}
|
||||
return &actorError{
|
||||
retCode: retCode,
|
||||
|
||||
msg: message,
|
||||
frame: xerrors.Caller(1),
|
||||
}
|
||||
}
|
||||
|
||||
// Newf creates a new non-fatal error
|
||||
func Newf(retCode uint8, format string, args ...interface{}) ActorError {
|
||||
if retCode == 0 {
|
||||
return &actorError{
|
||||
fatal: true,
|
||||
retCode: 0,
|
||||
|
||||
msg: "tried creating an error and setting RetCode to 0",
|
||||
frame: xerrors.Caller(1),
|
||||
err: fmt.Errorf(format, args...),
|
||||
}
|
||||
}
|
||||
return &actorError{
|
||||
retCode: retCode,
|
||||
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
frame: xerrors.Caller(1),
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap extens chain of errors with a message
|
||||
func Wrap(err ActorError, message string) ActorError {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &actorError{
|
||||
fatal: IsFatal(err),
|
||||
retCode: RetCode(err),
|
||||
|
||||
msg: message,
|
||||
frame: xerrors.Caller(1),
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapf extens chain of errors with a message
|
||||
func Wrapf(err ActorError, format string, args ...interface{}) ActorError {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &actorError{
|
||||
fatal: IsFatal(err),
|
||||
retCode: RetCode(err),
|
||||
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
frame: xerrors.Caller(1),
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
// Absorb takes and error and makes in not fatal ActorError
|
||||
func Absorb(err error, retCode uint8, msg string) ActorError {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if aerr, ok := err.(ActorError); ok && IsFatal(aerr) {
|
||||
return &actorError{
|
||||
fatal: true,
|
||||
retCode: 0,
|
||||
|
||||
msg: "tried absorbing an error that is alreay an fatal error",
|
||||
frame: xerrors.Caller(1),
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
if retCode == 0 {
|
||||
return &actorError{
|
||||
fatal: true,
|
||||
retCode: 0,
|
||||
|
||||
msg: "tried absorbing an error and setting RetCode to 0",
|
||||
frame: xerrors.Caller(1),
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
return &actorError{
|
||||
fatal: false,
|
||||
retCode: retCode,
|
||||
|
||||
msg: msg,
|
||||
frame: xerrors.Caller(1),
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
// Escalate takes and error and escalates it into a fatal error
|
||||
func Escalate(err error, msg string) ActorError {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &actorError{
|
||||
fatal: true,
|
||||
|
||||
msg: msg,
|
||||
frame: xerrors.Caller(1),
|
||||
err: err,
|
||||
}
|
||||
}
|
5
chain/actors/error.go
Normal file
5
chain/actors/error.go
Normal file
@ -0,0 +1,5 @@
|
||||
package actors
|
||||
|
||||
import "github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
||||
|
||||
type ActorError = aerrors.ActorError
|
@ -1,6 +1,7 @@
|
||||
package actors
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
)
|
||||
|
||||
@ -8,6 +9,10 @@ var (
|
||||
EmptyStructCBOR = []byte{0xa0}
|
||||
)
|
||||
|
||||
func SerializeParams(i interface{}) ([]byte, error) {
|
||||
return cbor.DumpObject(i)
|
||||
func SerializeParams(i interface{}) ([]byte, aerrors.ActorError) {
|
||||
dump, err := cbor.DumpObject(i)
|
||||
if err != nil {
|
||||
return nil, aerrors.Absorb(err, 1, "failed to encode parameter")
|
||||
}
|
||||
return dump, nil
|
||||
}
|
||||
|
@ -5,17 +5,17 @@ import (
|
||||
"reflect"
|
||||
|
||||
actors "github.com/filecoin-project/go-lotus/chain/actors"
|
||||
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
||||
"github.com/filecoin-project/go-lotus/chain/types"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type invoker struct {
|
||||
builtInCode map[cid.Cid]nativeCode
|
||||
}
|
||||
|
||||
type invokeFunc func(act *types.Actor, vmctx *VMContext, params []byte) (types.InvokeRet, error)
|
||||
type invokeFunc func(act *types.Actor, vmctx *VMContext, params []byte) ([]byte, aerrors.ActorError)
|
||||
type nativeCode []invokeFunc
|
||||
|
||||
func newInvoker() *invoker {
|
||||
@ -31,14 +31,14 @@ func newInvoker() *invoker {
|
||||
return inv
|
||||
}
|
||||
|
||||
func (inv *invoker) Invoke(act *types.Actor, vmctx *VMContext, method uint64, params []byte) (types.InvokeRet, error) {
|
||||
func (inv *invoker) Invoke(act *types.Actor, vmctx *VMContext, method uint64, params []byte) ([]byte, aerrors.ActorError) {
|
||||
|
||||
code, ok := inv.builtInCode[act.Code]
|
||||
if !ok {
|
||||
return types.InvokeRet{}, xerrors.Errorf("no code for actor %s", act.Code)
|
||||
return nil, aerrors.Newf(255, "no code for actor %s", act.Code)
|
||||
}
|
||||
if method >= uint64(len(code)) || code[method] == nil {
|
||||
return types.InvokeRet{}, xerrors.Errorf("no method %d on actor", method)
|
||||
return nil, aerrors.Newf(255, "no method %d on actor", method)
|
||||
}
|
||||
return code[method](act, vmctx, params)
|
||||
|
||||
@ -57,7 +57,7 @@ type Invokee interface {
|
||||
}
|
||||
|
||||
var tVMContext = reflect.TypeOf((*types.VMContext)(nil)).Elem()
|
||||
var tError = reflect.TypeOf((*error)(nil)).Elem()
|
||||
var tAError = reflect.TypeOf((*aerrors.ActorError)(nil)).Elem()
|
||||
|
||||
func (*invoker) transform(instance Invokee) (nativeCode, error) {
|
||||
itype := reflect.TypeOf(instance)
|
||||
@ -65,7 +65,7 @@ func (*invoker) transform(instance Invokee) (nativeCode, error) {
|
||||
for i, m := range exports {
|
||||
i := i
|
||||
newErr := func(format string, args ...interface{}) error {
|
||||
str := fmt.Sprintf(format, args)
|
||||
str := fmt.Sprintf(format, args...)
|
||||
return fmt.Errorf("transform(%s) export(%d): %s", itype.Name(), i, str)
|
||||
}
|
||||
if m == nil {
|
||||
@ -96,11 +96,11 @@ func (*invoker) transform(instance Invokee) (nativeCode, error) {
|
||||
return nil, newErr("wrong number of outputs should be: " +
|
||||
"(InvokeRet, error)")
|
||||
}
|
||||
if t.Out(0) != reflect.TypeOf(types.InvokeRet{}) {
|
||||
return nil, newErr("first output should be of type InvokeRet")
|
||||
if t.Out(0) != reflect.TypeOf([]byte{}) {
|
||||
return nil, newErr("first output should be slice of bytes")
|
||||
}
|
||||
if !t.Out(1).Implements(tError) {
|
||||
return nil, newErr("second output should be error type")
|
||||
if !t.Out(1).Implements(tAError) {
|
||||
return nil, newErr("second output should be ActorError type")
|
||||
}
|
||||
|
||||
}
|
||||
@ -115,11 +115,12 @@ func (*invoker) transform(instance Invokee) (nativeCode, error) {
|
||||
inBytes := in[2].Interface().([]byte)
|
||||
err := cbor.DecodeInto(inBytes, param.Interface())
|
||||
if err != nil {
|
||||
aerr := aerrors.Absorb(err, 1, "failed to decode parameters")
|
||||
return []reflect.Value{
|
||||
reflect.ValueOf(types.InvokeRet{}),
|
||||
reflect.ValueOf([]byte{}),
|
||||
// Below is a hack, fixed in Go 1.13
|
||||
// https://git.io/fjXU6
|
||||
reflect.ValueOf(&err).Elem(),
|
||||
reflect.ValueOf(&aerr).Elem(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
||||
"github.com/filecoin-project/go-lotus/chain/types"
|
||||
)
|
||||
|
||||
@ -35,23 +36,17 @@ func (b basicContract) Exports() []interface{} {
|
||||
}
|
||||
|
||||
func (basicContract) InvokeSomething0(act *types.Actor, vmctx types.VMContext,
|
||||
params *basicParams) (types.InvokeRet, error) {
|
||||
return types.InvokeRet{
|
||||
ReturnCode: params.B,
|
||||
}, nil
|
||||
params *basicParams) ([]byte, aerrors.ActorError) {
|
||||
return nil, aerrors.New(params.B, "params.B")
|
||||
}
|
||||
func (basicContract) BadParam(act *types.Actor, vmctx types.VMContext,
|
||||
params *basicParams) (types.InvokeRet, error) {
|
||||
return types.InvokeRet{
|
||||
ReturnCode: 255,
|
||||
}, nil
|
||||
params *basicParams) ([]byte, aerrors.ActorError) {
|
||||
return nil, aerrors.New(255, "bad params")
|
||||
}
|
||||
|
||||
func (basicContract) InvokeSomething10(act *types.Actor, vmctx types.VMContext,
|
||||
params *basicParams) (types.InvokeRet, error) {
|
||||
return types.InvokeRet{
|
||||
ReturnCode: params.B + 10,
|
||||
}, nil
|
||||
params *basicParams) ([]byte, aerrors.ActorError) {
|
||||
return nil, aerrors.New(params.B+10, "params.B")
|
||||
}
|
||||
|
||||
func TestInvokerBasic(t *testing.T) {
|
||||
@ -63,21 +58,29 @@ func TestInvokerBasic(t *testing.T) {
|
||||
bParam, err := cbor.DumpObject(basicParams{B: 1})
|
||||
assert.NoError(t, err)
|
||||
|
||||
ret, err := code[0](nil, &VMContext{}, bParam)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, byte(1), ret.ReturnCode, "return code should be 1")
|
||||
_, aerr := code[0](nil, &VMContext{}, bParam)
|
||||
|
||||
assert.Equal(t, byte(1), aerrors.RetCode(aerr), "return code should be 1")
|
||||
if aerrors.IsFatal(aerr) {
|
||||
t.Fatal("err should not be fatal")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
bParam, err := cbor.DumpObject(basicParams{B: 2})
|
||||
assert.NoError(t, err)
|
||||
|
||||
ret, err := code[10](nil, &VMContext{}, bParam)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, byte(12), ret.ReturnCode, "return code should be 12")
|
||||
_, aerr := code[10](nil, &VMContext{}, bParam)
|
||||
assert.Equal(t, byte(12), aerrors.RetCode(aerr), "return code should be 12")
|
||||
if aerrors.IsFatal(aerr) {
|
||||
t.Fatal("err should not be fatal")
|
||||
}
|
||||
}
|
||||
|
||||
_, err = code[1](nil, &VMContext{}, []byte{0})
|
||||
assert.Error(t, err)
|
||||
_, aerr := code[1](nil, &VMContext{}, []byte{0})
|
||||
if aerrors.IsFatal(aerr) {
|
||||
t.Fatal("err should not be fatal")
|
||||
}
|
||||
assert.Equal(t, byte(1), aerrors.RetCode(aerr), "return code should be 1")
|
||||
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package chain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
@ -13,8 +12,6 @@ import (
|
||||
"github.com/filecoin-project/go-lotus/chain/types"
|
||||
)
|
||||
|
||||
var ErrActorNotFound = fmt.Errorf("actor not found")
|
||||
|
||||
type StateTree struct {
|
||||
root *hamt.Node
|
||||
store *hamt.CborIpldStore
|
||||
@ -83,7 +80,7 @@ func (st *StateTree) GetActor(addr address.Address) (*types.Actor, error) {
|
||||
iaddr, err := st.lookupID(addr)
|
||||
if err != nil {
|
||||
if err == hamt.ErrNotFound {
|
||||
return nil, ErrActorNotFound
|
||||
return nil, types.ErrActorNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
@ -98,7 +95,7 @@ func (st *StateTree) GetActor(addr address.Address) (*types.Actor, error) {
|
||||
thing, err := st.root.Find(context.TODO(), string(addr.Bytes()))
|
||||
if err != nil {
|
||||
if err == hamt.ErrNotFound {
|
||||
return nil, ErrActorNotFound
|
||||
return nil, types.ErrActorNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1,10 +1,14 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
)
|
||||
|
||||
var ErrActorNotFound = fmt.Errorf("actor not found")
|
||||
|
||||
func init() {
|
||||
cbor.RegisterCborType(Actor{})
|
||||
}
|
||||
|
@ -1,20 +1,21 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-hamt-ipld"
|
||||
)
|
||||
|
||||
type Storage interface {
|
||||
Put(interface{}) (cid.Cid, error)
|
||||
Get(cid.Cid, interface{}) error
|
||||
Put(interface{}) (cid.Cid, aerrors.ActorError)
|
||||
Get(cid.Cid, interface{}) aerrors.ActorError
|
||||
|
||||
GetHead() cid.Cid
|
||||
|
||||
// Commit sets the new head of the actors state as long as the current
|
||||
// state matches 'oldh'
|
||||
Commit(oldh cid.Cid, newh cid.Cid) error
|
||||
Commit(oldh cid.Cid, newh cid.Cid) aerrors.ActorError
|
||||
}
|
||||
|
||||
type StateTree interface {
|
||||
@ -26,9 +27,9 @@ type VMContext interface {
|
||||
Message() *Message
|
||||
Origin() address.Address
|
||||
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
|
||||
GasUsed() BigInt
|
||||
Storage() Storage
|
||||
StateTree() (StateTree, error)
|
||||
StateTree() (StateTree, aerrors.ActorError)
|
||||
}
|
||||
|
50
chain/vm.go
50
chain/vm.go
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/chain/actors"
|
||||
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
"github.com/filecoin-project/go-lotus/chain/types"
|
||||
"github.com/filecoin-project/go-lotus/lib/bufbstore"
|
||||
@ -45,21 +46,25 @@ type storage struct {
|
||||
head cid.Cid
|
||||
}
|
||||
|
||||
func (s *storage) Put(i interface{}) (cid.Cid, error) {
|
||||
return s.cst.Put(context.TODO(), i)
|
||||
func (s *storage) Put(i interface{}) (cid.Cid, aerrors.ActorError) {
|
||||
c, err := s.cst.Put(context.TODO(), i)
|
||||
if err != nil {
|
||||
return cid.Undef, aerrors.Escalate(err, "putting cid")
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (s *storage) Get(c cid.Cid, out interface{}) error {
|
||||
return s.cst.Get(context.TODO(), c, out)
|
||||
func (s *storage) Get(c cid.Cid, out interface{}) aerrors.ActorError {
|
||||
return aerrors.Escalate(s.cst.Get(context.TODO(), c, out), "getting cid")
|
||||
}
|
||||
|
||||
func (s *storage) GetHead() cid.Cid {
|
||||
return s.head
|
||||
}
|
||||
|
||||
func (s *storage) Commit(oldh, newh cid.Cid) error {
|
||||
func (s *storage) Commit(oldh, newh cid.Cid) aerrors.ActorError {
|
||||
if s.head != oldh {
|
||||
return fmt.Errorf("failed to update, inconsistent base reference")
|
||||
return aerrors.New(1, "failed to update, inconsistent base reference")
|
||||
}
|
||||
|
||||
s.head = newh
|
||||
@ -80,7 +85,7 @@ func (vmc *VMContext) Origin() address.Address {
|
||||
}
|
||||
|
||||
// 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, uint8, error) {
|
||||
func (vmc *VMContext) Send(to address.Address, method uint64, value types.BigInt, params []byte) ([]byte, aerrors.ActorError) {
|
||||
|
||||
msg := &types.Message{
|
||||
From: vmc.msg.To,
|
||||
@ -92,19 +97,19 @@ func (vmc *VMContext) Send(to address.Address, method uint64, value types.BigInt
|
||||
|
||||
toAct, err := vmc.state.GetActor(to)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
return nil, aerrors.Absorb(err, 2, "could not find actor for Send")
|
||||
}
|
||||
|
||||
nvmctx := vmc.vm.makeVMContext(toAct.Head, vmc.origin, msg)
|
||||
|
||||
res, ret, err := vmc.vm.Invoke(toAct, nvmctx, method, params)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
res, aerr := vmc.vm.Invoke(toAct, nvmctx, method, params)
|
||||
if aerr != nil {
|
||||
return nil, aerr
|
||||
}
|
||||
|
||||
toAct.Head = nvmctx.Storage().GetHead()
|
||||
|
||||
return res, ret, err
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// BlockHeight returns the height of the block this message was added to the chain in
|
||||
@ -116,9 +121,9 @@ func (vmc *VMContext) GasUsed() types.BigInt {
|
||||
return types.NewInt(0)
|
||||
}
|
||||
|
||||
func (vmc *VMContext) StateTree() (types.StateTree, error) {
|
||||
func (vmc *VMContext) StateTree() (types.StateTree, aerrors.ActorError) {
|
||||
if vmc.msg.To != actors.InitActorAddress {
|
||||
return nil, fmt.Errorf("only init actor can access state tree directly")
|
||||
return nil, aerrors.Escalate(fmt.Errorf("only init actor can access state tree directly"), "invalid use of StateTree")
|
||||
}
|
||||
|
||||
return vmc.state, nil
|
||||
@ -192,7 +197,7 @@ func (vm *VM) ApplyMessage(msg *types.Message) (*types.MessageReceipt, error) {
|
||||
|
||||
toActor, err := st.GetActor(msg.To)
|
||||
if err != nil {
|
||||
if err == ErrActorNotFound {
|
||||
if xerrors.Is(err, types.ErrActorNotFound) {
|
||||
a, err := TryCreateAccountActor(st, msg.To)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -213,18 +218,21 @@ func (vm *VM) ApplyMessage(msg *types.Message) (*types.MessageReceipt, error) {
|
||||
var errcode byte
|
||||
var ret []byte
|
||||
if msg.Method != 0 {
|
||||
ret, errcode, err = vm.Invoke(toActor, vmctx, msg.Method, msg.Params)
|
||||
if err != nil {
|
||||
var err aerrors.ActorError
|
||||
ret, err = vm.Invoke(toActor, vmctx, msg.Method, msg.Params)
|
||||
|
||||
if aerrors.IsFatal(err) {
|
||||
return nil, xerrors.Errorf("during invoke: %w", err)
|
||||
}
|
||||
|
||||
if errcode != 0 {
|
||||
if errcode = aerrors.RetCode(err); errcode != 0 {
|
||||
// revert all state changes since snapshot
|
||||
st.Revert()
|
||||
gascost := types.BigMul(vmctx.GasUsed(), msg.GasPrice)
|
||||
if err := DeductFunds(fromActor, gascost); err != nil {
|
||||
panic("invariant violated: " + err.Error())
|
||||
}
|
||||
|
||||
} else {
|
||||
// Update actor head reference
|
||||
toActor.Head = vmctx.storage.head
|
||||
@ -320,10 +328,10 @@ func (vm *VM) TransferFunds(from, to address.Address, amt types.BigInt) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vm *VM) Invoke(act *types.Actor, vmctx *VMContext, method uint64, params []byte) ([]byte, byte, error) {
|
||||
func (vm *VM) Invoke(act *types.Actor, vmctx *VMContext, method uint64, params []byte) ([]byte, aerrors.ActorError) {
|
||||
ret, err := vm.inv.Invoke(act, vmctx, method, params)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
return nil, err
|
||||
}
|
||||
return ret.Result, ret.ReturnCode, nil
|
||||
return ret, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user