diff --git a/.gitignore b/.gitignore index 05f762d8d..fd51881b7 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ /lotus-bench /lotus-gateway /lotus-pcr +/lotus-wallet /bench.json /lotuspond/front/node_modules /lotuspond/front/build diff --git a/Makefile b/Makefile index 56ab361ec..79f7fa81e 100644 --- a/Makefile +++ b/Makefile @@ -186,6 +186,12 @@ lotus-health: .PHONY: lotus-health BINS+=lotus-health +lotus-wallet: + rm -f lotus-wallet + go build -o lotus-wallet ./cmd/lotus-wallet +.PHONY: lotus-wallet +BINS+=lotus-wallet + testground: go build -tags testground -o /dev/null ./cmd/lotus .PHONY: testground diff --git a/api/api_full.go b/api/api_full.go index 777e996cb..7ebc8791a 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -422,8 +422,7 @@ type FullNode interface { // MsigGetAvailableBalance returns the portion of a multisig's balance that can be withdrawn or spent MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) - // MsigGetLockedBalance returns the locked balance of an msig at a vien epoch. - // The return may be greater than the multisig actor's actual balance. + // MsigGetVestingSchedule returns the vesting details of a given multisig. MsigGetVestingSchedule(context.Context, address.Address, types.TipSetKey) (MsigVesting, error) // MsigGetVested returns the amount of FIL that vested in a multisig in a certain period. // It takes the following params: , , diff --git a/api/api_wallet.go b/api/api_wallet.go new file mode 100644 index 000000000..1213ffc1d --- /dev/null +++ b/api/api_wallet.go @@ -0,0 +1,47 @@ +package api + +import ( + "context" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/crypto" + + "github.com/filecoin-project/lotus/chain/types" +) + +type MsgType string + +const ( + MTUnknown = "unknown" + + // Signing message CID. MsgMeta.Extra contains raw cbor message bytes + MTChainMsg = "message" + + // Signing a blockheader. signing raw cbor block bytes (MsgMeta.Extra is empty) + MTBlock = "block" + + // Signing a deal proposal. signing raw cbor proposal bytes (MsgMeta.Extra is empty) + MTDealProposal = "dealproposal" + + // TODO: Deals, Vouchers, VRF +) + +type MsgMeta struct { + Type MsgType + + // Additional data related to what is signed. Should be verifiable with the + // signed bytes (e.g. CID(Extra).Bytes() == toSign) + Extra []byte +} + +type WalletAPI interface { + WalletNew(context.Context, crypto.SigType) (address.Address, error) + WalletHas(context.Context, address.Address) (bool, error) + WalletList(context.Context) ([]address.Address, error) + + WalletSign(ctx context.Context, signer address.Address, toSign []byte, meta MsgMeta) (*crypto.Signature, error) + + WalletExport(context.Context, address.Address) (*types.KeyInfo, error) + WalletImport(context.Context, *types.KeyInfo) (address.Address, error) + WalletDelete(context.Context, address.Address) error +} diff --git a/api/apistruct/permissioned.go b/api/apistruct/permissioned.go index c93662733..86902d31b 100644 --- a/api/apistruct/permissioned.go +++ b/api/apistruct/permissioned.go @@ -36,3 +36,9 @@ func PermissionedWorkerAPI(a api.WorkerAPI) api.WorkerAPI { auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal) return &out } + +func PermissionedWalletAPI(a api.WalletAPI) api.WalletAPI { + var out WalletStruct + auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal) + return &out +} diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index df84eac80..348e8a6de 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -379,6 +379,18 @@ type GatewayStruct struct { } } +type WalletStruct struct { + Internal struct { + WalletNew func(context.Context, crypto.SigType) (address.Address, error) `perm:"write"` + WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"` + WalletList func(context.Context) ([]address.Address, error) `perm:"write"` + WalletSign func(context.Context, address.Address, []byte, api.MsgMeta) (*crypto.Signature, error) `perm:"sign"` + WalletExport func(context.Context, address.Address) (*types.KeyInfo, error) `perm:"admin"` + WalletImport func(context.Context, *types.KeyInfo) (address.Address, error) `perm:"admin"` + WalletDelete func(context.Context, address.Address) error `perm:"write"` + } +} + // CommonStruct func (c *CommonStruct) AuthVerify(ctx context.Context, token string) ([]auth.Permission, error) { @@ -1438,8 +1450,37 @@ func (g GatewayStruct) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence return g.Internal.StateWaitMsg(ctx, msg, confidence) } +func (c *WalletStruct) WalletNew(ctx context.Context, typ crypto.SigType) (address.Address, error) { + return c.Internal.WalletNew(ctx, typ) +} + +func (c *WalletStruct) WalletHas(ctx context.Context, addr address.Address) (bool, error) { + return c.Internal.WalletHas(ctx, addr) +} + +func (c *WalletStruct) WalletList(ctx context.Context) ([]address.Address, error) { + return c.Internal.WalletList(ctx) +} + +func (c *WalletStruct) WalletSign(ctx context.Context, k address.Address, msg []byte, meta api.MsgMeta) (*crypto.Signature, error) { + return c.Internal.WalletSign(ctx, k, msg, meta) +} + +func (c *WalletStruct) WalletExport(ctx context.Context, a address.Address) (*types.KeyInfo, error) { + return c.Internal.WalletExport(ctx, a) +} + +func (c *WalletStruct) WalletImport(ctx context.Context, ki *types.KeyInfo) (address.Address, error) { + return c.Internal.WalletImport(ctx, ki) +} + +func (c *WalletStruct) WalletDelete(ctx context.Context, addr address.Address) error { + return c.Internal.WalletDelete(ctx, addr) +} + var _ api.Common = &CommonStruct{} var _ api.FullNode = &FullNodeStruct{} var _ api.StorageMiner = &StorageMinerStruct{} var _ api.WorkerAPI = &WorkerStruct{} var _ api.GatewayAPI = &GatewayStruct{} +var _ api.WalletAPI = &WalletStruct{} diff --git a/api/client/client.go b/api/client/client.go index 390ce93d7..7d8a466d3 100644 --- a/api/client/client.go +++ b/api/client/client.go @@ -96,3 +96,15 @@ func NewGatewayRPC(ctx context.Context, addr string, requestHeader http.Header, return &res, closer, err } + +func NewWalletRPC(ctx context.Context, addr string, requestHeader http.Header) (api.WalletAPI, jsonrpc.ClientCloser, error) { + var res apistruct.WalletStruct + closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin", + []interface{}{ + &res.Internal, + }, + requestHeader, + ) + + return &res, closer, err +} diff --git a/chain/gen/gen.go b/chain/gen/gen.go index a1d9a3f7e..9133f14b4 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -72,7 +72,7 @@ type ChainGen struct { GetMessages func(*ChainGen) ([]*types.SignedMessage, error) - w *wallet.Wallet + w *wallet.LocalWallet eppProvs map[address.Address]WinningPoStProver Miners []address.Address @@ -155,14 +155,14 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) { return nil, xerrors.Errorf("creating memrepo wallet failed: %w", err) } - banker, err := w.GenerateKey(crypto.SigTypeSecp256k1) + banker, err := w.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { return nil, xerrors.Errorf("failed to generate banker key: %w", err) } receievers := make([]address.Address, msgsPerBlock) for r := range receievers { - receievers[r], err = w.GenerateKey(crypto.SigTypeBLS) + receievers[r], err = w.WalletNew(context.Background(), crypto.SigTypeBLS) if err != nil { return nil, xerrors.Errorf("failed to generate receiver key: %w", err) } @@ -192,11 +192,11 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) { return nil, err } - mk1, err := w.Import(k1) + mk1, err := w.WalletImport(context.Background(), k1) if err != nil { return nil, err } - mk2, err := w.Import(k2) + mk2, err := w.WalletImport(context.Background(), k2) if err != nil { return nil, err } @@ -376,7 +376,13 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add return nil, nil, nil, xerrors.Errorf("get miner worker: %w", err) } - vrfout, err := ComputeVRF(ctx, cg.w.Sign, worker, ticketRand) + sf := func(ctx context.Context, a address.Address, i []byte) (*crypto.Signature, error) { + return cg.w.WalletSign(ctx, a, i, api.MsgMeta{ + Type: api.MTUnknown, + }) + } + + vrfout, err := ComputeVRF(ctx, sf, worker, ticketRand) if err != nil { return nil, nil, nil, xerrors.Errorf("compute VRF: %w", err) } @@ -508,7 +514,7 @@ func (cg *ChainGen) Banker() address.Address { return cg.banker } -func (cg *ChainGen) Wallet() *wallet.Wallet { +func (cg *ChainGen) Wallet() *wallet.LocalWallet { return cg.w } @@ -530,7 +536,9 @@ func getRandomMessages(cg *ChainGen) ([]*types.SignedMessage, error) { GasPremium: types.NewInt(0), } - sig, err := cg.w.Sign(context.TODO(), cg.banker, msg.Cid().Bytes()) + sig, err := cg.w.WalletSign(context.TODO(), cg.banker, msg.Cid().Bytes(), api.MsgMeta{ + Type: api.MTUnknown, // testing + }) if err != nil { return nil, err } @@ -561,7 +569,7 @@ type MiningCheckAPI interface { } type mca struct { - w *wallet.Wallet + w *wallet.LocalWallet sm *stmgr.StateManager pv ffiwrapper.Verifier bcn beacon.Schedule @@ -590,7 +598,9 @@ func (mca mca) MinerGetBaseInfo(ctx context.Context, maddr address.Address, epoc } func (mca mca) WalletSign(ctx context.Context, a address.Address, v []byte) (*crypto.Signature, error) { - return mca.w.Sign(ctx, a, v) + return mca.w.WalletSign(ctx, a, v, api.MsgMeta{ + Type: api.MTUnknown, + }) } type WinningPoStProver interface { diff --git a/chain/gen/mining.go b/chain/gen/mining.go index dd867da48..45a089452 100644 --- a/chain/gen/mining.go +++ b/chain/gen/mining.go @@ -15,11 +15,10 @@ import ( "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" - "github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/lotus/lib/sigs/bls" ) -func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wallet, bt *api.BlockTemplate) (*types.FullBlock, error) { +func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w api.WalletAPI, bt *api.BlockTemplate) (*types.FullBlock, error) { pts, err := sm.ChainStore().LoadTipSet(bt.Parents) if err != nil { @@ -131,7 +130,9 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal return nil, xerrors.Errorf("failed to get signing bytes for block: %w", err) } - sig, err := w.Sign(ctx, waddr, nosigbytes) + sig, err := w.WalletSign(ctx, waddr, nosigbytes, api.MsgMeta{ + Type: api.MTBlock, + }) if err != nil { return nil, xerrors.Errorf("failed to sign new block: %w", err) } diff --git a/chain/messagepool/messagepool_test.go b/chain/messagepool/messagepool_test.go index afb1efde2..063e0bbab 100644 --- a/chain/messagepool/messagepool_test.go +++ b/chain/messagepool/messagepool_test.go @@ -232,7 +232,7 @@ func TestMessagePool(t *testing.T) { a := tma.nextBlock() - sender, err := w.GenerateKey(crypto.SigTypeBLS) + sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS) if err != nil { t.Fatal(err) } @@ -273,7 +273,7 @@ func TestMessagePoolMessagesInEachBlock(t *testing.T) { a := tma.nextBlock() - sender, err := w.GenerateKey(crypto.SigTypeBLS) + sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS) if err != nil { t.Fatal(err) } @@ -323,7 +323,7 @@ func TestRevertMessages(t *testing.T) { a := tma.nextBlock() b := tma.nextBlock() - sender, err := w.GenerateKey(crypto.SigTypeBLS) + sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS) if err != nil { t.Fatal(err) } @@ -386,7 +386,7 @@ func TestPruningSimple(t *testing.T) { a := tma.nextBlock() tma.applyBlock(t, a) - sender, err := w.GenerateKey(crypto.SigTypeBLS) + sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS) if err != nil { t.Fatal(err) } @@ -433,7 +433,7 @@ func TestLoadLocal(t *testing.T) { t.Fatal(err) } - a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) + a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -443,7 +443,7 @@ func TestLoadLocal(t *testing.T) { t.Fatal(err) } - a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) + a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -505,7 +505,7 @@ func TestClearAll(t *testing.T) { t.Fatal(err) } - a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) + a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -515,7 +515,7 @@ func TestClearAll(t *testing.T) { t.Fatal(err) } - a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) + a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -559,7 +559,7 @@ func TestClearNonLocal(t *testing.T) { t.Fatal(err) } - a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) + a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -569,7 +569,7 @@ func TestClearNonLocal(t *testing.T) { t.Fatal(err) } - a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) + a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -620,7 +620,7 @@ func TestUpdates(t *testing.T) { t.Fatal(err) } - a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) + a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -630,7 +630,7 @@ func TestUpdates(t *testing.T) { t.Fatal(err) } - a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) + a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } diff --git a/chain/messagepool/repub_test.go b/chain/messagepool/repub_test.go index 5cb99f836..3e1252eec 100644 --- a/chain/messagepool/repub_test.go +++ b/chain/messagepool/repub_test.go @@ -1,6 +1,7 @@ package messagepool import ( + "context" "testing" "time" @@ -32,7 +33,7 @@ func TestRepubMessages(t *testing.T) { t.Fatal(err) } - a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) + a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -42,7 +43,7 @@ func TestRepubMessages(t *testing.T) { t.Fatal(err) } - a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) + a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index ca95b9621..9e4fe39e5 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -13,6 +13,10 @@ import ( "sort" "testing" + "github.com/ipfs/go-cid" + "github.com/ipfs/go-datastore" + logging "github.com/ipfs/go-log" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/build" @@ -21,12 +25,10 @@ import ( "github.com/filecoin-project/lotus/chain/types/mock" "github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/ipfs/go-cid" - "github.com/ipfs/go-datastore" + "github.com/filecoin-project/lotus/api" _ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "github.com/filecoin-project/lotus/lib/sigs/secp" - logging "github.com/ipfs/go-log" ) func init() { @@ -34,7 +36,7 @@ func init() { MaxActorPendingMessages = 1000000 } -func makeTestMessage(w *wallet.Wallet, from, to address.Address, nonce uint64, gasLimit int64, gasPrice uint64) *types.SignedMessage { +func makeTestMessage(w *wallet.LocalWallet, from, to address.Address, nonce uint64, gasLimit int64, gasPrice uint64) *types.SignedMessage { msg := &types.Message{ From: from, To: to, @@ -45,7 +47,7 @@ func makeTestMessage(w *wallet.Wallet, from, to address.Address, nonce uint64, g GasFeeCap: types.NewInt(100 + gasPrice), GasPremium: types.NewInt(gasPrice), } - sig, err := w.Sign(context.TODO(), from, msg.Cid().Bytes()) + sig, err := w.WalletSign(context.TODO(), from, msg.Cid().Bytes(), api.MsgMeta{}) if err != nil { panic(err) } @@ -75,7 +77,7 @@ func TestMessageChains(t *testing.T) { t.Fatal(err) } - a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) + a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -85,7 +87,7 @@ func TestMessageChains(t *testing.T) { t.Fatal(err) } - a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) + a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -313,7 +315,7 @@ func TestMessageChainSkipping(t *testing.T) { t.Fatal(err) } - a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) + a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -323,7 +325,7 @@ func TestMessageChainSkipping(t *testing.T) { t.Fatal(err) } - a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) + a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -389,7 +391,7 @@ func TestBasicMessageSelection(t *testing.T) { t.Fatal(err) } - a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) + a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -399,7 +401,7 @@ func TestBasicMessageSelection(t *testing.T) { t.Fatal(err) } - a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) + a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -533,7 +535,7 @@ func TestMessageSelectionTrimming(t *testing.T) { t.Fatal(err) } - a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) + a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -543,7 +545,7 @@ func TestMessageSelectionTrimming(t *testing.T) { t.Fatal(err) } - a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) + a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -596,7 +598,7 @@ func TestPriorityMessageSelection(t *testing.T) { t.Fatal(err) } - a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) + a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -606,7 +608,7 @@ func TestPriorityMessageSelection(t *testing.T) { t.Fatal(err) } - a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) + a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -675,7 +677,7 @@ func TestPriorityMessageSelection2(t *testing.T) { t.Fatal(err) } - a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) + a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -685,7 +687,7 @@ func TestPriorityMessageSelection2(t *testing.T) { t.Fatal(err) } - a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) + a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -744,7 +746,7 @@ func TestPriorityMessageSelection3(t *testing.T) { t.Fatal(err) } - a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) + a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -754,7 +756,7 @@ func TestPriorityMessageSelection3(t *testing.T) { t.Fatal(err) } - a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) + a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -841,7 +843,7 @@ func TestOptimalMessageSelection1(t *testing.T) { t.Fatal(err) } - a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) + a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -851,7 +853,7 @@ func TestOptimalMessageSelection1(t *testing.T) { t.Fatal(err) } - a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) + a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -908,7 +910,7 @@ func TestOptimalMessageSelection2(t *testing.T) { t.Fatal(err) } - a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) + a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -918,7 +920,7 @@ func TestOptimalMessageSelection2(t *testing.T) { t.Fatal(err) } - a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) + a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -984,7 +986,7 @@ func TestOptimalMessageSelection3(t *testing.T) { nActors := 10 // the actors var actors []address.Address - var wallets []*wallet.Wallet + var wallets []*wallet.LocalWallet for i := 0; i < nActors; i++ { w, err := wallet.NewWallet(wallet.NewMemKeyStore()) @@ -992,7 +994,7 @@ func TestOptimalMessageSelection3(t *testing.T) { t.Fatal(err) } - a, err := w.GenerateKey(crypto.SigTypeSecp256k1) + a, err := w.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -1064,7 +1066,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu nActors := 300 // the actors var actors []address.Address - var wallets []*wallet.Wallet + var wallets []*wallet.LocalWallet for i := 0; i < nActors; i++ { w, err := wallet.NewWallet(wallet.NewMemKeyStore()) @@ -1072,7 +1074,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu t.Fatal(err) } - a, err := w.GenerateKey(crypto.SigTypeSecp256k1) + a, err := w.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -1330,7 +1332,7 @@ readLoop: } actorMap := make(map[address.Address]address.Address) - actorWallets := make(map[address.Address]*wallet.Wallet) + actorWallets := make(map[address.Address]api.WalletAPI) for _, m := range msgs { baseNonce := baseNonces[m.Message.From] @@ -1342,7 +1344,7 @@ readLoop: t.Fatal(err) } - a, err := w.GenerateKey(crypto.SigTypeSecp256k1) + a, err := w.WalletNew(context.Background(), crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -1360,7 +1362,7 @@ readLoop: m.Message.From = localActor m.Message.Nonce -= baseNonce - sig, err := w.Sign(context.TODO(), localActor, m.Message.Cid().Bytes()) + sig, err := w.WalletSign(context.TODO(), localActor, m.Message.Cid().Bytes(), api.MsgMeta{}) if err != nil { t.Fatal(err) } diff --git a/chain/messagesigner/messagesigner.go b/chain/messagesigner/messagesigner.go index 1fe8f9565..9b8f86b64 100644 --- a/chain/messagesigner/messagesigner.go +++ b/chain/messagesigner/messagesigner.go @@ -5,15 +5,17 @@ import ( "context" "sync" - "github.com/filecoin-project/go-address" - "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/chain/wallet" - "github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore/namespace" logging "github.com/ipfs/go-log/v2" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/modules/dtypes" ) const dsKeyActorNonce = "ActorNextNonce" @@ -27,13 +29,13 @@ type MpoolNonceAPI interface { // MessageSigner keeps track of nonces per address, and increments the nonce // when signing a message type MessageSigner struct { - wallet *wallet.Wallet + wallet api.WalletAPI lk sync.Mutex mpool MpoolNonceAPI ds datastore.Batching } -func NewMessageSigner(wallet *wallet.Wallet, mpool MpoolNonceAPI, ds dtypes.MetadataDS) *MessageSigner { +func NewMessageSigner(wallet api.WalletAPI, mpool MpoolNonceAPI, ds dtypes.MetadataDS) *MessageSigner { ds = namespace.Wrap(ds, datastore.NewKey("/message-signer/")) return &MessageSigner{ wallet: wallet, @@ -56,7 +58,16 @@ func (ms *MessageSigner) SignMessage(ctx context.Context, msg *types.Message, cb // Sign the message with the nonce msg.Nonce = nonce - sig, err := ms.wallet.Sign(ctx, msg.From, msg.Cid().Bytes()) + + mb, err := msg.ToStorageBlock() + if err != nil { + return nil, xerrors.Errorf("serializing message: %w", err) + } + + sig, err := ms.wallet.WalletSign(ctx, msg.From, mb.Cid().Bytes(), api.MsgMeta{ + Type: api.MTChainMsg, + Extra: mb.RawData(), + }) if err != nil { return nil, xerrors.Errorf("failed to sign message: %w", err) } diff --git a/chain/messagesigner/messagesigner_test.go b/chain/messagesigner/messagesigner_test.go index de74b8a48..0dafce9a1 100644 --- a/chain/messagesigner/messagesigner_test.go +++ b/chain/messagesigner/messagesigner_test.go @@ -47,13 +47,13 @@ func TestMessageSignerSignMessage(t *testing.T) { ctx := context.Background() w, _ := wallet.NewWallet(wallet.NewMemKeyStore()) - from1, err := w.GenerateKey(crypto.SigTypeSecp256k1) + from1, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1) require.NoError(t, err) - from2, err := w.GenerateKey(crypto.SigTypeSecp256k1) + from2, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1) require.NoError(t, err) - to1, err := w.GenerateKey(crypto.SigTypeSecp256k1) + to1, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1) require.NoError(t, err) - to2, err := w.GenerateKey(crypto.SigTypeSecp256k1) + to2, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1) require.NoError(t, err) type msgSpec struct { diff --git a/chain/stmgr/forks_test.go b/chain/stmgr/forks_test.go index bf1c711e4..0388af6ad 100644 --- a/chain/stmgr/forks_test.go +++ b/chain/stmgr/forks_test.go @@ -6,15 +6,21 @@ import ( "io" "testing" + "github.com/ipfs/go-cid" + ipldcbor "github.com/ipfs/go-ipld-cbor" + logging "github.com/ipfs/go-log" + "github.com/stretchr/testify/require" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/cbor" "github.com/filecoin-project/specs-actors/actors/builtin" init0 "github.com/filecoin-project/specs-actors/actors/builtin/init" "github.com/filecoin-project/specs-actors/actors/runtime" - "github.com/stretchr/testify/require" - "golang.org/x/xerrors" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/aerrors" lotusinit "github.com/filecoin-project/lotus/chain/actors/builtin/init" @@ -25,11 +31,6 @@ import ( "github.com/filecoin-project/lotus/chain/vm" _ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "github.com/filecoin-project/lotus/lib/sigs/secp" - - "github.com/ipfs/go-cid" - ipldcbor "github.com/ipfs/go-ipld-cbor" - logging "github.com/ipfs/go-log" - cbg "github.com/whyrusleeping/cbor-gen" ) func init() { @@ -186,7 +187,7 @@ func TestForkHeightTriggers(t *testing.T) { Params: enc, GasLimit: types.TestGasLimit, } - sig, err := cg.Wallet().Sign(ctx, cg.Banker(), m.Cid().Bytes()) + sig, err := cg.Wallet().WalletSign(ctx, cg.Banker(), m.Cid().Bytes(), api.MsgMeta{}) if err != nil { t.Fatal(err) } @@ -214,7 +215,7 @@ func TestForkHeightTriggers(t *testing.T) { } nonce++ - sig, err := cg.Wallet().Sign(ctx, cg.Banker(), m.Cid().Bytes()) + sig, err := cg.Wallet().WalletSign(ctx, cg.Banker(), m.Cid().Bytes(), api.MsgMeta{}) if err != nil { return nil, err } diff --git a/chain/sync_test.go b/chain/sync_test.go index 318f6d82f..0a8174c41 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -593,7 +593,7 @@ func TestDuplicateNonce(t *testing.T) { GasPremium: types.NewInt(0), } - sig, err := tu.g.Wallet().Sign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes()) + sig, err := tu.g.Wallet().WalletSign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes(), api.MsgMeta{}) require.NoError(t, err) return &types.SignedMessage{ @@ -685,7 +685,7 @@ func TestBadNonce(t *testing.T) { GasPremium: types.NewInt(0), } - sig, err := tu.g.Wallet().Sign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes()) + sig, err := tu.g.Wallet().WalletSign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes(), api.MsgMeta{}) require.NoError(t, err) return &types.SignedMessage{ diff --git a/chain/types/mock/chain.go b/chain/types/mock/chain.go index 85437079c..e4bb2fcee 100644 --- a/chain/types/mock/chain.go +++ b/chain/types/mock/chain.go @@ -9,6 +9,7 @@ import ( "github.com/filecoin-project/go-state-types/crypto" "github.com/ipfs/go-cid" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet" @@ -22,7 +23,7 @@ func Address(i uint64) address.Address { return a } -func MkMessage(from, to address.Address, nonce uint64, w *wallet.Wallet) *types.SignedMessage { +func MkMessage(from, to address.Address, nonce uint64, w *wallet.LocalWallet) *types.SignedMessage { msg := &types.Message{ To: to, From: from, @@ -33,7 +34,7 @@ func MkMessage(from, to address.Address, nonce uint64, w *wallet.Wallet) *types. GasPremium: types.NewInt(1), } - sig, err := w.Sign(context.TODO(), from, msg.Cid().Bytes()) + sig, err := w.WalletSign(context.TODO(), from, msg.Cid().Bytes(), api.MsgMeta{}) if err != nil { panic(err) } diff --git a/chain/vectors/gen/main.go b/chain/vectors/gen/main.go index 51d907648..096548e04 100644 --- a/chain/vectors/gen/main.go +++ b/chain/vectors/gen/main.go @@ -1,6 +1,7 @@ package main import ( + "context" "encoding/json" "fmt" "math/rand" @@ -61,11 +62,11 @@ func MakeMessageSigningVectors() []vectors.MessageSigningVector { panic(err) } - blsk, err := w.GenerateKey(crypto.SigTypeBLS) + blsk, err := w.WalletNew(context.Background(), crypto.SigTypeBLS) if err != nil { panic(err) } - bki, err := w.Export(blsk) + bki, err := w.WalletExport(context.Background(), blsk) if err != nil { panic(err) } @@ -85,11 +86,11 @@ func MakeMessageSigningVectors() []vectors.MessageSigningVector { Signature: &bmsg.Signature, } - secpk, err := w.GenerateKey(crypto.SigTypeBLS) + secpk, err := w.WalletNew(context.Background(), crypto.SigTypeBLS) if err != nil { panic(err) } - ski, err := w.Export(secpk) + ski, err := w.WalletExport(context.Background(), secpk) if err != nil { panic(err) } diff --git a/chain/wallet/key.go b/chain/wallet/key.go new file mode 100644 index 000000000..4b746a17a --- /dev/null +++ b/chain/wallet/key.go @@ -0,0 +1,81 @@ +package wallet + +import ( + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/crypto" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/lib/sigs" +) + +func GenerateKey(typ crypto.SigType) (*Key, error) { + pk, err := sigs.Generate(typ) + if err != nil { + return nil, err + } + ki := types.KeyInfo{ + Type: kstoreSigType(typ), + PrivateKey: pk, + } + return NewKey(ki) +} + +type Key struct { + types.KeyInfo + + PublicKey []byte + Address address.Address +} + +func NewKey(keyinfo types.KeyInfo) (*Key, error) { + k := &Key{ + KeyInfo: keyinfo, + } + + var err error + k.PublicKey, err = sigs.ToPublic(ActSigType(k.Type), k.PrivateKey) + if err != nil { + return nil, err + } + + switch k.Type { + case KTSecp256k1: + k.Address, err = address.NewSecp256k1Address(k.PublicKey) + if err != nil { + return nil, xerrors.Errorf("converting Secp256k1 to address: %w", err) + } + case KTBLS: + k.Address, err = address.NewBLSAddress(k.PublicKey) + if err != nil { + return nil, xerrors.Errorf("converting BLS to address: %w", err) + } + default: + return nil, xerrors.Errorf("unknown key type") + } + return k, nil + +} + +func kstoreSigType(typ crypto.SigType) string { + switch typ { + case crypto.SigTypeBLS: + return KTBLS + case crypto.SigTypeSecp256k1: + return KTSecp256k1 + default: + return "" + } +} + +func ActSigType(typ string) crypto.SigType { + switch typ { + case KTBLS: + return crypto.SigTypeBLS + case KTSecp256k1: + return crypto.SigTypeSecp256k1 + default: + return 0 + } +} diff --git a/chain/wallet/remotewallet/remote.go b/chain/wallet/remotewallet/remote.go new file mode 100644 index 000000000..c7192f496 --- /dev/null +++ b/chain/wallet/remotewallet/remote.go @@ -0,0 +1,42 @@ +package remotewallet + +import ( + "context" + + "go.uber.org/fx" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/client" + cliutil "github.com/filecoin-project/lotus/cli/util" + "github.com/filecoin-project/lotus/node/modules/helpers" +) + +type RemoteWallet struct { + api.WalletAPI +} + +func SetupRemoteWallet(info string) func(mctx helpers.MetricsCtx, lc fx.Lifecycle) (*RemoteWallet, error) { + return func(mctx helpers.MetricsCtx, lc fx.Lifecycle) (*RemoteWallet, error) { + ai := cliutil.ParseApiInfo(info) + + url, err := ai.DialArgs() + if err != nil { + return nil, err + } + + wapi, closer, err := client.NewWalletRPC(mctx, url, ai.AuthHeader()) + if err != nil { + return nil, xerrors.Errorf("creating jsonrpc client: %w", err) + } + + lc.Append(fx.Hook{ + OnStop: func(ctx context.Context) error { + closer() + return nil + }, + }) + + return &RemoteWallet{wapi}, nil + } +} diff --git a/chain/wallet/wallet.go b/chain/wallet/wallet.go index f821951b5..3efbf8ab7 100644 --- a/chain/wallet/wallet.go +++ b/chain/wallet/wallet.go @@ -12,6 +12,7 @@ import ( "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/api" _ "github.com/filecoin-project/lotus/lib/sigs/bls" // enable bls signatures _ "github.com/filecoin-project/lotus/lib/sigs/secp" // enable secp signatures @@ -29,15 +30,20 @@ const ( KTSecp256k1 = "secp256k1" ) -type Wallet struct { +type LocalWallet struct { keys map[address.Address]*Key keystore types.KeyStore lk sync.Mutex } -func NewWallet(keystore types.KeyStore) (*Wallet, error) { - w := &Wallet{ +type Default interface { + GetDefault() (address.Address, error) + SetDefault(a address.Address) error +} + +func NewWallet(keystore types.KeyStore) (*LocalWallet, error) { + w := &LocalWallet{ keys: make(map[address.Address]*Key), keystore: keystore, } @@ -45,18 +51,18 @@ func NewWallet(keystore types.KeyStore) (*Wallet, error) { return w, nil } -func KeyWallet(keys ...*Key) *Wallet { +func KeyWallet(keys ...*Key) *LocalWallet { m := make(map[address.Address]*Key) for _, key := range keys { m[key.Address] = key } - return &Wallet{ + return &LocalWallet{ keys: m, } } -func (w *Wallet) Sign(ctx context.Context, addr address.Address, msg []byte) (*crypto.Signature, error) { +func (w *LocalWallet) WalletSign(ctx context.Context, addr address.Address, msg []byte, meta api.MsgMeta) (*crypto.Signature, error) { ki, err := w.findKey(addr) if err != nil { return nil, err @@ -68,7 +74,7 @@ func (w *Wallet) Sign(ctx context.Context, addr address.Address, msg []byte) (*c return sigs.Sign(ActSigType(ki.Type), ki.PrivateKey, msg) } -func (w *Wallet) findKey(addr address.Address) (*Key, error) { +func (w *LocalWallet) findKey(addr address.Address) (*Key, error) { w.lk.Lock() defer w.lk.Unlock() @@ -96,7 +102,7 @@ func (w *Wallet) findKey(addr address.Address) (*Key, error) { return k, nil } -func (w *Wallet) tryFind(addr address.Address) (types.KeyInfo, error) { +func (w *LocalWallet) tryFind(addr address.Address) (types.KeyInfo, error) { ki, err := w.keystore.Get(KNamePrefix + addr.String()) if err == nil { @@ -130,7 +136,7 @@ func (w *Wallet) tryFind(addr address.Address) (types.KeyInfo, error) { return ki, nil } -func (w *Wallet) Export(addr address.Address) (*types.KeyInfo, error) { +func (w *LocalWallet) WalletExport(ctx context.Context, addr address.Address) (*types.KeyInfo, error) { k, err := w.findKey(addr) if err != nil { return nil, xerrors.Errorf("failed to find key to export: %w", err) @@ -139,7 +145,7 @@ func (w *Wallet) Export(addr address.Address) (*types.KeyInfo, error) { return &k.KeyInfo, nil } -func (w *Wallet) Import(ki *types.KeyInfo) (address.Address, error) { +func (w *LocalWallet) WalletImport(ctx context.Context, ki *types.KeyInfo) (address.Address, error) { w.lk.Lock() defer w.lk.Unlock() @@ -155,7 +161,7 @@ func (w *Wallet) Import(ki *types.KeyInfo) (address.Address, error) { return k.Address, nil } -func (w *Wallet) ListAddrs() ([]address.Address, error) { +func (w *LocalWallet) WalletList(ctx context.Context) ([]address.Address, error) { all, err := w.keystore.List() if err != nil { return nil, xerrors.Errorf("listing keystore: %w", err) @@ -188,7 +194,7 @@ func (w *Wallet) ListAddrs() ([]address.Address, error) { return out, nil } -func (w *Wallet) GetDefault() (address.Address, error) { +func (w *LocalWallet) GetDefault() (address.Address, error) { w.lk.Lock() defer w.lk.Unlock() @@ -205,7 +211,7 @@ func (w *Wallet) GetDefault() (address.Address, error) { return k.Address, nil } -func (w *Wallet) SetDefault(a address.Address) error { +func (w *LocalWallet) SetDefault(a address.Address) error { w.lk.Lock() defer w.lk.Unlock() @@ -227,19 +233,7 @@ func (w *Wallet) SetDefault(a address.Address) error { return nil } -func GenerateKey(typ crypto.SigType) (*Key, error) { - pk, err := sigs.Generate(typ) - if err != nil { - return nil, err - } - ki := types.KeyInfo{ - Type: kstoreSigType(typ), - PrivateKey: pk, - } - return NewKey(ki) -} - -func (w *Wallet) GenerateKey(typ crypto.SigType) (address.Address, error) { +func (w *LocalWallet) WalletNew(ctx context.Context, typ crypto.SigType) (address.Address, error) { w.lk.Lock() defer w.lk.Unlock() @@ -267,7 +261,7 @@ func (w *Wallet) GenerateKey(typ crypto.SigType) (address.Address, error) { return k.Address, nil } -func (w *Wallet) HasKey(addr address.Address) (bool, error) { +func (w *LocalWallet) WalletHas(ctx context.Context, addr address.Address) (bool, error) { k, err := w.findKey(addr) if err != nil { return false, err @@ -275,7 +269,7 @@ func (w *Wallet) HasKey(addr address.Address) (bool, error) { return k != nil, nil } -func (w *Wallet) DeleteKey(addr address.Address) error { +func (w *LocalWallet) WalletDelete(ctx context.Context, addr address.Address) error { k, err := w.findKey(addr) if err != nil { return xerrors.Errorf("failed to delete key %s : %w", addr, err) @@ -300,63 +294,7 @@ func (w *Wallet) DeleteKey(addr address.Address) error { return nil } -type Key struct { - types.KeyInfo - - PublicKey []byte - Address address.Address -} - -func NewKey(keyinfo types.KeyInfo) (*Key, error) { - k := &Key{ - KeyInfo: keyinfo, - } - - var err error - k.PublicKey, err = sigs.ToPublic(ActSigType(k.Type), k.PrivateKey) - if err != nil { - return nil, err - } - - switch k.Type { - case KTSecp256k1: - k.Address, err = address.NewSecp256k1Address(k.PublicKey) - if err != nil { - return nil, xerrors.Errorf("converting Secp256k1 to address: %w", err) - } - case KTBLS: - k.Address, err = address.NewBLSAddress(k.PublicKey) - if err != nil { - return nil, xerrors.Errorf("converting BLS to address: %w", err) - } - default: - return nil, xerrors.Errorf("unknown key type") - } - return k, nil - -} - -func kstoreSigType(typ crypto.SigType) string { - switch typ { - case crypto.SigTypeBLS: - return KTBLS - case crypto.SigTypeSecp256k1: - return KTSecp256k1 - default: - return "" - } -} - -func ActSigType(typ string) crypto.SigType { - switch typ { - case KTBLS: - return crypto.SigTypeBLS - case KTSecp256k1: - return crypto.SigTypeSecp256k1 - default: - return 0 - } -} +var _ api.WalletAPI = &LocalWallet{} func swapMainnetForTestnetPrefix(addr string) (string, error) { aChars := []rune(addr) diff --git a/cli/cmd.go b/cli/cmd.go index e6475934b..eef73b241 100644 --- a/cli/cmd.go +++ b/cli/cmd.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "net/http" - "net/url" "os" "os/signal" "strings" @@ -12,8 +11,6 @@ import ( logging "github.com/ipfs/go-log/v2" "github.com/mitchellh/go-homedir" - "github.com/multiformats/go-multiaddr" - manet "github.com/multiformats/go-multiaddr/net" "github.com/urfave/cli/v2" "golang.org/x/xerrors" @@ -21,6 +18,7 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/client" + cliutil "github.com/filecoin-project/lotus/cli/util" "github.com/filecoin-project/lotus/node/repo" ) @@ -47,57 +45,6 @@ func NewCliError(s string) error { // ApiConnector returns API instance type ApiConnector func() api.FullNode -type APIInfo struct { - Addr string - Token []byte -} - -func (a APIInfo) DialArgs() (string, error) { - ma, err := multiaddr.NewMultiaddr(a.Addr) - if err == nil { - _, addr, err := manet.DialArgs(ma) - if err != nil { - return "", err - } - - return "ws://" + addr + "/rpc/v0", nil - } - - _, err = url.Parse(a.Addr) - if err != nil { - return "", err - } - return a.Addr + "/rpc/v0", nil -} - -func (a APIInfo) Host() (string, error) { - ma, err := multiaddr.NewMultiaddr(a.Addr) - if err == nil { - _, addr, err := manet.DialArgs(ma) - if err != nil { - return "", err - } - - return addr, nil - } - - spec, err := url.Parse(a.Addr) - if err != nil { - return "", err - } - return spec.Host, nil -} - -func (a APIInfo) AuthHeader() http.Header { - if len(a.Token) != 0 { - headers := http.Header{} - headers.Add("Authorization", "Bearer "+string(a.Token)) - return headers - } - log.Warn("API Token not set and requested, capabilities might be limited.") - return nil -} - // The flag passed on the command line with the listen address of the API // server (only used by the tests) func flagForAPI(t repo.RepoType) string { @@ -153,7 +100,7 @@ func envForRepoDeprecation(t repo.RepoType) string { } } -func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) { +func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (cliutil.APIInfo, error) { // Check if there was a flag passed with the listen address of the API // server (only used by the tests) apiFlag := flagForAPI(t) @@ -161,7 +108,7 @@ func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) { strma := ctx.String(apiFlag) strma = strings.TrimSpace(strma) - return APIInfo{Addr: strma}, nil + return cliutil.APIInfo{Addr: strma}, nil } envKey := envForRepo(t) @@ -175,32 +122,24 @@ func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) { } } if ok { - sp := strings.SplitN(env, ":", 2) - if len(sp) != 2 { - log.Warnf("invalid env(%s) value, missing token or address", envKey) - } else { - return APIInfo{ - Addr: sp[1], - Token: []byte(sp[0]), - }, nil - } + return cliutil.ParseApiInfo(env), nil } repoFlag := flagForRepo(t) p, err := homedir.Expand(ctx.String(repoFlag)) if err != nil { - return APIInfo{}, xerrors.Errorf("could not expand home dir (%s): %w", repoFlag, err) + return cliutil.APIInfo{}, xerrors.Errorf("could not expand home dir (%s): %w", repoFlag, err) } r, err := repo.NewFS(p) if err != nil { - return APIInfo{}, xerrors.Errorf("could not open repo at path: %s; %w", p, err) + return cliutil.APIInfo{}, xerrors.Errorf("could not open repo at path: %s; %w", p, err) } ma, err := r.APIEndpoint() if err != nil { - return APIInfo{}, xerrors.Errorf("could not get api endpoint: %w", err) + return cliutil.APIInfo{}, xerrors.Errorf("could not get api endpoint: %w", err) } token, err := r.APIToken() @@ -208,7 +147,7 @@ func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) { log.Warnf("Couldn't load CLI token, capabilities may be limited: %v", err) } - return APIInfo{ + return cliutil.APIInfo{ Addr: ma.String(), Token: token, }, nil diff --git a/cli/util/apiinfo.go b/cli/util/apiinfo.go new file mode 100644 index 000000000..1f9a83769 --- /dev/null +++ b/cli/util/apiinfo.go @@ -0,0 +1,83 @@ +package cliutil + +import ( + "net/http" + "net/url" + "regexp" + "strings" + + logging "github.com/ipfs/go-log/v2" + "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" +) + +var log = logging.Logger("cliutil") + +var ( + infoWithToken = regexp.MustCompile("^[a-zA-Z0-9\\-_]+?\\.[a-zA-Z0-9\\-_]+?\\.([a-zA-Z0-9\\-_]+)?:.+$") +) + +type APIInfo struct { + Addr string + Token []byte +} + +func ParseApiInfo(s string) APIInfo { + var tok []byte + if infoWithToken.Match([]byte(s)) { + sp := strings.SplitN(s, ":", 2) + tok = []byte(sp[0]) + s = sp[1] + } + + return APIInfo{ + Addr: s, + Token: tok, + } +} + +func (a APIInfo) DialArgs() (string, error) { + ma, err := multiaddr.NewMultiaddr(a.Addr) + if err == nil { + _, addr, err := manet.DialArgs(ma) + if err != nil { + return "", err + } + + return "ws://" + addr + "/rpc/v0", nil + } + + _, err = url.Parse(a.Addr) + if err != nil { + return "", err + } + return a.Addr + "/rpc/v0", nil +} + +func (a APIInfo) Host() (string, error) { + ma, err := multiaddr.NewMultiaddr(a.Addr) + if err == nil { + _, addr, err := manet.DialArgs(ma) + if err != nil { + return "", err + } + + return addr, nil + } + + spec, err := url.Parse(a.Addr) + if err != nil { + return "", err + } + return spec.Host, nil +} + +func (a APIInfo) AuthHeader() http.Header { + if len(a.Token) != 0 { + headers := http.Header{} + headers.Add("Authorization", "Bearer "+string(a.Token)) + return headers + } + log.Warn("API Token not set and requested, capabilities might be limited.") + return nil +} diff --git a/cmd/lotus-keygen/main.go b/cmd/lotus-keygen/main.go index 8e2881ae9..4b971cf48 100644 --- a/cmd/lotus-keygen/main.go +++ b/cmd/lotus-keygen/main.go @@ -40,12 +40,12 @@ func main() { return fmt.Errorf("unrecognized key type: %q", cctx.String("type")) } - kaddr, err := w.GenerateKey(kt) + kaddr, err := w.WalletNew(cctx.Context, kt) if err != nil { return err } - ki, err := w.Export(kaddr) + ki, err := w.WalletExport(cctx.Context, kaddr) if err != nil { return err } diff --git a/cmd/lotus-shed/consensus.go b/cmd/lotus-shed/consensus.go index 38a8cd8ef..1fe7756c1 100644 --- a/cmd/lotus-shed/consensus.go +++ b/cmd/lotus-shed/consensus.go @@ -15,6 +15,7 @@ import ( "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" + cliutil "github.com/filecoin-project/lotus/cli/util" "github.com/libp2p/go-libp2p-core/peer" "github.com/multiformats/go-multiaddr" "github.com/urfave/cli/v2" @@ -111,7 +112,7 @@ var consensusCheckCmd = &cli.Command{ if err != nil { return err } - ainfo := lcli.APIInfo{Addr: apima.String()} + ainfo := cliutil.APIInfo{Addr: apima.String()} addr, err := ainfo.DialArgs() if err != nil { return err diff --git a/cmd/lotus-shed/keyinfo.go b/cmd/lotus-shed/keyinfo.go index 6090b7a0f..fdd1fcb49 100644 --- a/cmd/lotus-shed/keyinfo.go +++ b/cmd/lotus-shed/keyinfo.go @@ -105,7 +105,7 @@ var keyinfoVerifyCmd = &cli.Command{ return err } - if _, err := w.Import(&keyInfo); err != nil { + if _, err := w.WalletImport(cctx.Context, &keyInfo); err != nil { return err } @@ -220,7 +220,7 @@ var keyinfoImportCmd = &cli.Command{ return err } - addr, err := w.Import(&keyInfo) + addr, err := w.WalletImport(cctx.Context, &keyInfo) if err != nil { return err } diff --git a/cmd/lotus-wallet/logged.go b/cmd/lotus-wallet/logged.go new file mode 100644 index 000000000..3bcb3f867 --- /dev/null +++ b/cmd/lotus-wallet/logged.go @@ -0,0 +1,94 @@ +package main + +import ( + "bytes" + "context" + "encoding/hex" + + "github.com/ipfs/go-cid" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/crypto" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" +) + +type LoggedWallet struct { + under api.WalletAPI +} + +func (c *LoggedWallet) WalletNew(ctx context.Context, typ crypto.SigType) (address.Address, error) { + n, err := typ.Name() + if err != nil { + return address.Address{}, err + } + + log.Infow("WalletNew", "type", n) + + return c.under.WalletNew(ctx, typ) +} + +func (c *LoggedWallet) WalletHas(ctx context.Context, addr address.Address) (bool, error) { + log.Infow("WalletHas", "address", addr) + + return c.under.WalletHas(ctx, addr) +} + +func (c *LoggedWallet) WalletList(ctx context.Context) ([]address.Address, error) { + log.Infow("WalletList") + + return c.under.WalletList(ctx) +} + +func (c *LoggedWallet) WalletSign(ctx context.Context, k address.Address, msg []byte, meta api.MsgMeta) (*crypto.Signature, error) { + switch meta.Type { + case api.MTChainMsg: + var cmsg types.Message + if err := cmsg.UnmarshalCBOR(bytes.NewReader(meta.Extra)); err != nil { + return nil, xerrors.Errorf("unmarshalling message: %w", err) + } + + _, bc, err := cid.CidFromBytes(msg) + if err != nil { + return nil, xerrors.Errorf("getting cid from signing bytes: %w", err) + } + + if !cmsg.Cid().Equals(bc) { + return nil, xerrors.Errorf("cid(meta.Extra).bytes() != msg") + } + + log.Infow("WalletSign", + "address", k, + "type", meta.Type, + "from", cmsg.From, + "to", cmsg.To, + "value", types.FIL(cmsg.Value), + "feecap", types.FIL(cmsg.RequiredFunds()), + "method", cmsg.Method, + "params", hex.EncodeToString(cmsg.Params)) + default: + log.Infow("WalletSign", "address", k, "type", meta.Type) + } + + return c.under.WalletSign(ctx, k, msg, meta) +} + +func (c *LoggedWallet) WalletExport(ctx context.Context, a address.Address) (*types.KeyInfo, error) { + log.Infow("WalletExport", "address", a) + + return c.under.WalletExport(ctx, a) +} + +func (c *LoggedWallet) WalletImport(ctx context.Context, ki *types.KeyInfo) (address.Address, error) { + log.Infow("WalletImport", "type", ki.Type) + + return c.under.WalletImport(ctx, ki) +} + +func (c *LoggedWallet) WalletDelete(ctx context.Context, addr address.Address) error { + log.Infow("WalletDelete", "address", addr) + + return c.under.WalletDelete(ctx, addr) +} diff --git a/cmd/lotus-wallet/main.go b/cmd/lotus-wallet/main.go new file mode 100644 index 000000000..ae3580a59 --- /dev/null +++ b/cmd/lotus-wallet/main.go @@ -0,0 +1,141 @@ +package main + +import ( + "context" + "net" + "net/http" + "os" + + "github.com/gorilla/mux" + logging "github.com/ipfs/go-log/v2" + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/wallet" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/lib/lotuslog" + "github.com/filecoin-project/lotus/node/repo" +) + +var log = logging.Logger("main") + +const FlagWalletRepo = "wallet-repo" + +func main() { + lotuslog.SetupLogLevels() + + local := []*cli.Command{ + runCmd, + } + + app := &cli.App{ + Name: "lotus-wallet", + Usage: "Basic external wallet", + Version: build.UserVersion(), + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: FlagWalletRepo, + EnvVars: []string{"WALLET_PATH"}, + Value: "~/.lotuswallet", // TODO: Consider XDG_DATA_HOME + }, + }, + + Commands: local, + } + app.Setup() + + if err := app.Run(os.Args); err != nil { + log.Warnf("%+v", err) + return + } +} + +var runCmd = &cli.Command{ + Name: "run", + Usage: "Start lotus wallet", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "listen", + Usage: "host address and port the wallet api will listen on", + Value: "0.0.0.0:1777", + }, + }, + Action: func(cctx *cli.Context) error { + log.Info("Starting lotus wallet") + + ctx := lcli.ReqContext(cctx) + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + repoPath := cctx.String(FlagWalletRepo) + r, err := repo.NewFS(repoPath) + if err != nil { + return err + } + + ok, err := r.Exists() + if err != nil { + return err + } + if !ok { + if err := r.Init(repo.Worker); err != nil { + return err + } + } + + lr, err := r.Lock(repo.Wallet) + if err != nil { + return err + } + + ks, err := lr.KeyStore() + if err != nil { + return err + } + + w, err := wallet.NewWallet(ks) + if err != nil { + return err + } + + address := cctx.String("listen") + mux := mux.NewRouter() + + log.Info("Setting up API endpoint at " + address) + + rpcServer := jsonrpc.NewServer() + rpcServer.Register("Filecoin", &LoggedWallet{under: w}) + + mux.Handle("/rpc/v0", rpcServer) + mux.PathPrefix("/").Handler(http.DefaultServeMux) // pprof + + /*ah := &auth.Handler{ + Verify: nodeApi.AuthVerify, + Next: mux.ServeHTTP, + }*/ + + srv := &http.Server{ + Handler: mux, + BaseContext: func(listener net.Listener) context.Context { + return ctx + }, + } + + go func() { + <-ctx.Done() + log.Warn("Shutting down...") + if err := srv.Shutdown(context.TODO()); err != nil { + log.Errorf("shutting down RPC server failed: %s", err) + } + log.Warn("Graceful shutdown successful") + }() + + nl, err := net.Listen("tcp", address) + if err != nil { + return err + } + + return srv.Serve(nl) + }, +} diff --git a/documentation/en/api-methods.md b/documentation/en/api-methods.md index cc6d92e4f..b3a9627e0 100644 --- a/documentation/en/api-methods.md +++ b/documentation/en/api-methods.md @@ -2146,8 +2146,7 @@ Inputs: Response: `"0"` ### MsigGetVestingSchedule -MsigGetLockedBalance returns the locked balance of an msig at a vien epoch. -The return may be greater than the multisig actor's actual balance. +MsigGetVestingSchedule returns the vesting details of a given multisig. Perms: read diff --git a/go.mod b/go.mod index e9687c7b8..e1bf6cb3b 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/filecoin-project/go-data-transfer v0.6.7 github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f github.com/filecoin-project/go-fil-markets v0.7.1 - github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 + github.com/filecoin-project/go-jsonrpc v0.1.2-0.20201008195726-68c6a2704e49 github.com/filecoin-project/go-multistore v0.0.3 github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261 diff --git a/go.sum b/go.sum index bab4e929d..ef954e66d 100644 --- a/go.sum +++ b/go.sum @@ -252,8 +252,8 @@ github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CW github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24= github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0 h1:b3UDemBYN2HNfk3KOXNuxgTTxlWi3xVvbQP0IT38fvM= github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0/go.mod h1:7aWZdaQ1b16BVoQUYR+eEvrDCGJoPLxFpDynFjYfBjI= -github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 h1:FXtCp0ybqdQL9knb3OGDpkNTaBbPxgkqPeWKotUwkH0= -github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= +github.com/filecoin-project/go-jsonrpc v0.1.2-0.20201008195726-68c6a2704e49 h1:FSY245KeXFCUgyfFEu+bhrZNk8BGGJyfpSmQl2aiPU8= +github.com/filecoin-project/go-jsonrpc v0.1.2-0.20201008195726-68c6a2704e49/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= github.com/filecoin-project/go-multistore v0.0.3 h1:vaRBY4YiA2UZFPK57RNuewypB8u0DzzQwqsL0XarpnI= github.com/filecoin-project/go-multistore v0.0.3/go.mod h1:kaNqCC4IhU4B1uyr7YWFHd23TL4KM32aChS0jNkyUvQ= github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 h1:+/4aUeUoKr6AKfPE3mBhXA5spIV6UcKdTYDPNU2Tdmg= diff --git a/markets/storageadapter/client.go b/markets/storageadapter/client.go index 647a1675d..6496fffad 100644 --- a/markets/storageadapter/client.go +++ b/markets/storageadapter/client.go @@ -6,19 +6,22 @@ import ( "bytes" "context" - "github.com/filecoin-project/go-state-types/big" - miner0 "github.com/filecoin-project/specs-actors/actors/builtin" - market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" - "golang.org/x/xerrors" + "github.com/ipfs/go-cid" + "github.com/filecoin-project/go-address" cborutil "github.com/filecoin-project/go-cbor-util" "github.com/filecoin-project/go-fil-markets/shared" "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/exitcode" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin" + market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" + + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/events" @@ -30,7 +33,6 @@ import ( "github.com/filecoin-project/lotus/lib/sigs" "github.com/filecoin-project/lotus/markets/utils" "github.com/filecoin-project/lotus/node/impl/full" - "github.com/ipfs/go-cid" ) type ClientNodeAdapter struct { @@ -422,7 +424,9 @@ func (c *ClientNodeAdapter) SignProposal(ctx context.Context, signer address.Add return nil, err } - sig, err := c.Wallet.Sign(ctx, signer, buf) + sig, err := c.Wallet.WalletSign(ctx, signer, buf, api.MsgMeta{ + Type: api.MTDealProposal, + }) if err != nil { return nil, err } @@ -434,7 +438,7 @@ func (c *ClientNodeAdapter) SignProposal(ctx context.Context, signer address.Add } func (c *ClientNodeAdapter) GetDefaultWalletAddress(ctx context.Context) (address.Address, error) { - addr, err := c.Wallet.GetDefault() + addr, err := c.DefWallet.GetDefault() return addr, err } @@ -475,7 +479,9 @@ func (c *ClientNodeAdapter) SignBytes(ctx context.Context, signer address.Addres return nil, err } - localSignature, err := c.Wallet.Sign(ctx, signer, b) + localSignature, err := c.Wallet.WalletSign(ctx, signer, b, api.MsgMeta{ + Type: api.MTUnknown, // TODO: pass type here + }) if err != nil { return nil, err } diff --git a/node/builder.go b/node/builder.go index a2e3c981e..b91172386 100644 --- a/node/builder.go +++ b/node/builder.go @@ -44,6 +44,7 @@ import ( "github.com/filecoin-project/lotus/chain/metrics" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/wallet/remotewallet" sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" "github.com/filecoin-project/lotus/extern/sector-storage/stores" @@ -249,7 +250,9 @@ func Online() Option { Override(new(stmgr.UpgradeSchedule), stmgr.DefaultUpgradeSchedule()), Override(new(*stmgr.StateManager), stmgr.NewStateManagerWithUpgradeSchedule), Override(new(stmgr.StateManagerAPI), From(new(*stmgr.StateManager))), - Override(new(*wallet.Wallet), wallet.NewWallet), + Override(new(*wallet.LocalWallet), wallet.NewWallet), + Override(new(api.WalletAPI), From(new(*wallet.LocalWallet))), + Override(new(wallet.Default), From(new(*wallet.LocalWallet))), Override(new(*messagesigner.MessageSigner), messagesigner.NewMessageSigner), Override(new(dtypes.ChainGCLocker), blockstore.NewGCLocker), @@ -456,6 +459,9 @@ func ConfigFullNode(c interface{}) Option { If(cfg.Metrics.HeadNotifs, Override(HeadMetricsKey, metrics.SendHeadNotifs(cfg.Metrics.Nickname)), ), + If(cfg.Wallet.RemoteBackend != "", + Override(new(api.WalletAPI), remotewallet.SetupRemoteWallet(cfg.Wallet.RemoteBackend)), + ), ) } diff --git a/node/config/def.go b/node/config/def.go index b05891e47..63340cfd5 100644 --- a/node/config/def.go +++ b/node/config/def.go @@ -22,6 +22,7 @@ type FullNode struct { Common Client Client Metrics Metrics + Wallet Wallet } // // Common @@ -107,6 +108,10 @@ type Client struct { IpfsUseForRetrieval bool } +type Wallet struct { + RemoteBackend string +} + func defCommon() Common { return Common{ API: API{ diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 34724e205..db91433aa 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -5,14 +5,6 @@ import ( "context" "strconv" - "github.com/filecoin-project/lotus/chain/actors/builtin" - "github.com/filecoin-project/lotus/chain/actors/policy" - - "github.com/filecoin-project/lotus/chain/actors/builtin/verifreg" - - "github.com/filecoin-project/go-state-types/dline" - "github.com/filecoin-project/go-state-types/network" - cid "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" "go.uber.org/fx" @@ -22,14 +14,19 @@ import ( "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/builtin/market" "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/actors/builtin/multisig" "github.com/filecoin-project/lotus/chain/actors/builtin/power" "github.com/filecoin-project/lotus/chain/actors/builtin/reward" + "github.com/filecoin-project/lotus/chain/actors/builtin/verifreg" + "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/beacon" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/state" @@ -68,7 +65,8 @@ type StateAPI struct { // TODO: the wallet here is only needed because we have the MinerCreateBlock // API attached to the state API. It probably should live somewhere better - Wallet *wallet.Wallet + Wallet api.WalletAPI + DefWallet wallet.Default StateModuleAPI diff --git a/node/impl/full/wallet.go b/node/impl/full/wallet.go index 616c7b46e..05a7a5768 100644 --- a/node/impl/full/wallet.go +++ b/node/impl/full/wallet.go @@ -3,13 +3,14 @@ package full import ( "context" - "github.com/filecoin-project/go-address" "go.uber.org/fx" "golang.org/x/xerrors" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet" @@ -20,19 +21,8 @@ type WalletAPI struct { fx.In StateManagerAPI stmgr.StateManagerAPI - Wallet *wallet.Wallet -} - -func (a *WalletAPI) WalletNew(ctx context.Context, typ crypto.SigType) (address.Address, error) { - return a.Wallet.GenerateKey(typ) -} - -func (a *WalletAPI) WalletHas(ctx context.Context, addr address.Address) (bool, error) { - return a.Wallet.HasKey(addr) -} - -func (a *WalletAPI) WalletList(ctx context.Context) ([]address.Address, error) { - return a.Wallet.ListAddrs() + Default wallet.Default + api.WalletAPI } func (a *WalletAPI) WalletBalance(ctx context.Context, addr address.Address) (types.BigInt, error) { @@ -50,13 +40,26 @@ func (a *WalletAPI) WalletSign(ctx context.Context, k address.Address, msg []byt if err != nil { return nil, xerrors.Errorf("failed to resolve ID address: %w", keyAddr) } - return a.Wallet.Sign(ctx, keyAddr, msg) + return a.WalletAPI.WalletSign(ctx, keyAddr, msg, api.MsgMeta{ + Type: api.MTUnknown, + }) } func (a *WalletAPI) WalletSignMessage(ctx context.Context, k address.Address, msg *types.Message) (*types.SignedMessage, error) { - mcid := msg.Cid() + keyAddr, err := a.StateManagerAPI.ResolveToKeyAddress(ctx, k, nil) + if err != nil { + return nil, xerrors.Errorf("failed to resolve ID address: %w", keyAddr) + } - sig, err := a.WalletSign(ctx, k, mcid.Bytes()) + mb, err := msg.ToStorageBlock() + if err != nil { + return nil, xerrors.Errorf("serializing message: %w", err) + } + + sig, err := a.WalletAPI.WalletSign(ctx, k, mb.Cid().Bytes(), api.MsgMeta{ + Type: api.MTChainMsg, + Extra: mb.RawData(), + }) if err != nil { return nil, xerrors.Errorf("failed to sign message: %w", err) } @@ -72,23 +75,11 @@ func (a *WalletAPI) WalletVerify(ctx context.Context, k address.Address, msg []b } func (a *WalletAPI) WalletDefaultAddress(ctx context.Context) (address.Address, error) { - return a.Wallet.GetDefault() + return a.Default.GetDefault() } func (a *WalletAPI) WalletSetDefault(ctx context.Context, addr address.Address) error { - return a.Wallet.SetDefault(addr) -} - -func (a *WalletAPI) WalletExport(ctx context.Context, addr address.Address) (*types.KeyInfo, error) { - return a.Wallet.Export(addr) -} - -func (a *WalletAPI) WalletImport(ctx context.Context, ki *types.KeyInfo) (address.Address, error) { - return a.Wallet.Import(ki) -} - -func (a *WalletAPI) WalletDelete(ctx context.Context, addr address.Address) error { - return a.Wallet.DeleteKey(addr) + return a.Default.SetDefault(addr) } func (a *WalletAPI) WalletValidateAddress(ctx context.Context, str string) (address.Address, error) { diff --git a/node/repo/fsrepo.go b/node/repo/fsrepo.go index c4571c478..c1b6b5233 100644 --- a/node/repo/fsrepo.go +++ b/node/repo/fsrepo.go @@ -44,6 +44,7 @@ const ( FullNode RepoType = iota StorageMiner Worker + Wallet ) func defConfForType(t RepoType) interface{} { @@ -54,6 +55,8 @@ func defConfForType(t RepoType) interface{} { return config.DefaultStorageMiner() case Worker: return &struct{}{} + case Wallet: + return &struct{}{} default: panic(fmt.Sprintf("unknown RepoType(%d)", int(t))) } @@ -93,6 +96,12 @@ func (fsr *FsRepo) Exists() (bool, error) { notexist := os.IsNotExist(err) if notexist { err = nil + + _, err = os.Stat(filepath.Join(fsr.path, fsKeystore)) + notexist = os.IsNotExist(err) + if notexist { + err = nil + } } return !notexist, err }