integrate init actor to vm invoker
more wiring Add a test for the basic init.exec running and make it pass fix bad block comment License: MIT Signed-off-by: Jakub Sztandera <kubuxu@protonmail.ch>
This commit is contained in:
parent
e720f5d3a6
commit
c4022505c7
183
chain/actor_init.go
Normal file
183
chain/actor_init.go
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
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 successfull.
|
||||||
|
// 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
|
||||||
|
_ = actor
|
||||||
|
//if err := vmctx.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
|
package chain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"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"
|
||||||
hamt "github.com/ipfs/go-hamt-ipld"
|
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
mh "github.com/multiformats/go-multihash"
|
mh "github.com/multiformats/go-multihash"
|
||||||
)
|
)
|
||||||
@ -54,58 +50,3 @@ func init() {
|
|||||||
|
|
||||||
type VMActor struct {
|
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/filecoin-project/go-lotus/chain/types"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
datastore "github.com/ipfs/go-datastore"
|
|
||||||
dstore "github.com/ipfs/go-datastore"
|
dstore "github.com/ipfs/go-datastore"
|
||||||
hamt "github.com/ipfs/go-hamt-ipld"
|
hamt "github.com/ipfs/go-hamt-ipld"
|
||||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||||
@ -78,7 +77,7 @@ func init() {
|
|||||||
|
|
||||||
var EmptyObjectCid cid.Cid
|
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)
|
cst := hamt.CSTFromBstore(bs)
|
||||||
state, err := NewStateTree(cst)
|
state, err := NewStateTree(cst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -90,12 +89,12 @@ func MakeGenesisBlock(bs bstore.Blockstore, w *Wallet) (*GenesisBootstrap, error
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
minerAddr, err := w.GenerateKey(KTSecp256k1)
|
var addrs []address.Address
|
||||||
if err != nil {
|
for a := range actors {
|
||||||
return nil, err
|
addrs = append(addrs, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
initact, err := SetupInitActor(bs, []address.Address{minerAddr})
|
initact, err := SetupInitActor(bs, addrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -104,6 +103,17 @@ func MakeGenesisBlock(bs bstore.Blockstore, w *Wallet) (*GenesisBootstrap, error
|
|||||||
return nil, err
|
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{
|
err = state.SetActor(NetworkAddress, &types.Actor{
|
||||||
Code: AccountActorCodeCid,
|
Code: AccountActorCodeCid,
|
||||||
Balance: types.NewInt(100000000000),
|
Balance: types.NewInt(100000000000),
|
||||||
@ -113,22 +123,64 @@ func MakeGenesisBlock(bs bstore.Blockstore, w *Wallet) (*GenesisBootstrap, error
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = state.SetActor(minerAddr, &types.Actor{
|
for a, v := range actors {
|
||||||
Code: AccountActorCodeCid,
|
err = state.SetActor(a, &types.Actor{
|
||||||
Balance: types.NewInt(5000000),
|
Code: AccountActorCodeCid,
|
||||||
Head: emptyobject,
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fmt.Println("about to flush state...")
|
|
||||||
|
|
||||||
stateroot, err := state.Flush()
|
stateroot, err := state.Flush()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fmt.Println("at end of make Genesis block")
|
|
||||||
|
|
||||||
|
cst := hamt.CSTFromBstore(bs)
|
||||||
emptyroot, err := sharray.Build(context.TODO(), 4, []interface{}{}, cst)
|
emptyroot, err := sharray.Build(context.TODO(), 4, []interface{}{}, cst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -164,7 +216,7 @@ func MakeGenesisBlock(bs bstore.Blockstore, w *Wallet) (*GenesisBootstrap, error
|
|||||||
|
|
||||||
type ChainStore struct {
|
type ChainStore struct {
|
||||||
bs bstore.Blockstore
|
bs bstore.Blockstore
|
||||||
ds datastore.Datastore
|
ds dstore.Datastore
|
||||||
|
|
||||||
heaviestLk sync.Mutex
|
heaviestLk sync.Mutex
|
||||||
heaviest *TipSet
|
heaviest *TipSet
|
||||||
@ -174,7 +226,7 @@ type ChainStore struct {
|
|||||||
headChange func(rev, app []*TipSet) error
|
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{
|
return &ChainStore{
|
||||||
bs: bs,
|
bs: bs,
|
||||||
ds: ds,
|
ds: ds,
|
||||||
@ -204,7 +256,7 @@ func (cs *ChainStore) SetGenesis(b *BlockHeader) error {
|
|||||||
return err
|
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 {
|
func (cs *ChainStore) PutTipSet(ts *FullTipSet) error {
|
||||||
@ -379,7 +431,7 @@ func (cs *ChainStore) AddBlock(b *BlockHeader) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cs *ChainStore) GetGenesis() (*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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,10 @@ func newInvoker() *invoker {
|
|||||||
inv := &invoker{
|
inv := &invoker{
|
||||||
builtInCode: make(map[cid.Cid]nativeCode),
|
builtInCode: make(map[cid.Cid]nativeCode),
|
||||||
}
|
}
|
||||||
|
|
||||||
// add builtInCode using: register(cid, singleton)
|
// add builtInCode using: register(cid, singleton)
|
||||||
|
inv.register(InitActorCodeCid, InitActor{})
|
||||||
|
|
||||||
return inv
|
return inv
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,13 +4,26 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"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-hamt-ipld"
|
"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 VMContext interface {
|
type VMContext interface {
|
||||||
Message() *Message
|
Message() *Message
|
||||||
Ipld() *hamt.CborIpldStore
|
Ipld() *hamt.CborIpldStore
|
||||||
Send(to address.Address, method string, value *big.Int, params []interface{}) ([][]byte, uint8, error)
|
Send(to address.Address, method string, value *big.Int, params []interface{}) ([][]byte, uint8, error)
|
||||||
BlockHeight() uint64
|
BlockHeight() uint64
|
||||||
GasUsed() BigInt
|
GasUsed() BigInt
|
||||||
|
Storage() Storage
|
||||||
}
|
}
|
||||||
|
64
chain/vm.go
64
chain/vm.go
@ -1,7 +1,9 @@
|
|||||||
package chain
|
package chain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
@ -12,6 +14,7 @@ import (
|
|||||||
bserv "github.com/ipfs/go-blockservice"
|
bserv "github.com/ipfs/go-blockservice"
|
||||||
cid "github.com/ipfs/go-cid"
|
cid "github.com/ipfs/go-cid"
|
||||||
hamt "github.com/ipfs/go-hamt-ipld"
|
hamt "github.com/ipfs/go-hamt-ipld"
|
||||||
|
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||||
ipld "github.com/ipfs/go-ipld-format"
|
ipld "github.com/ipfs/go-ipld-format"
|
||||||
dag "github.com/ipfs/go-merkledag"
|
dag "github.com/ipfs/go-merkledag"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -22,6 +25,11 @@ type VMContext struct {
|
|||||||
msg *types.Message
|
msg *types.Message
|
||||||
height uint64
|
height uint64
|
||||||
cst *hamt.CborIpldStore
|
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
|
// Message is the message that kicked off the current invocation
|
||||||
@ -29,12 +37,38 @@ func (vmc *VMContext) Message() *types.Message {
|
|||||||
return vmc.msg
|
return vmc.msg
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
type storage struct {
|
||||||
// Storage provides access to the VM storage layer
|
// would be great to stop depending on this crap everywhere
|
||||||
func (vmc *VMContext) Storage() Storage {
|
// I am my own worst enemy
|
||||||
panic("nyi")
|
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 {
|
func (vmc *VMContext) Ipld() *hamt.CborIpldStore {
|
||||||
return vmc.cst
|
return vmc.cst
|
||||||
@ -54,11 +88,18 @@ func (vmc *VMContext) GasUsed() types.BigInt {
|
|||||||
return types.NewInt(0)
|
return types.NewInt(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeVMContext(state *StateTree, msg *types.Message, height uint64) *VMContext {
|
func makeVMContext(state *StateTree, bs bstore.Blockstore, sroot cid.Cid, msg *types.Message, height uint64) *VMContext {
|
||||||
|
cst := hamt.CSTFromBstore(bs)
|
||||||
return &VMContext{
|
return &VMContext{
|
||||||
state: state,
|
state: state,
|
||||||
|
sroot: sroot,
|
||||||
msg: msg,
|
msg: msg,
|
||||||
height: height,
|
height: height,
|
||||||
|
cst: cst,
|
||||||
|
storage: &storage{
|
||||||
|
cst: cst,
|
||||||
|
head: sroot,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +169,7 @@ func (vm *VM) ApplyMessage(msg *types.Message) (*types.MessageReceipt, error) {
|
|||||||
}
|
}
|
||||||
DepositFunds(toActor, msg.Value)
|
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 errcode byte
|
||||||
var ret []byte
|
var ret []byte
|
||||||
@ -214,3 +255,12 @@ func (vm *VM) Invoke(act *types.Actor, vmctx *VMContext, method uint64, params [
|
|||||||
}
|
}
|
||||||
return ret.result, ret.returnCode, nil
|
return ret.result, ret.returnCode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ComputeActorAddress(creator address.Address, nonce uint64) (address.Address, error) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
buf.Write(creator.Bytes())
|
||||||
|
|
||||||
|
binary.Write(buf, binary.BigEndian, nonce)
|
||||||
|
|
||||||
|
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