integrating storage market actor, includes cross actor messaging

This commit is contained in:
whyrusleeping 2019-07-12 13:56:41 -07:00
parent 60a767da7d
commit 9747ed3bef
8 changed files with 309 additions and 31 deletions

98
chain/actor_miner.go Normal file
View File

@ -0,0 +1,98 @@
package chain
import (
"github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/types"
"github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
"github.com/libp2p/go-libp2p-core/peer"
)
func init() {
cbor.RegisterCborType(StorageMinerActorState{})
cbor.RegisterCborType(StorageMinerConstructorParams{})
}
type StorageMinerActor struct{}
type StorageMinerActorState struct {
// Account that owns this miner.
// - Income and returned collateral are paid to this address.
// - This address is also allowed to change the worker address for the miner.
Owner address.Address
// Worker account for this miner.
// This will be the key that is used to sign blocks created by this miner, and
// sign messages sent on behalf of this miner to commit sectors, submit PoSts, and
// other day to day miner activities.
Worker address.Address
// Libp2p identity that should be used when connecting to this miner.
PeerID peer.ID
// Amount of space in each sector committed to the network by this miner.
SectorSize types.BigInt
// Collateral currently committed to live storage.
ActiveCollateral types.BigInt
// Collateral that is waiting to be withdrawn.
DePledgedCollateral types.BigInt
// Time at which the depledged collateral may be withdrawn.
DePledgeTime types.BigInt
// All sectors this miner has committed.
//Sectors SectorSet
// Sectors this miner is currently mining. It is only updated
// when a PoSt is submitted (not as each new sector commitment is added).
//ProvingSet SectorSet
// Sectors reported during the last PoSt submission as being 'done'. The collateral
// for them is still being held until the next PoSt submission in case early sector
// removal penalization is needed.
//NextDoneSet BitField
// Deals this miner has been slashed for since the last post submission.
ArbitratedDeals map[cid.Cid]struct{}
// Amount of power this miner has.
Power types.BigInt
// List of sectors that this miner was slashed for.
//SlashedSet SectorSet
// The height at which this miner was slashed at.
SlashedAt types.BigInt
// The amount of storage collateral that is owed to clients, and cannot be used for collateral anymore.
OwedStorageCollateral types.BigInt
}
type StorageMinerConstructorParams struct {
Worker address.Address
SectorSize types.BigInt
PeerID peer.ID
}
func (sma StorageMinerActor) StorageMinerActor(act *types.Actor, vmctx types.VMContext, params *StorageMinerConstructorParams) (InvokeRet, error) {
var self StorageMinerActorState
self.Owner = vmctx.Message().From
self.Worker = params.Worker
self.PeerID = params.PeerID
self.SectorSize = params.SectorSize
storage := vmctx.Storage()
c, err := storage.Put(self)
if err != nil {
return InvokeRet{}, err
}
if err := storage.Commit(cid.Undef, c); err != nil {
return InvokeRet{}, err
}
return InvokeRet{}, nil
}

View File

@ -0,0 +1,104 @@
package chain
import (
"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"
)
func init() {
cbor.RegisterCborType(StorageMarketState{})
}
type StorageMarketActor struct{}
func (sma StorageMarketActor) Exports() []interface{} {
return []interface{}{
nil,
sma.CreateStorageMiner,
}
}
type StorageMarketState struct {
Miners map[address.Address]struct{}
TotalStorage types.BigInt
}
type CreateStorageMinerParams struct {
Worker address.Address
SectorSize types.BigInt
PeerID peer.ID
}
func (p *CreateStorageMinerParams) UnmarshalCBOR(b []byte) (int, error) {
if err := cbor.DecodeInto(b, p); err != nil {
return 0, err
}
return len(b), nil
}
func (sma StorageMarketActor) CreateStorageMiner(act *types.Actor, vmctx types.VMContext, params *CreateStorageMinerParams) (InvokeRet, error) {
if !SupportedSectorSize(params.SectorSize) {
//Fatal("Unsupported sector size")
return InvokeRet{
returnCode: 1,
}, nil
}
var smcp StorageMinerConstructorParams
smcp.Worker = params.Worker
smcp.SectorSize = params.SectorSize
smcp.PeerID = params.PeerID
encoded, err := cbor.DumpObject(smcp)
if err != nil {
return InvokeRet{}, err
}
ret, exit, err := vmctx.Send(InitActorAddress, 1, vmctx.Message().Value, encoded)
if err != nil {
return InvokeRet{}, err
}
naddr, err := address.NewFromBytes(ret)
if err != nil {
return InvokeRet{}, err
}
if exit != 0 {
return InvokeRet{
returnCode: 2,
}, nil
}
var self StorageMarketState
old := vmctx.Storage().GetHead()
if err := vmctx.Storage().Get(old, &self); err != nil {
return InvokeRet{}, err
}
self.Miners[naddr] = struct{}{}
nroot, err := vmctx.Storage().Put(self)
if err != nil {
return InvokeRet{}, err
}
if err := vmctx.Storage().Commit(old, nroot); err != nil {
return InvokeRet{}, err
}
return InvokeRet{
result: naddr.Bytes(),
}, nil
}
func SupportedSectorSize(ssize types.BigInt) bool {
if ssize.Uint64() == 1024 {
return true
}
return false
}

View File

@ -21,12 +21,12 @@ func init() {
var addressAtlasEntry = atlas.BuildEntry(Address{}).Transform(). var addressAtlasEntry = atlas.BuildEntry(Address{}).Transform().
TransformMarshal(atlas.MakeMarshalTransformFunc( TransformMarshal(atlas.MakeMarshalTransformFunc(
func(a Address) ([]byte, error) { func(a Address) (string, error) {
return a.Bytes(), nil return string(a.Bytes()), nil
})). })).
TransformUnmarshal(atlas.MakeUnmarshalTransformFunc( TransformUnmarshal(atlas.MakeUnmarshalTransformFunc(
func(x []byte) (Address, error) { func(x string) (Address, error) {
return NewFromBytes(x) return NewFromBytes([]byte(x))
})). })).
Complete() Complete()

View File

@ -103,7 +103,6 @@ func MakeInitialStateTree(bs bstore.Blockstore, actors map[address.Address]types
return nil, err return nil, err
} }
/*
smact, err := SetupStorageMarketActor(bs) smact, err := SetupStorageMarketActor(bs)
if err != nil { if err != nil {
return nil, err return nil, err
@ -112,7 +111,6 @@ func MakeInitialStateTree(bs bstore.Blockstore, actors map[address.Address]types
if err := state.SetActor(StorageMarketAddress, smact); err != nil { if err := state.SetActor(StorageMarketAddress, smact); err != nil {
return nil, err return nil, err
} }
*/
err = state.SetActor(NetworkAddress, &types.Actor{ err = state.SetActor(NetworkAddress, &types.Actor{
Code: AccountActorCodeCid, Code: AccountActorCodeCid,
@ -137,11 +135,10 @@ func MakeInitialStateTree(bs bstore.Blockstore, actors map[address.Address]types
return state, nil return state, nil
} }
/* func SetupStorageMarketActor(bs bstore.Blockstore) (*types.Actor, error) {
func SetupStorageMarketActor(bs bstore.Blockstore) (*Actor, error) {
sms := &StorageMarketState{ sms := &StorageMarketState{
Miners: make(map[address.Address]struct{}), Miners: make(map[address.Address]struct{}),
TotalStorage: NewInt(0), TotalStorage: types.NewInt(0),
} }
stcid, err := hamt.CSTFromBstore(bs).Put(context.TODO(), sms) stcid, err := hamt.CSTFromBstore(bs).Put(context.TODO(), sms)
@ -149,14 +146,13 @@ func SetupStorageMarketActor(bs bstore.Blockstore) (*Actor, error) {
return nil, err return nil, err
} }
return &Actor{ return &types.Actor{
Code: StorageMarketActorCodeCid, Code: StorageMarketActorCodeCid,
Head: stcid, Head: stcid,
Nonce: 0, Nonce: 0,
Balance: NewInt(0), Balance: types.NewInt(0),
}, nil }, nil
} }
*/
func MakeGenesisBlock(bs bstore.Blockstore, w *Wallet) (*GenesisBootstrap, error) { func MakeGenesisBlock(bs bstore.Blockstore, w *Wallet) (*GenesisBootstrap, error) {
fmt.Println("at end of make Genesis block") fmt.Println("at end of make Genesis block")

View File

@ -27,6 +27,7 @@ func newInvoker() *invoker {
// add builtInCode using: register(cid, singleton) // add builtInCode using: register(cid, singleton)
inv.register(InitActorCodeCid, InitActor{}) inv.register(InitActorCodeCid, InitActor{})
inv.register(StorageMarketActorCodeCid, StorageMarketActor{})
return inv return inv
} }

View File

@ -1,8 +1,6 @@
package types package types
import ( import (
"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-cid"
"github.com/ipfs/go-hamt-ipld" "github.com/ipfs/go-hamt-ipld"
@ -27,7 +25,7 @@ type StateTree interface {
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 uint64, value BigInt, params []byte) ([]byte, uint8, error)
BlockHeight() uint64 BlockHeight() uint64
GasUsed() BigInt GasUsed() BigInt
Storage() Storage Storage() Storage

View File

@ -5,7 +5,6 @@ import (
"context" "context"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"math/big"
"github.com/filecoin-project/go-lotus/chain/address" "github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/types" "github.com/filecoin-project/go-lotus/chain/types"
@ -14,13 +13,13 @@ 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"
) )
type VMContext struct { type VMContext struct {
vm *VM
state *StateTree state *StateTree
msg *types.Message msg *types.Message
height uint64 height uint64
@ -75,8 +74,22 @@ func (vmc *VMContext) Ipld() *hamt.CborIpldStore {
} }
// Send allows the current execution context to invoke methods on other actors in the system // Send allows the current execution context to invoke methods on other actors in the system
func (vmc *VMContext) Send(to address.Address, method string, value *big.Int, params []interface{}) ([][]byte, uint8, error) { func (vmc *VMContext) Send(to address.Address, method uint64, value types.BigInt, params []byte) ([]byte, uint8, error) {
panic("nyi") msg := &types.Message{
To: to,
Method: method,
Value: value,
Params: params,
}
toAct, err := vmc.state.GetActor(to)
if err != nil {
return nil, 0, err
}
nvmctx := vmc.vm.makeVMContext(toAct.Head, msg)
return vmc.vm.Invoke(toAct, nvmctx, method, params)
} }
// BlockHeight returns the height of the block this message was added to the chain in // BlockHeight returns the height of the block this message was added to the chain in
@ -96,13 +109,15 @@ func (vmc *VMContext) StateTree() (types.StateTree, error) {
return vmc.state, nil return vmc.state, nil
} }
func makeVMContext(state *StateTree, bs bstore.Blockstore, sroot cid.Cid, msg *types.Message, height uint64) *VMContext { func (vm *VM) makeVMContext(sroot cid.Cid, msg *types.Message) *VMContext {
cst := hamt.CSTFromBstore(bs) cst := hamt.CSTFromBstore(vm.cs.bs)
return &VMContext{ return &VMContext{
state: state, vm: vm,
state: vm.cstate,
sroot: sroot, sroot: sroot,
msg: msg, msg: msg,
height: height, height: vm.blockHeight,
cst: cst, cst: cst,
storage: &storage{ storage: &storage{
cst: cst, cst: cst,
@ -177,7 +192,7 @@ func (vm *VM) ApplyMessage(msg *types.Message) (*types.MessageReceipt, error) {
} }
DepositFunds(toActor, msg.Value) DepositFunds(toActor, msg.Value)
vmctx := makeVMContext(st, vm.cs.bs, toActor.Head, msg, vm.blockHeight) vmctx := vm.makeVMContext(toActor.Head, msg)
var errcode byte var errcode byte
var ret []byte var ret []byte

View File

@ -89,3 +89,69 @@ func TestVMInvokeMethod(t *testing.T) {
t.Fatal("hold up") t.Fatal("hold up")
} }
} }
func TestStorageMarketActorCreateMiner(t *testing.T) {
////////// BOILERPLATE //////////
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)
}
////// END BOILERPLATE //////////
params := &StorageMinerConstructorParams{}
enc, err := cbor.DumpObject(params)
if err != nil {
t.Fatal(err)
}
msg := &types.Message{
To: StorageMarketAddress,
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")
}
}