Merge pull request #23 from filecoin-project/feat/init-actor-rebase
init actor
This commit is contained in:
commit
87a3eba8db
@ -137,7 +137,6 @@ workflows:
|
||||
jobs:
|
||||
- lint-changes:
|
||||
args: "--new-from-rev origin/master"
|
||||
- lint-all
|
||||
- test:
|
||||
codecov-upload: true
|
||||
- mod-tidy-check
|
||||
|
187
chain/actor_init.go
Normal file
187
chain/actor_init.go
Normal file
@ -0,0 +1,187 @@
|
||||
package chain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
"github.com/filecoin-project/go-lotus/chain/types"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cbor.RegisterCborType(ExecParams{})
|
||||
}
|
||||
|
||||
type InitActor struct{}
|
||||
|
||||
type InitActorState struct {
|
||||
// TODO: this needs to be a HAMT, its a dumb map for now
|
||||
AddressMap cid.Cid
|
||||
|
||||
NextID uint64
|
||||
}
|
||||
|
||||
func (ia InitActor) Exports() []interface{} {
|
||||
return []interface{}{
|
||||
nil,
|
||||
ia.Exec,
|
||||
}
|
||||
}
|
||||
|
||||
type ExecParams struct {
|
||||
Code cid.Cid
|
||||
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 (ia InitActor) Exec(act *types.Actor, vmctx types.VMContext, p *ExecParams) (InvokeRet, error) {
|
||||
beginState := vmctx.Storage().GetHead()
|
||||
|
||||
var self InitActorState
|
||||
if err := vmctx.Storage().Get(beginState, &self); err != nil {
|
||||
return InvokeRet{}, 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 InvokeRet{
|
||||
returnCode: 1,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 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 InvokeRet{
|
||||
returnCode: 1,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 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 InvokeRet{}, err
|
||||
}
|
||||
|
||||
// Set up the actor itself
|
||||
actor := types.Actor{
|
||||
Code: p.Code,
|
||||
Balance: vmctx.Message().Value,
|
||||
Head: cid.Undef,
|
||||
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, err := self.AddActor(vmctx, addr)
|
||||
if err != nil {
|
||||
return InvokeRet{}, errors.Wrap(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 InvokeRet{}, err
|
||||
}
|
||||
|
||||
if err := state.SetActor(idAddr, &actor); err != nil {
|
||||
return InvokeRet{}, errors.Wrap(err, "inserting new actor into state tree")
|
||||
}
|
||||
|
||||
c, err := vmctx.Storage().Put(self)
|
||||
if err != nil {
|
||||
return InvokeRet{}, err
|
||||
}
|
||||
|
||||
if err := vmctx.Storage().Commit(beginState, c); err != nil {
|
||||
return InvokeRet{}, err
|
||||
}
|
||||
|
||||
return InvokeRet{
|
||||
result: idAddr.Bytes(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func IsBuiltinActor(code cid.Cid) bool {
|
||||
switch code {
|
||||
case StorageMinerCodeCid, StorageMinerCodeCid, AccountActorCodeCid, InitActorCodeCid, MultisigActorCodeCid:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func IsSingletonActor(code cid.Cid) bool {
|
||||
return code == StorageMarketActorCodeCid || code == InitActorCodeCid
|
||||
}
|
||||
|
||||
func (ias *InitActorState) AddActor(vmctx types.VMContext, addr address.Address) (address.Address, error) {
|
||||
nid := ias.NextID
|
||||
ias.NextID++
|
||||
|
||||
amap, err := hamt.LoadNode(context.TODO(), vmctx.Ipld(), 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 := vmctx.Ipld().Put(context.TODO(), amap)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
ias.AddressMap = ncid
|
||||
|
||||
return address.NewIDAddress(nid)
|
||||
}
|
||||
|
||||
func (ias *InitActorState) Lookup(cst *hamt.CborIpldStore, addr address.Address) (address.Address, error) {
|
||||
amap, err := hamt.LoadNode(context.TODO(), cst, ias.AddressMap)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
val, err := amap.Find(context.TODO(), string(addr.Bytes()))
|
||||
if err != nil {
|
||||
return address.Undef, 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
|
||||
}
|
@ -1,13 +1,9 @@
|
||||
package chain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
mh "github.com/multiformats/go-multihash"
|
||||
)
|
||||
@ -54,58 +50,3 @@ func init() {
|
||||
|
||||
type VMActor struct {
|
||||
}
|
||||
|
||||
type InitActorState struct {
|
||||
AddressMap cid.Cid
|
||||
|
||||
NextID uint64
|
||||
}
|
||||
|
||||
func (ias *InitActorState) AddActor(vmctx *VMContext, addr address.Address) (address.Address, error) {
|
||||
nid := ias.NextID
|
||||
ias.NextID++
|
||||
|
||||
amap, err := hamt.LoadNode(context.TODO(), vmctx.Ipld(), 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 := vmctx.Ipld().Put(context.TODO(), amap)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
ias.AddressMap = ncid
|
||||
|
||||
return address.NewIDAddress(nid)
|
||||
}
|
||||
|
||||
func (ias *InitActorState) Lookup(cst *hamt.CborIpldStore, addr address.Address) (address.Address, error) {
|
||||
amap, err := hamt.LoadNode(context.TODO(), cst, ias.AddressMap)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
val, err := amap.Find(context.TODO(), string(addr.Bytes()))
|
||||
if err != nil {
|
||||
return address.Undef, 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
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
"github.com/filecoin-project/go-lotus/chain/types"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
datastore "github.com/ipfs/go-datastore"
|
||||
dstore "github.com/ipfs/go-datastore"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
@ -78,7 +77,7 @@ func init() {
|
||||
|
||||
var EmptyObjectCid cid.Cid
|
||||
|
||||
func MakeGenesisBlock(bs bstore.Blockstore, w *Wallet) (*GenesisBootstrap, error) {
|
||||
func MakeInitialStateTree(bs bstore.Blockstore, actors map[address.Address]types.BigInt) (*StateTree, error) {
|
||||
cst := hamt.CSTFromBstore(bs)
|
||||
state, err := NewStateTree(cst)
|
||||
if err != nil {
|
||||
@ -90,12 +89,12 @@ func MakeGenesisBlock(bs bstore.Blockstore, w *Wallet) (*GenesisBootstrap, error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
minerAddr, err := w.GenerateKey(KTSecp256k1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var addrs []address.Address
|
||||
for a := range actors {
|
||||
addrs = append(addrs, a)
|
||||
}
|
||||
|
||||
initact, err := SetupInitActor(bs, []address.Address{minerAddr})
|
||||
initact, err := SetupInitActor(bs, addrs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -104,6 +103,17 @@ func MakeGenesisBlock(bs bstore.Blockstore, w *Wallet) (*GenesisBootstrap, error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
/*
|
||||
smact, err := SetupStorageMarketActor(bs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := state.SetActor(StorageMarketAddress, smact); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
*/
|
||||
|
||||
err = state.SetActor(NetworkAddress, &types.Actor{
|
||||
Code: AccountActorCodeCid,
|
||||
Balance: types.NewInt(100000000000),
|
||||
@ -113,22 +123,64 @@ func MakeGenesisBlock(bs bstore.Blockstore, w *Wallet) (*GenesisBootstrap, error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = state.SetActor(minerAddr, &types.Actor{
|
||||
Code: AccountActorCodeCid,
|
||||
Balance: types.NewInt(5000000),
|
||||
Head: emptyobject,
|
||||
})
|
||||
for a, v := range actors {
|
||||
err = state.SetActor(a, &types.Actor{
|
||||
Code: AccountActorCodeCid,
|
||||
Balance: v,
|
||||
Head: emptyobject,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
|
||||
/*
|
||||
func SetupStorageMarketActor(bs bstore.Blockstore) (*Actor, error) {
|
||||
sms := &StorageMarketState{
|
||||
Miners: make(map[address.Address]struct{}),
|
||||
TotalStorage: NewInt(0),
|
||||
}
|
||||
|
||||
stcid, err := hamt.CSTFromBstore(bs).Put(context.TODO(), sms)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Actor{
|
||||
Code: StorageMarketActorCodeCid,
|
||||
Head: stcid,
|
||||
Nonce: 0,
|
||||
Balance: NewInt(0),
|
||||
}, nil
|
||||
}
|
||||
*/
|
||||
|
||||
func MakeGenesisBlock(bs bstore.Blockstore, w *Wallet) (*GenesisBootstrap, error) {
|
||||
fmt.Println("at end of make Genesis block")
|
||||
|
||||
minerAddr, err := w.GenerateKey(KTSecp256k1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
addrs := map[address.Address]types.BigInt{
|
||||
minerAddr: types.NewInt(50000000),
|
||||
}
|
||||
|
||||
state, err := MakeInitialStateTree(bs, addrs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fmt.Println("about to flush state...")
|
||||
|
||||
stateroot, err := state.Flush()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fmt.Println("at end of make Genesis block")
|
||||
|
||||
cst := hamt.CSTFromBstore(bs)
|
||||
emptyroot, err := sharray.Build(context.TODO(), 4, []interface{}{}, cst)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -164,7 +216,7 @@ func MakeGenesisBlock(bs bstore.Blockstore, w *Wallet) (*GenesisBootstrap, error
|
||||
|
||||
type ChainStore struct {
|
||||
bs bstore.Blockstore
|
||||
ds datastore.Datastore
|
||||
ds dstore.Datastore
|
||||
|
||||
heaviestLk sync.Mutex
|
||||
heaviest *TipSet
|
||||
@ -174,7 +226,7 @@ type ChainStore struct {
|
||||
headChange func(rev, app []*TipSet) error
|
||||
}
|
||||
|
||||
func NewChainStore(bs bstore.Blockstore, ds datastore.Batching) *ChainStore {
|
||||
func NewChainStore(bs bstore.Blockstore, ds dstore.Batching) *ChainStore {
|
||||
return &ChainStore{
|
||||
bs: bs,
|
||||
ds: ds,
|
||||
@ -204,7 +256,7 @@ func (cs *ChainStore) SetGenesis(b *BlockHeader) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return cs.ds.Put(datastore.NewKey("0"), b.Cid().Bytes())
|
||||
return cs.ds.Put(dstore.NewKey("0"), b.Cid().Bytes())
|
||||
}
|
||||
|
||||
func (cs *ChainStore) PutTipSet(ts *FullTipSet) error {
|
||||
@ -379,7 +431,7 @@ func (cs *ChainStore) AddBlock(b *BlockHeader) error {
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetGenesis() (*BlockHeader, error) {
|
||||
data, err := cs.ds.Get(datastore.NewKey("0"))
|
||||
data, err := cs.ds.Get(dstore.NewKey("0"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -24,7 +24,10 @@ func newInvoker() *invoker {
|
||||
inv := &invoker{
|
||||
builtInCode: make(map[cid.Cid]nativeCode),
|
||||
}
|
||||
|
||||
// add builtInCode using: register(cid, singleton)
|
||||
inv.register(InitActorCodeCid, InitActor{})
|
||||
|
||||
return inv
|
||||
}
|
||||
|
||||
|
@ -4,13 +4,32 @@ import (
|
||||
"math/big"
|
||||
|
||||
"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
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
type StateTree interface {
|
||||
SetActor(addr address.Address, act *Actor) error
|
||||
GetActor(addr address.Address) (*Actor, error)
|
||||
}
|
||||
|
||||
type VMContext interface {
|
||||
Message() *Message
|
||||
Ipld() *hamt.CborIpldStore
|
||||
Send(to address.Address, method string, value *big.Int, params []interface{}) ([][]byte, uint8, error)
|
||||
BlockHeight() uint64
|
||||
GasUsed() BigInt
|
||||
Storage() Storage
|
||||
StateTree() (StateTree, error)
|
||||
}
|
||||
|
78
chain/vm.go
78
chain/vm.go
@ -1,7 +1,9 @@
|
||||
package chain
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
@ -12,6 +14,7 @@ import (
|
||||
bserv "github.com/ipfs/go-blockservice"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
ipld "github.com/ipfs/go-ipld-format"
|
||||
dag "github.com/ipfs/go-merkledag"
|
||||
"github.com/pkg/errors"
|
||||
@ -22,6 +25,11 @@ type VMContext struct {
|
||||
msg *types.Message
|
||||
height uint64
|
||||
cst *hamt.CborIpldStore
|
||||
|
||||
// root cid of the state of the actor this invocation will be on
|
||||
sroot cid.Cid
|
||||
|
||||
storage types.Storage
|
||||
}
|
||||
|
||||
// Message is the message that kicked off the current invocation
|
||||
@ -29,12 +37,38 @@ func (vmc *VMContext) Message() *types.Message {
|
||||
return vmc.msg
|
||||
}
|
||||
|
||||
/*
|
||||
// Storage provides access to the VM storage layer
|
||||
func (vmc *VMContext) Storage() Storage {
|
||||
panic("nyi")
|
||||
type storage struct {
|
||||
// would be great to stop depending on this crap everywhere
|
||||
// I am my own worst enemy
|
||||
cst *hamt.CborIpldStore
|
||||
head cid.Cid
|
||||
}
|
||||
|
||||
func (s *storage) Put(i interface{}) (cid.Cid, error) {
|
||||
return s.cst.Put(context.TODO(), i)
|
||||
}
|
||||
|
||||
func (s *storage) Get(c cid.Cid, out interface{}) error {
|
||||
return s.cst.Get(context.TODO(), c, out)
|
||||
}
|
||||
|
||||
func (s *storage) GetHead() cid.Cid {
|
||||
return s.head
|
||||
}
|
||||
|
||||
func (s *storage) Commit(oldh, newh cid.Cid) error {
|
||||
if s.head != oldh {
|
||||
return fmt.Errorf("failed to update, inconsistent base reference")
|
||||
}
|
||||
|
||||
s.head = newh
|
||||
return nil
|
||||
}
|
||||
|
||||
// Storage provides access to the VM storage layer
|
||||
func (vmc *VMContext) Storage() types.Storage {
|
||||
return vmc.storage
|
||||
}
|
||||
*/
|
||||
|
||||
func (vmc *VMContext) Ipld() *hamt.CborIpldStore {
|
||||
return vmc.cst
|
||||
@ -54,11 +88,26 @@ func (vmc *VMContext) GasUsed() types.BigInt {
|
||||
return types.NewInt(0)
|
||||
}
|
||||
|
||||
func makeVMContext(state *StateTree, msg *types.Message, height uint64) *VMContext {
|
||||
func (vmc *VMContext) StateTree() (types.StateTree, error) {
|
||||
if vmc.msg.To != InitActorAddress {
|
||||
return nil, fmt.Errorf("only init actor can access state tree directly")
|
||||
}
|
||||
|
||||
return vmc.state, nil
|
||||
}
|
||||
|
||||
func makeVMContext(state *StateTree, bs bstore.Blockstore, sroot cid.Cid, msg *types.Message, height uint64) *VMContext {
|
||||
cst := hamt.CSTFromBstore(bs)
|
||||
return &VMContext{
|
||||
state: state,
|
||||
sroot: sroot,
|
||||
msg: msg,
|
||||
height: height,
|
||||
cst: cst,
|
||||
storage: &storage{
|
||||
cst: cst,
|
||||
head: sroot,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,7 +177,7 @@ func (vm *VM) ApplyMessage(msg *types.Message) (*types.MessageReceipt, error) {
|
||||
}
|
||||
DepositFunds(toActor, msg.Value)
|
||||
|
||||
vmctx := makeVMContext(st, msg, vm.blockHeight)
|
||||
vmctx := makeVMContext(st, vm.cs.bs, toActor.Head, msg, vm.blockHeight)
|
||||
|
||||
var errcode byte
|
||||
var ret []byte
|
||||
@ -214,3 +263,18 @@ func (vm *VM) Invoke(act *types.Actor, vmctx *VMContext, method uint64, params [
|
||||
}
|
||||
return ret.result, ret.returnCode, nil
|
||||
}
|
||||
|
||||
func ComputeActorAddress(creator address.Address, nonce uint64) (address.Address, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
_, err := buf.Write(creator.Bytes())
|
||||
if err != nil {
|
||||
return address.Address{}, err
|
||||
}
|
||||
|
||||
err = binary.Write(buf, binary.BigEndian, nonce)
|
||||
if err != nil {
|
||||
return address.Address{}, err
|
||||
}
|
||||
|
||||
return address.NewActorAddress(buf.Bytes())
|
||||
}
|
||||
|
91
chain/vm_test.go
Normal file
91
chain/vm_test.go
Normal file
@ -0,0 +1,91 @@
|
||||
package chain
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
"github.com/filecoin-project/go-lotus/chain/types"
|
||||
dstore "github.com/ipfs/go-datastore"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
)
|
||||
|
||||
func blsaddr(n uint64) address.Address {
|
||||
buf := make([]byte, 48)
|
||||
binary.PutUvarint(buf, n)
|
||||
|
||||
addr, err := address.NewBLSAddress(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return addr
|
||||
}
|
||||
|
||||
func TestVMInvokeMethod(t *testing.T) {
|
||||
bs := bstore.NewBlockstore(dstore.NewMapDatastore())
|
||||
|
||||
from := blsaddr(0)
|
||||
maddr := blsaddr(1)
|
||||
|
||||
actors := map[address.Address]types.BigInt{
|
||||
from: types.NewInt(1000000),
|
||||
maddr: types.NewInt(0),
|
||||
}
|
||||
st, err := MakeInitialStateTree(bs, actors)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stateroot, err := st.Flush()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cs := &ChainStore{
|
||||
bs: bs,
|
||||
}
|
||||
|
||||
vm, err := NewVM(stateroot, 1, maddr, cs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
execparams := &ExecParams{
|
||||
Code: StorageMinerCodeCid,
|
||||
Params: []byte("cats"),
|
||||
}
|
||||
enc, err := cbor.DumpObject(execparams)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
msg := &types.Message{
|
||||
To: InitActorAddress,
|
||||
From: from,
|
||||
Method: 1,
|
||||
Params: enc,
|
||||
GasPrice: types.NewInt(1),
|
||||
GasLimit: types.NewInt(1),
|
||||
Value: types.NewInt(0),
|
||||
}
|
||||
|
||||
ret, err := vm.ApplyMessage(msg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ret.ExitCode != 0 {
|
||||
t.Fatal("invocation failed")
|
||||
}
|
||||
|
||||
outaddr, err := address.NewFromBytes(ret.Return)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if outaddr.String() != "t0102" {
|
||||
t.Fatal("hold up")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user