From 6ee1b6fc842ccd1250e2ea64e93187cd8f0c0a2a Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Wed, 17 Jul 2019 15:48:20 +0200 Subject: [PATCH 1/3] Add GetPower License: MIT Signed-off-by: Jakub Sztandera --- chain/actors/actor_miner.go | 29 ++++++++++++++++++++++++++--- chain/actors/actor_storagemarket.go | 16 ++++++++++------ chain/invoker.go | 6 ++++-- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/chain/actors/actor_miner.go b/chain/actors/actor_miner.go index 33620441cdb..7c803256ebb 100644 --- a/chain/actors/actor_miner.go +++ b/chain/actors/actor_miner.go @@ -89,12 +89,24 @@ type StorageMinerConstructorParams struct { func (sma StorageMinerActor) Exports() []interface{} { return []interface{}{ - sma.StorageMinerActor, - sma.CommitSector, + 0: sma.StorageMinerConstructor, + 1: sma.CommitSector, + //2: sma.SubmitPost, + //3: sma.SlashStorageFault, + //4: sma.GetCurrentProvingSet, + //5: sma.ArbitrateDeal, + //6: sma.DePledge, + //7: sma.GetOwner, + //8: sma.GetWorkerAddr, + 9: sma.GetPower, + //10: sma.GetPeerID, + //11: sma.GetSectorSize, + //12: sma.UpdatePeerID, + //13: sma.ChangeWorker, } } -func (sma StorageMinerActor) StorageMinerActor(act *types.Actor, vmctx types.VMContext, params *StorageMinerConstructorParams) (types.InvokeRet, error) { +func (sma StorageMinerActor) StorageMinerConstructor(act *types.Actor, vmctx types.VMContext, params *StorageMinerConstructorParams) (types.InvokeRet, error) { var self StorageMinerActorState self.Owner = params.Owner self.Worker = params.Worker @@ -209,6 +221,17 @@ func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContex return types.InvokeRet{}, nil } +func (sma StorageMinerActor) GetPower(act *types.Actor, vmctx types.VMContext, params *struct{}) (types.InvokeRet, error) { + var self StorageMinerActorState + state := vmctx.Storage().GetHead() + if err := vmctx.Storage().Get(state, &self); err != nil { + return types.InvokeRet{}, err + } + return types.InvokeRet{ + Result: self.Power.Bytes(), + }, nil +} + func SectorIsUnique(cst *hamt.CborIpldStore, sroot cid.Cid, sid types.BigInt) (bool, error) { nd, err := hamt.LoadNode(context.TODO(), cst, sroot) if err != nil { diff --git a/chain/actors/actor_storagemarket.go b/chain/actors/actor_storagemarket.go index 872288465c6..b701f32643c 100644 --- a/chain/actors/actor_storagemarket.go +++ b/chain/actors/actor_storagemarket.go @@ -19,10 +19,14 @@ type StorageMarketActor struct{} func (sma StorageMarketActor) Exports() []interface{} { return []interface{}{ - nil, - sma.CreateStorageMiner, - nil, // TODO: slash consensus fault - sma.UpdateStorage, + //0: sma.StorageMarketConstructor, + 1: sma.CreateStorageMiner, + //2: sma.SlashConsensusFault, + 3: sma.UpdateStorage, + 4: sma.GetTotalStorage, + 5: sma.PowerLookup, + //6: sma.IsMiner, + //7: sma.StorageCollateralForSize, } } @@ -123,7 +127,7 @@ func (sma StorageMarketActor) UpdateStorage(act *types.Actor, vmctx types.VMCont return types.InvokeRet{}, 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{}) (types.InvokeRet, error) { var self StorageMarketState if err := vmctx.Storage().Get(vmctx.Storage().GetHead(), &self); err != nil { return types.InvokeRet{}, err @@ -151,7 +155,7 @@ func (sma StorageMarketActor) PowerLookup(act *types.Actor, vmctx types.VMContex }, nil } - ret, code, err := vmctx.Send(params.Miner, 9999, types.NewInt(0), nil) + ret, code, err := vmctx.Send(params.Miner, 9, types.NewInt(0), nil) if err != nil { return types.InvokeRet{}, err } diff --git a/chain/invoker.go b/chain/invoker.go index 79c1a50289f..21fedb0c183 100644 --- a/chain/invoker.go +++ b/chain/invoker.go @@ -63,7 +63,8 @@ func (*invoker) transform(instance Invokee) (nativeCode, error) { exports := instance.Exports() for i, m := range exports { i := i - newErr := func(str string) error { + newErr := func(format string, args ...interface{}) error { + str := fmt.Sprintf(format, args) return fmt.Errorf("transform(%s) export(%d): %s", itype.Name(), i, str) } if m == nil { @@ -86,7 +87,8 @@ func (*invoker) transform(instance Invokee) (nativeCode, error) { } if t.In(2).Kind() != reflect.Ptr { - return nil, newErr("parameter has to be a pointer to parameter") + return nil, newErr("parameter has to be a pointer to parameter, is: %s", + t.In(2).Kind()) } if t.NumOut() != 2 { From 81f03a9f68584a0db40faf555f04d8b5c24b58b1 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Wed, 17 Jul 2019 16:30:55 +0200 Subject: [PATCH 2/3] Add and test IsMiner License: MIT Signed-off-by: Jakub Sztandera --- chain/actors/actor_storagemarket.go | 32 ++++++++++++++++++---- chain/actors/actor_storagemarket_test.go | 35 +++++++++++++++++++++--- chain/actors/harness_test.go | 2 +- chain/actors/params.go | 9 ++++++ chain/vm.go | 4 ++- 5 files changed, 70 insertions(+), 12 deletions(-) create mode 100644 chain/actors/params.go diff --git a/chain/actors/actor_storagemarket.go b/chain/actors/actor_storagemarket.go index b701f32643c..8de5f52880c 100644 --- a/chain/actors/actor_storagemarket.go +++ b/chain/actors/actor_storagemarket.go @@ -13,6 +13,7 @@ const SectorSize = 1024 func init() { cbor.RegisterCborType(StorageMarketState{}) cbor.RegisterCborType(CreateStorageMinerParams{}) + cbor.RegisterCborType(IsMinerParam{}) } type StorageMarketActor struct{} @@ -25,7 +26,7 @@ func (sma StorageMarketActor) Exports() []interface{} { 3: sma.UpdateStorage, 4: sma.GetTotalStorage, 5: sma.PowerLookup, - //6: sma.IsMiner, + 6: sma.IsMiner, //7: sma.StorageCollateralForSize, } } @@ -65,17 +66,17 @@ func (sma StorageMarketActor) CreateStorageMiner(act *types.Actor, vmctx types.V return types.InvokeRet{}, err } - naddr, err := address.NewFromBytes(ret) - if err != nil { - return types.InvokeRet{}, err - } - if exit != 0 { return types.InvokeRet{ ReturnCode: 2, }, nil } + naddr, err := address.NewFromBytes(ret) + if err != nil { + return types.InvokeRet{}, err + } + var self StorageMarketState old := vmctx.Storage().GetHead() if err := vmctx.Storage().Get(old, &self); err != nil { @@ -171,3 +172,22 @@ func (sma StorageMarketActor) PowerLookup(act *types.Actor, vmctx types.VMContex Result: ret, }, nil } + +type IsMinerParam struct { + Addr address.Address +} + +func (sma StorageMarketActor) IsMiner(act *types.Actor, vmctx types.VMContext, param *IsMinerParam) (types.InvokeRet, error) { + var self StorageMarketState + if err := vmctx.Storage().Get(vmctx.Storage().GetHead(), &self); err != nil { + return types.InvokeRet{}, err + } + _, ok := self.Miners[param.Addr] + out, err := SerializeParams(ok) + if err != nil { + return types.InvokeRet{}, err + } + return types.InvokeRet{ + Result: out, + }, nil +} diff --git a/chain/actors/actor_storagemarket_test.go b/chain/actors/actor_storagemarket_test.go index 4c89da66138..719360c16ca 100644 --- a/chain/actors/actor_storagemarket_test.go +++ b/chain/actors/actor_storagemarket_test.go @@ -11,7 +11,7 @@ import ( func TestStorageMarketCreateMiner(t *testing.T) { h := NewHarness(t) - var outaddr address.Address + var sminer address.Address h.Steps = []Step{ { M: types.Message{ @@ -34,19 +34,46 @@ func TestStorageMarketCreateMiner(t *testing.T) { } var err error - outaddr, err = address.NewFromBytes(ret.Return) + sminer, err = address.NewFromBytes(ret.Return) if err != nil { t.Fatal(err) } - if outaddr.String() != "t0102" { + if sminer.String() != "t0102" { t.Fatal("hold up") } + h.Steps[1].M.Params = h.DumpObject(&IsMinerParam{Addr: sminer}) + }, + }, + { + M: types.Message{ + To: StorageMarketAddress, + From: h.From, + Method: 6, + GasPrice: types.NewInt(1), + GasLimit: types.NewInt(1), + Value: types.NewInt(0), + Nonce: 1, + // Params is sent in previous set + }, + Ret: func(t *testing.T, ret *types.MessageReceipt) { + if ret.ExitCode != 0 { + t.Fatal("invokation failed: ", ret.ExitCode) + } + var output bool + err := cbor.DecodeInto(ret.Return, &output) + if err != nil { + t.Fatalf("error decoding: %+v", err) + } + + if !output { + t.Fatalf("%s is miner but IsMiner call returned false", sminer) + } }, }, } state := h.Execute() - act, err := state.GetActor(outaddr) + act, err := state.GetActor(sminer) if err != nil { t.Fatal(err) } diff --git a/chain/actors/harness_test.go b/chain/actors/harness_test.go index 8b275d653eb..06a1c46d198 100644 --- a/chain/actors/harness_test.go +++ b/chain/actors/harness_test.go @@ -103,7 +103,7 @@ func (h *Harness) DumpObject(obj interface{}) []byte { } func (h *Harness) NoError(t *testing.T, err error) { if err != nil { - t.Fatalf("Error in step %d: %s", h.currStep, err) + t.Fatalf("Error in step %d: %+v", h.currStep, err) } } diff --git a/chain/actors/params.go b/chain/actors/params.go new file mode 100644 index 00000000000..124498fa964 --- /dev/null +++ b/chain/actors/params.go @@ -0,0 +1,9 @@ +package actors + +import ( + cbor "github.com/ipfs/go-ipld-cbor" +) + +func SerializeParams(i interface{}) ([]byte, error) { + return cbor.DumpObject(i) +} diff --git a/chain/vm.go b/chain/vm.go index 6c5e2f41826..7c7778422a2 100644 --- a/chain/vm.go +++ b/chain/vm.go @@ -30,7 +30,7 @@ type VMContext struct { // address that started invokation chain origin address.Address - storage types.Storage + storage *storage } // Message is the message that kicked off the current invocation @@ -226,6 +226,8 @@ func (vm *VM) ApplyMessage(msg *types.Message) (*types.MessageReceipt, error) { panic("invariant violated: " + err.Error()) } } else { + // Update actor head reference + toActor.Head = vmctx.storage.head // refund unused gas refund := types.BigMul(types.BigSub(msg.GasLimit, vmctx.GasUsed()), msg.GasPrice) DepositFunds(fromActor, refund) From 9597ed8498215cc8d4cd93f9e9e218162b369c87 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Wed, 17 Jul 2019 18:00:59 +0200 Subject: [PATCH 3/3] Make PowerLookup work and test it License: MIT Signed-off-by: Jakub Sztandera --- chain/actors/actor_storagemarket.go | 8 ++++--- chain/actors/actor_storagemarket_test.go | 28 ++++++++++++++++++++++++ chain/actors/params.go | 4 ++++ chain/invoker.go | 5 +++-- chain/vm.go | 2 +- 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/chain/actors/actor_storagemarket.go b/chain/actors/actor_storagemarket.go index 8de5f52880c..4b7c8f61861 100644 --- a/chain/actors/actor_storagemarket.go +++ b/chain/actors/actor_storagemarket.go @@ -6,6 +6,7 @@ import ( cbor "github.com/ipfs/go-ipld-cbor" "github.com/libp2p/go-libp2p-core/peer" + "golang.org/x/xerrors" ) const SectorSize = 1024 @@ -14,6 +15,7 @@ func init() { cbor.RegisterCborType(StorageMarketState{}) cbor.RegisterCborType(CreateStorageMinerParams{}) cbor.RegisterCborType(IsMinerParam{}) + cbor.RegisterCborType(PowerLookupParams{}) } type StorageMarketActor struct{} @@ -146,7 +148,7 @@ type PowerLookupParams struct { func (sma StorageMarketActor) PowerLookup(act *types.Actor, vmctx types.VMContext, params *PowerLookupParams) (types.InvokeRet, error) { var self StorageMarketState if err := vmctx.Storage().Get(vmctx.Storage().GetHead(), &self); err != nil { - return types.InvokeRet{}, err + return types.InvokeRet{}, xerrors.Errorf("getting head: %w", err) } if _, ok := self.Miners[params.Miner]; !ok { @@ -156,9 +158,9 @@ func (sma StorageMarketActor) PowerLookup(act *types.Actor, vmctx types.VMContex }, nil } - ret, code, err := vmctx.Send(params.Miner, 9, types.NewInt(0), nil) + ret, code, err := vmctx.Send(params.Miner, 9, types.NewInt(0), EmptyStructCBOR) if err != nil { - return types.InvokeRet{}, err + return types.InvokeRet{}, xerrors.Errorf("invoke Miner.GetPower: %w", err) } if code != 0 { diff --git a/chain/actors/actor_storagemarket_test.go b/chain/actors/actor_storagemarket_test.go index 719360c16ca..cb525579006 100644 --- a/chain/actors/actor_storagemarket_test.go +++ b/chain/actors/actor_storagemarket_test.go @@ -9,6 +9,11 @@ import ( cbor "github.com/ipfs/go-ipld-cbor" ) +func TestDumpEmpyStruct(t *testing.T) { + res, err := SerializeParams(struct{}{}) + t.Logf("res: %x, err: %+v", res, err) +} + func TestStorageMarketCreateMiner(t *testing.T) { h := NewHarness(t) var sminer address.Address @@ -43,6 +48,7 @@ func TestStorageMarketCreateMiner(t *testing.T) { t.Fatal("hold up") } h.Steps[1].M.Params = h.DumpObject(&IsMinerParam{Addr: sminer}) + h.Steps[2].M.Params = h.DumpObject(&PowerLookupParams{Miner: sminer}) }, }, { @@ -71,6 +77,28 @@ func TestStorageMarketCreateMiner(t *testing.T) { } }, }, + { + M: types.Message{ + To: StorageMarketAddress, + From: h.From, + Method: 5, + GasPrice: types.NewInt(1), + GasLimit: types.NewInt(1), + Value: types.NewInt(0), + Nonce: 2, + // Params is sent in previous set + }, + Ret: func(t *testing.T, ret *types.MessageReceipt) { + if ret.ExitCode != 0 { + t.Fatal("invokation failed: ", ret.ExitCode) + } + power := types.BigFromBytes(ret.Return) + + if types.BigCmp(power, types.NewInt(0)) != 0 { + t.Fatalf("power should be zero, is: %s", power) + } + }, + }, } state := h.Execute() act, err := state.GetActor(sminer) diff --git a/chain/actors/params.go b/chain/actors/params.go index 124498fa964..83fc39fca5c 100644 --- a/chain/actors/params.go +++ b/chain/actors/params.go @@ -4,6 +4,10 @@ import ( cbor "github.com/ipfs/go-ipld-cbor" ) +var ( + EmptyStructCBOR = []byte{0xa0} +) + func SerializeParams(i interface{}) ([]byte, error) { return cbor.DumpObject(i) } diff --git a/chain/invoker.go b/chain/invoker.go index 21fedb0c183..52bde0c7d8d 100644 --- a/chain/invoker.go +++ b/chain/invoker.go @@ -8,6 +8,7 @@ import ( "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 { @@ -34,10 +35,10 @@ func (inv *invoker) Invoke(act *types.Actor, vmctx *VMContext, method uint64, pa code, ok := inv.builtInCode[act.Code] if !ok { - return types.InvokeRet{}, fmt.Errorf("no code for actor %s", act.Code) + return types.InvokeRet{}, xerrors.Errorf("no code for actor %s", act.Code) } if method >= uint64(len(code)) || code[method] == nil { - return types.InvokeRet{}, fmt.Errorf("no method %d on actor", method) + return types.InvokeRet{}, xerrors.Errorf("no method %d on actor", method) } return code[method](act, vmctx, params) diff --git a/chain/vm.go b/chain/vm.go index 7c7778422a2..22114462c6e 100644 --- a/chain/vm.go +++ b/chain/vm.go @@ -215,7 +215,7 @@ func (vm *VM) ApplyMessage(msg *types.Message) (*types.MessageReceipt, error) { if msg.Method != 0 { ret, errcode, err = vm.Invoke(toActor, vmctx, msg.Method, msg.Params) if err != nil { - return nil, err + return nil, xerrors.Errorf("during invoke: %w", err) } if errcode != 0 {