183 lines
4.4 KiB
Go
183 lines
4.4 KiB
Go
package vm
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"runtime/debug"
|
|
|
|
"github.com/filecoin-project/go-address"
|
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
"github.com/filecoin-project/specs-actors/actors/runtime"
|
|
vmr "github.com/filecoin-project/specs-actors/actors/runtime"
|
|
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
|
"github.com/ipfs/go-cid"
|
|
cbg "github.com/whyrusleeping/cbor-gen"
|
|
|
|
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
|
"github.com/filecoin-project/lotus/chain/types"
|
|
)
|
|
|
|
type runtimeShim struct {
|
|
vmctx types.VMContext
|
|
vmr.Runtime
|
|
}
|
|
|
|
var _ runtime.Runtime = (*runtimeShim)(nil)
|
|
|
|
func (rs *runtimeShim) shimCall(f func() interface{}) (rval []byte, aerr aerrors.ActorError) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
if ar, ok := r.(aerrors.ActorError); ok {
|
|
aerr = ar
|
|
return
|
|
}
|
|
fmt.Println("caught one of those actor errors: ", r)
|
|
debug.PrintStack()
|
|
log.Errorf("ERROR")
|
|
aerr = aerrors.Newf(1, "generic spec actors failure")
|
|
}
|
|
}()
|
|
|
|
ret := f()
|
|
switch ret := ret.(type) {
|
|
case []byte:
|
|
return ret, nil
|
|
case cbg.CBORMarshaler:
|
|
buf := new(bytes.Buffer)
|
|
if err := ret.MarshalCBOR(buf); err != nil {
|
|
return nil, aerrors.Absorb(err, 2, "failed to marshal response to cbor")
|
|
}
|
|
return buf.Bytes(), nil
|
|
case nil:
|
|
return nil, nil
|
|
default:
|
|
return nil, aerrors.New(3, "could not determine type for response from call")
|
|
}
|
|
}
|
|
|
|
func (rs *runtimeShim) ValidateImmediateCallerIs(as ...address.Address) {
|
|
for _, a := range as {
|
|
if rs.vmctx.Message().From == a {
|
|
return
|
|
}
|
|
}
|
|
fmt.Println("Caller: ", rs.vmctx.Message().From, as)
|
|
panic("we like to panic when people call the wrong methods")
|
|
}
|
|
|
|
func (rs *runtimeShim) ImmediateCaller() address.Address {
|
|
return rs.vmctx.Message().From
|
|
}
|
|
|
|
func (rs *runtimeShim) Context() context.Context {
|
|
return rs.vmctx.Context()
|
|
}
|
|
|
|
func (rs *runtimeShim) IpldGet(c cid.Cid, o vmr.CBORUnmarshaler) bool {
|
|
if err := rs.vmctx.Storage().Get(c, o); err != nil {
|
|
panic(err) // y o o o o o l l l l o o o o o
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (rs *runtimeShim) IpldPut(o vmr.CBORMarshaler) cid.Cid {
|
|
c, err := rs.vmctx.Storage().Put(o)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return c
|
|
}
|
|
|
|
func (rs *runtimeShim) Abort(code exitcode.ExitCode, msg string, args ...interface{}) {
|
|
panic(aerrors.Newf(uint8(code), msg, args...))
|
|
}
|
|
|
|
func (rs *runtimeShim) AbortStateMsg(msg string) {
|
|
rs.Abort(101, msg)
|
|
}
|
|
|
|
func (rs *runtimeShim) ValidateImmediateCallerType(...cid.Cid) {
|
|
log.Info("validate caller type is dumb")
|
|
}
|
|
|
|
func (rs *runtimeShim) CurrentBalance() abi.TokenAmount {
|
|
b, err := rs.vmctx.GetBalance(rs.vmctx.Message().From)
|
|
if err != nil {
|
|
rs.Abort(1, err.Error())
|
|
}
|
|
|
|
return abi.TokenAmount(b)
|
|
}
|
|
|
|
func (rs *runtimeShim) CurrEpoch() abi.ChainEpoch {
|
|
return abi.ChainEpoch(rs.vmctx.BlockHeight())
|
|
}
|
|
|
|
type dumbWrapperType struct {
|
|
val []byte
|
|
}
|
|
|
|
func (dwt *dumbWrapperType) Into(um vmr.CBORUnmarshaler) error {
|
|
return um.UnmarshalCBOR(bytes.NewReader(dwt.val))
|
|
}
|
|
|
|
func (rs *runtimeShim) Send(to address.Address, method abi.MethodNum, m runtime.CBORMarshaler, value abi.TokenAmount) (vmr.SendReturn, exitcode.ExitCode) {
|
|
buf := new(bytes.Buffer)
|
|
if err := m.MarshalCBOR(buf); err != nil {
|
|
rs.Abort(exitcode.SysErrInvalidParameters, "failed to marshal input parameters: %s", err)
|
|
}
|
|
|
|
ret, err := rs.vmctx.Send(to, method, types.BigInt(value), buf.Bytes())
|
|
if err != nil {
|
|
if err.IsFatal() {
|
|
panic(err)
|
|
}
|
|
return nil, exitcode.ExitCode(err.RetCode())
|
|
}
|
|
return &dumbWrapperType{ret}, 0
|
|
}
|
|
|
|
func (rs *runtimeShim) State() vmr.StateHandle {
|
|
return &shimStateHandle{rs: rs}
|
|
}
|
|
|
|
type shimStateHandle struct {
|
|
rs *runtimeShim
|
|
}
|
|
|
|
func (ssh *shimStateHandle) Create(obj vmr.CBORMarshaler) {
|
|
c, err := ssh.rs.vmctx.Storage().Put(obj)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
if err := ssh.rs.vmctx.Storage().Commit(cid.Undef, c); err != nil { // todo: empty cbor thing may have been here for a good reason
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func (ssh *shimStateHandle) Readonly(obj vmr.CBORUnmarshaler) {
|
|
if err := ssh.rs.vmctx.Storage().Get(ssh.rs.vmctx.Storage().GetHead(), obj); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func (ssh *shimStateHandle) Transaction(obj vmr.CBORer, f func() interface{}) interface{} {
|
|
head := ssh.rs.vmctx.Storage().GetHead()
|
|
if err := ssh.rs.vmctx.Storage().Get(head, obj); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
out := f()
|
|
|
|
c, err := ssh.rs.vmctx.Storage().Put(obj)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
if err := ssh.rs.vmctx.Storage().Commit(head, c); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return out
|
|
}
|