Merge pull request #3583 from filecoin-project/feat/signing-backends

Remote wallet backends
This commit is contained in:
Łukasz Magiera 2020-10-10 02:58:02 +02:00 committed by GitHub
commit a6d9b302fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 773 additions and 300 deletions

1
.gitignore vendored
View File

@ -12,6 +12,7 @@
/lotus-bench /lotus-bench
/lotus-gateway /lotus-gateway
/lotus-pcr /lotus-pcr
/lotus-wallet
/bench.json /bench.json
/lotuspond/front/node_modules /lotuspond/front/node_modules
/lotuspond/front/build /lotuspond/front/build

View File

@ -186,6 +186,12 @@ lotus-health:
.PHONY: lotus-health .PHONY: lotus-health
BINS+=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: testground:
go build -tags testground -o /dev/null ./cmd/lotus go build -tags testground -o /dev/null ./cmd/lotus
.PHONY: testground .PHONY: testground

View File

@ -422,8 +422,7 @@ type FullNode interface {
// MsigGetAvailableBalance returns the portion of a multisig's balance that can be withdrawn or spent // 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) MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
// MsigGetLockedBalance returns the locked balance of an msig at a vien epoch. // MsigGetVestingSchedule returns the vesting details of a given multisig.
// The return may be greater than the multisig actor's actual balance.
MsigGetVestingSchedule(context.Context, address.Address, types.TipSetKey) (MsigVesting, error) MsigGetVestingSchedule(context.Context, address.Address, types.TipSetKey) (MsigVesting, error)
// MsigGetVested returns the amount of FIL that vested in a multisig in a certain period. // MsigGetVested returns the amount of FIL that vested in a multisig in a certain period.
// It takes the following params: <multisig address>, <start epoch>, <end epoch> // It takes the following params: <multisig address>, <start epoch>, <end epoch>

47
api/api_wallet.go Normal file
View File

@ -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
}

View File

@ -36,3 +36,9 @@ func PermissionedWorkerAPI(a api.WorkerAPI) api.WorkerAPI {
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal) auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal)
return &out return &out
} }
func PermissionedWalletAPI(a api.WalletAPI) api.WalletAPI {
var out WalletStruct
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal)
return &out
}

View File

@ -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 // CommonStruct
func (c *CommonStruct) AuthVerify(ctx context.Context, token string) ([]auth.Permission, error) { 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) 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.Common = &CommonStruct{}
var _ api.FullNode = &FullNodeStruct{} var _ api.FullNode = &FullNodeStruct{}
var _ api.StorageMiner = &StorageMinerStruct{} var _ api.StorageMiner = &StorageMinerStruct{}
var _ api.WorkerAPI = &WorkerStruct{} var _ api.WorkerAPI = &WorkerStruct{}
var _ api.GatewayAPI = &GatewayStruct{} var _ api.GatewayAPI = &GatewayStruct{}
var _ api.WalletAPI = &WalletStruct{}

View File

@ -96,3 +96,15 @@ func NewGatewayRPC(ctx context.Context, addr string, requestHeader http.Header,
return &res, closer, err 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
}

View File

@ -72,7 +72,7 @@ type ChainGen struct {
GetMessages func(*ChainGen) ([]*types.SignedMessage, error) GetMessages func(*ChainGen) ([]*types.SignedMessage, error)
w *wallet.Wallet w *wallet.LocalWallet
eppProvs map[address.Address]WinningPoStProver eppProvs map[address.Address]WinningPoStProver
Miners []address.Address Miners []address.Address
@ -155,14 +155,14 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
return nil, xerrors.Errorf("creating memrepo wallet failed: %w", err) 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 { if err != nil {
return nil, xerrors.Errorf("failed to generate banker key: %w", err) return nil, xerrors.Errorf("failed to generate banker key: %w", err)
} }
receievers := make([]address.Address, msgsPerBlock) receievers := make([]address.Address, msgsPerBlock)
for r := range receievers { for r := range receievers {
receievers[r], err = w.GenerateKey(crypto.SigTypeBLS) receievers[r], err = w.WalletNew(context.Background(), crypto.SigTypeBLS)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to generate receiver key: %w", err) return nil, xerrors.Errorf("failed to generate receiver key: %w", err)
} }
@ -192,11 +192,11 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
return nil, err return nil, err
} }
mk1, err := w.Import(k1) mk1, err := w.WalletImport(context.Background(), k1)
if err != nil { if err != nil {
return nil, err return nil, err
} }
mk2, err := w.Import(k2) mk2, err := w.WalletImport(context.Background(), k2)
if err != nil { if err != nil {
return nil, err 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) 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 { if err != nil {
return nil, nil, nil, xerrors.Errorf("compute VRF: %w", err) return nil, nil, nil, xerrors.Errorf("compute VRF: %w", err)
} }
@ -508,7 +514,7 @@ func (cg *ChainGen) Banker() address.Address {
return cg.banker return cg.banker
} }
func (cg *ChainGen) Wallet() *wallet.Wallet { func (cg *ChainGen) Wallet() *wallet.LocalWallet {
return cg.w return cg.w
} }
@ -530,7 +536,9 @@ func getRandomMessages(cg *ChainGen) ([]*types.SignedMessage, error) {
GasPremium: types.NewInt(0), 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 { if err != nil {
return nil, err return nil, err
} }
@ -561,7 +569,7 @@ type MiningCheckAPI interface {
} }
type mca struct { type mca struct {
w *wallet.Wallet w *wallet.LocalWallet
sm *stmgr.StateManager sm *stmgr.StateManager
pv ffiwrapper.Verifier pv ffiwrapper.Verifier
bcn beacon.Schedule 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) { 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 { type WinningPoStProver interface {

View File

@ -15,11 +15,10 @@ import (
"github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/chain/vm"
"github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/lotus/lib/sigs/bls" "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) pts, err := sm.ChainStore().LoadTipSet(bt.Parents)
if err != nil { 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) 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 { if err != nil {
return nil, xerrors.Errorf("failed to sign new block: %w", err) return nil, xerrors.Errorf("failed to sign new block: %w", err)
} }

View File

@ -232,7 +232,7 @@ func TestMessagePool(t *testing.T) {
a := tma.nextBlock() a := tma.nextBlock()
sender, err := w.GenerateKey(crypto.SigTypeBLS) sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -273,7 +273,7 @@ func TestMessagePoolMessagesInEachBlock(t *testing.T) {
a := tma.nextBlock() a := tma.nextBlock()
sender, err := w.GenerateKey(crypto.SigTypeBLS) sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -323,7 +323,7 @@ func TestRevertMessages(t *testing.T) {
a := tma.nextBlock() a := tma.nextBlock()
b := tma.nextBlock() b := tma.nextBlock()
sender, err := w.GenerateKey(crypto.SigTypeBLS) sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -386,7 +386,7 @@ func TestPruningSimple(t *testing.T) {
a := tma.nextBlock() a := tma.nextBlock()
tma.applyBlock(t, a) tma.applyBlock(t, a)
sender, err := w.GenerateKey(crypto.SigTypeBLS) sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -433,7 +433,7 @@ func TestLoadLocal(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -443,7 +443,7 @@ func TestLoadLocal(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -505,7 +505,7 @@ func TestClearAll(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -515,7 +515,7 @@ func TestClearAll(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -559,7 +559,7 @@ func TestClearNonLocal(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -569,7 +569,7 @@ func TestClearNonLocal(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -620,7 +620,7 @@ func TestUpdates(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -630,7 +630,7 @@ func TestUpdates(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -1,6 +1,7 @@
package messagepool package messagepool
import ( import (
"context"
"testing" "testing"
"time" "time"
@ -32,7 +33,7 @@ func TestRepubMessages(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -42,7 +43,7 @@ func TestRepubMessages(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -13,6 +13,10 @@ import (
"sort" "sort"
"testing" "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-address"
"github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/build" "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/types/mock"
"github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/specs-actors/actors/builtin" "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/bls"
_ "github.com/filecoin-project/lotus/lib/sigs/secp" _ "github.com/filecoin-project/lotus/lib/sigs/secp"
logging "github.com/ipfs/go-log"
) )
func init() { func init() {
@ -34,7 +36,7 @@ func init() {
MaxActorPendingMessages = 1000000 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{ msg := &types.Message{
From: from, From: from,
To: to, To: to,
@ -45,7 +47,7 @@ func makeTestMessage(w *wallet.Wallet, from, to address.Address, nonce uint64, g
GasFeeCap: types.NewInt(100 + gasPrice), GasFeeCap: types.NewInt(100 + gasPrice),
GasPremium: types.NewInt(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 { if err != nil {
panic(err) panic(err)
} }
@ -75,7 +77,7 @@ func TestMessageChains(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -85,7 +87,7 @@ func TestMessageChains(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -313,7 +315,7 @@ func TestMessageChainSkipping(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -323,7 +325,7 @@ func TestMessageChainSkipping(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -389,7 +391,7 @@ func TestBasicMessageSelection(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -399,7 +401,7 @@ func TestBasicMessageSelection(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -533,7 +535,7 @@ func TestMessageSelectionTrimming(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -543,7 +545,7 @@ func TestMessageSelectionTrimming(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -596,7 +598,7 @@ func TestPriorityMessageSelection(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -606,7 +608,7 @@ func TestPriorityMessageSelection(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -675,7 +677,7 @@ func TestPriorityMessageSelection2(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -685,7 +687,7 @@ func TestPriorityMessageSelection2(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -744,7 +746,7 @@ func TestPriorityMessageSelection3(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -754,7 +756,7 @@ func TestPriorityMessageSelection3(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -841,7 +843,7 @@ func TestOptimalMessageSelection1(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -851,7 +853,7 @@ func TestOptimalMessageSelection1(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -908,7 +910,7 @@ func TestOptimalMessageSelection2(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -918,7 +920,7 @@ func TestOptimalMessageSelection2(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -984,7 +986,7 @@ func TestOptimalMessageSelection3(t *testing.T) {
nActors := 10 nActors := 10
// the actors // the actors
var actors []address.Address var actors []address.Address
var wallets []*wallet.Wallet var wallets []*wallet.LocalWallet
for i := 0; i < nActors; i++ { for i := 0; i < nActors; i++ {
w, err := wallet.NewWallet(wallet.NewMemKeyStore()) w, err := wallet.NewWallet(wallet.NewMemKeyStore())
@ -992,7 +994,7 @@ func TestOptimalMessageSelection3(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
a, err := w.GenerateKey(crypto.SigTypeSecp256k1) a, err := w.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1064,7 +1066,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu
nActors := 300 nActors := 300
// the actors // the actors
var actors []address.Address var actors []address.Address
var wallets []*wallet.Wallet var wallets []*wallet.LocalWallet
for i := 0; i < nActors; i++ { for i := 0; i < nActors; i++ {
w, err := wallet.NewWallet(wallet.NewMemKeyStore()) w, err := wallet.NewWallet(wallet.NewMemKeyStore())
@ -1072,7 +1074,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu
t.Fatal(err) t.Fatal(err)
} }
a, err := w.GenerateKey(crypto.SigTypeSecp256k1) a, err := w.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1330,7 +1332,7 @@ readLoop:
} }
actorMap := make(map[address.Address]address.Address) 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 { for _, m := range msgs {
baseNonce := baseNonces[m.Message.From] baseNonce := baseNonces[m.Message.From]
@ -1342,7 +1344,7 @@ readLoop:
t.Fatal(err) t.Fatal(err)
} }
a, err := w.GenerateKey(crypto.SigTypeSecp256k1) a, err := w.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1360,7 +1362,7 @@ readLoop:
m.Message.From = localActor m.Message.From = localActor
m.Message.Nonce -= baseNonce 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -5,15 +5,17 @@ import (
"context" "context"
"sync" "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"
"github.com/ipfs/go-datastore/namespace" "github.com/ipfs/go-datastore/namespace"
logging "github.com/ipfs/go-log/v2" logging "github.com/ipfs/go-log/v2"
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors" "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" const dsKeyActorNonce = "ActorNextNonce"
@ -27,13 +29,13 @@ type MpoolNonceAPI interface {
// MessageSigner keeps track of nonces per address, and increments the nonce // MessageSigner keeps track of nonces per address, and increments the nonce
// when signing a message // when signing a message
type MessageSigner struct { type MessageSigner struct {
wallet *wallet.Wallet wallet api.WalletAPI
lk sync.Mutex lk sync.Mutex
mpool MpoolNonceAPI mpool MpoolNonceAPI
ds datastore.Batching 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/")) ds = namespace.Wrap(ds, datastore.NewKey("/message-signer/"))
return &MessageSigner{ return &MessageSigner{
wallet: wallet, wallet: wallet,
@ -56,7 +58,16 @@ func (ms *MessageSigner) SignMessage(ctx context.Context, msg *types.Message, cb
// Sign the message with the nonce // Sign the message with the nonce
msg.Nonce = 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 { if err != nil {
return nil, xerrors.Errorf("failed to sign message: %w", err) return nil, xerrors.Errorf("failed to sign message: %w", err)
} }

View File

@ -47,13 +47,13 @@ func TestMessageSignerSignMessage(t *testing.T) {
ctx := context.Background() ctx := context.Background()
w, _ := wallet.NewWallet(wallet.NewMemKeyStore()) w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
from1, err := w.GenerateKey(crypto.SigTypeSecp256k1) from1, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1)
require.NoError(t, err) require.NoError(t, err)
from2, err := w.GenerateKey(crypto.SigTypeSecp256k1) from2, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1)
require.NoError(t, err) require.NoError(t, err)
to1, err := w.GenerateKey(crypto.SigTypeSecp256k1) to1, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1)
require.NoError(t, err) require.NoError(t, err)
to2, err := w.GenerateKey(crypto.SigTypeSecp256k1) to2, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1)
require.NoError(t, err) require.NoError(t, err)
type msgSpec struct { type msgSpec struct {

View File

@ -6,15 +6,21 @@ import (
"io" "io"
"testing" "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-address"
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/cbor" "github.com/filecoin-project/go-state-types/cbor"
"github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin"
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init" init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
"github.com/filecoin-project/specs-actors/actors/runtime" "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"
"github.com/filecoin-project/lotus/chain/actors/aerrors" "github.com/filecoin-project/lotus/chain/actors/aerrors"
lotusinit "github.com/filecoin-project/lotus/chain/actors/builtin/init" 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/chain/vm"
_ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "github.com/filecoin-project/lotus/lib/sigs/bls"
_ "github.com/filecoin-project/lotus/lib/sigs/secp" _ "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() { func init() {
@ -186,7 +187,7 @@ func TestForkHeightTriggers(t *testing.T) {
Params: enc, Params: enc,
GasLimit: types.TestGasLimit, 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -214,7 +215,7 @@ func TestForkHeightTriggers(t *testing.T) {
} }
nonce++ 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 { if err != nil {
return nil, err return nil, err
} }

View File

@ -593,7 +593,7 @@ func TestDuplicateNonce(t *testing.T) {
GasPremium: types.NewInt(0), 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) require.NoError(t, err)
return &types.SignedMessage{ return &types.SignedMessage{
@ -685,7 +685,7 @@ func TestBadNonce(t *testing.T) {
GasPremium: types.NewInt(0), 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) require.NoError(t, err)
return &types.SignedMessage{ return &types.SignedMessage{

View File

@ -9,6 +9,7 @@ import (
"github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/crypto"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/lotus/chain/wallet"
@ -22,7 +23,7 @@ func Address(i uint64) address.Address {
return a 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{ msg := &types.Message{
To: to, To: to,
From: from, From: from,
@ -33,7 +34,7 @@ func MkMessage(from, to address.Address, nonce uint64, w *wallet.Wallet) *types.
GasPremium: types.NewInt(1), 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 { if err != nil {
panic(err) panic(err)
} }

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"math/rand" "math/rand"
@ -61,11 +62,11 @@ func MakeMessageSigningVectors() []vectors.MessageSigningVector {
panic(err) panic(err)
} }
blsk, err := w.GenerateKey(crypto.SigTypeBLS) blsk, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
if err != nil { if err != nil {
panic(err) panic(err)
} }
bki, err := w.Export(blsk) bki, err := w.WalletExport(context.Background(), blsk)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -85,11 +86,11 @@ func MakeMessageSigningVectors() []vectors.MessageSigningVector {
Signature: &bmsg.Signature, Signature: &bmsg.Signature,
} }
secpk, err := w.GenerateKey(crypto.SigTypeBLS) secpk, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
if err != nil { if err != nil {
panic(err) panic(err)
} }
ski, err := w.Export(secpk) ski, err := w.WalletExport(context.Background(), secpk)
if err != nil { if err != nil {
panic(err) panic(err)
} }

81
chain/wallet/key.go Normal file
View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -12,6 +12,7 @@ import (
"github.com/filecoin-project/go-address" "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/bls" // enable bls signatures
_ "github.com/filecoin-project/lotus/lib/sigs/secp" // enable secp signatures _ "github.com/filecoin-project/lotus/lib/sigs/secp" // enable secp signatures
@ -29,15 +30,20 @@ const (
KTSecp256k1 = "secp256k1" KTSecp256k1 = "secp256k1"
) )
type Wallet struct { type LocalWallet struct {
keys map[address.Address]*Key keys map[address.Address]*Key
keystore types.KeyStore keystore types.KeyStore
lk sync.Mutex lk sync.Mutex
} }
func NewWallet(keystore types.KeyStore) (*Wallet, error) { type Default interface {
w := &Wallet{ GetDefault() (address.Address, error)
SetDefault(a address.Address) error
}
func NewWallet(keystore types.KeyStore) (*LocalWallet, error) {
w := &LocalWallet{
keys: make(map[address.Address]*Key), keys: make(map[address.Address]*Key),
keystore: keystore, keystore: keystore,
} }
@ -45,18 +51,18 @@ func NewWallet(keystore types.KeyStore) (*Wallet, error) {
return w, nil return w, nil
} }
func KeyWallet(keys ...*Key) *Wallet { func KeyWallet(keys ...*Key) *LocalWallet {
m := make(map[address.Address]*Key) m := make(map[address.Address]*Key)
for _, key := range keys { for _, key := range keys {
m[key.Address] = key m[key.Address] = key
} }
return &Wallet{ return &LocalWallet{
keys: m, 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) ki, err := w.findKey(addr)
if err != nil { if err != nil {
return nil, err 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) 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() w.lk.Lock()
defer w.lk.Unlock() defer w.lk.Unlock()
@ -96,7 +102,7 @@ func (w *Wallet) findKey(addr address.Address) (*Key, error) {
return k, nil 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()) ki, err := w.keystore.Get(KNamePrefix + addr.String())
if err == nil { if err == nil {
@ -130,7 +136,7 @@ func (w *Wallet) tryFind(addr address.Address) (types.KeyInfo, error) {
return ki, nil 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) k, err := w.findKey(addr)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to find key to export: %w", err) 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 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() w.lk.Lock()
defer w.lk.Unlock() defer w.lk.Unlock()
@ -155,7 +161,7 @@ func (w *Wallet) Import(ki *types.KeyInfo) (address.Address, error) {
return k.Address, nil 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() all, err := w.keystore.List()
if err != nil { if err != nil {
return nil, xerrors.Errorf("listing keystore: %w", err) return nil, xerrors.Errorf("listing keystore: %w", err)
@ -188,7 +194,7 @@ func (w *Wallet) ListAddrs() ([]address.Address, error) {
return out, nil return out, nil
} }
func (w *Wallet) GetDefault() (address.Address, error) { func (w *LocalWallet) GetDefault() (address.Address, error) {
w.lk.Lock() w.lk.Lock()
defer w.lk.Unlock() defer w.lk.Unlock()
@ -205,7 +211,7 @@ func (w *Wallet) GetDefault() (address.Address, error) {
return k.Address, nil return k.Address, nil
} }
func (w *Wallet) SetDefault(a address.Address) error { func (w *LocalWallet) SetDefault(a address.Address) error {
w.lk.Lock() w.lk.Lock()
defer w.lk.Unlock() defer w.lk.Unlock()
@ -227,19 +233,7 @@ func (w *Wallet) SetDefault(a address.Address) error {
return nil return nil
} }
func GenerateKey(typ crypto.SigType) (*Key, error) { func (w *LocalWallet) WalletNew(ctx context.Context, typ crypto.SigType) (address.Address, 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) {
w.lk.Lock() w.lk.Lock()
defer w.lk.Unlock() defer w.lk.Unlock()
@ -267,7 +261,7 @@ func (w *Wallet) GenerateKey(typ crypto.SigType) (address.Address, error) {
return k.Address, nil 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) k, err := w.findKey(addr)
if err != nil { if err != nil {
return false, err return false, err
@ -275,7 +269,7 @@ func (w *Wallet) HasKey(addr address.Address) (bool, error) {
return k != nil, nil 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) k, err := w.findKey(addr)
if err != nil { if err != nil {
return xerrors.Errorf("failed to delete key %s : %w", addr, err) 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 return nil
} }
type Key struct { var _ api.WalletAPI = &LocalWallet{}
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
}
}
func swapMainnetForTestnetPrefix(addr string) (string, error) { func swapMainnetForTestnetPrefix(addr string) (string, error) {
aChars := []rune(addr) aChars := []rune(addr)

View File

@ -4,7 +4,6 @@ import (
"context" "context"
"fmt" "fmt"
"net/http" "net/http"
"net/url"
"os" "os"
"os/signal" "os/signal"
"strings" "strings"
@ -12,8 +11,6 @@ import (
logging "github.com/ipfs/go-log/v2" logging "github.com/ipfs/go-log/v2"
"github.com/mitchellh/go-homedir" "github.com/mitchellh/go-homedir"
"github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr/net"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"golang.org/x/xerrors" "golang.org/x/xerrors"
@ -21,6 +18,7 @@ import (
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/client" "github.com/filecoin-project/lotus/api/client"
cliutil "github.com/filecoin-project/lotus/cli/util"
"github.com/filecoin-project/lotus/node/repo" "github.com/filecoin-project/lotus/node/repo"
) )
@ -47,57 +45,6 @@ func NewCliError(s string) error {
// ApiConnector returns API instance // ApiConnector returns API instance
type ApiConnector func() api.FullNode 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 // The flag passed on the command line with the listen address of the API
// server (only used by the tests) // server (only used by the tests)
func flagForAPI(t repo.RepoType) string { 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 // Check if there was a flag passed with the listen address of the API
// server (only used by the tests) // server (only used by the tests)
apiFlag := flagForAPI(t) apiFlag := flagForAPI(t)
@ -161,7 +108,7 @@ func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
strma := ctx.String(apiFlag) strma := ctx.String(apiFlag)
strma = strings.TrimSpace(strma) strma = strings.TrimSpace(strma)
return APIInfo{Addr: strma}, nil return cliutil.APIInfo{Addr: strma}, nil
} }
envKey := envForRepo(t) envKey := envForRepo(t)
@ -175,32 +122,24 @@ func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
} }
} }
if ok { if ok {
sp := strings.SplitN(env, ":", 2) return cliutil.ParseApiInfo(env), nil
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
}
} }
repoFlag := flagForRepo(t) repoFlag := flagForRepo(t)
p, err := homedir.Expand(ctx.String(repoFlag)) p, err := homedir.Expand(ctx.String(repoFlag))
if err != nil { 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) r, err := repo.NewFS(p)
if err != nil { 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() ma, err := r.APIEndpoint()
if err != nil { 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() 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) log.Warnf("Couldn't load CLI token, capabilities may be limited: %v", err)
} }
return APIInfo{ return cliutil.APIInfo{
Addr: ma.String(), Addr: ma.String(),
Token: token, Token: token,
}, nil }, nil

83
cli/util/apiinfo.go Normal file
View File

@ -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
}

View File

@ -40,12 +40,12 @@ func main() {
return fmt.Errorf("unrecognized key type: %q", cctx.String("type")) 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 { if err != nil {
return err return err
} }
ki, err := w.Export(kaddr) ki, err := w.WalletExport(cctx.Context, kaddr)
if err != nil { if err != nil {
return err return err
} }

View File

@ -15,6 +15,7 @@ import (
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli" lcli "github.com/filecoin-project/lotus/cli"
cliutil "github.com/filecoin-project/lotus/cli/util"
"github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/peer"
"github.com/multiformats/go-multiaddr" "github.com/multiformats/go-multiaddr"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
@ -111,7 +112,7 @@ var consensusCheckCmd = &cli.Command{
if err != nil { if err != nil {
return err return err
} }
ainfo := lcli.APIInfo{Addr: apima.String()} ainfo := cliutil.APIInfo{Addr: apima.String()}
addr, err := ainfo.DialArgs() addr, err := ainfo.DialArgs()
if err != nil { if err != nil {
return err return err

View File

@ -105,7 +105,7 @@ var keyinfoVerifyCmd = &cli.Command{
return err return err
} }
if _, err := w.Import(&keyInfo); err != nil { if _, err := w.WalletImport(cctx.Context, &keyInfo); err != nil {
return err return err
} }
@ -220,7 +220,7 @@ var keyinfoImportCmd = &cli.Command{
return err return err
} }
addr, err := w.Import(&keyInfo) addr, err := w.WalletImport(cctx.Context, &keyInfo)
if err != nil { if err != nil {
return err return err
} }

View File

@ -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)
}

141
cmd/lotus-wallet/main.go Normal file
View File

@ -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)
},
}

View File

@ -2146,8 +2146,7 @@ Inputs:
Response: `"0"` Response: `"0"`
### MsigGetVestingSchedule ### MsigGetVestingSchedule
MsigGetLockedBalance returns the locked balance of an msig at a vien epoch. MsigGetVestingSchedule returns the vesting details of a given multisig.
The return may be greater than the multisig actor's actual balance.
Perms: read Perms: read

2
go.mod
View File

@ -30,7 +30,7 @@ require (
github.com/filecoin-project/go-data-transfer v0.6.7 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-commcid v0.0.0-20200716160307-8f644712406f
github.com/filecoin-project/go-fil-markets v0.7.1 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-multistore v0.0.3
github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20
github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261 github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261

4
go.sum
View File

@ -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 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 h1:b3UDemBYN2HNfk3KOXNuxgTTxlWi3xVvbQP0IT38fvM=
github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0/go.mod h1:7aWZdaQ1b16BVoQUYR+eEvrDCGJoPLxFpDynFjYfBjI= 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.20201008195726-68c6a2704e49 h1:FSY245KeXFCUgyfFEu+bhrZNk8BGGJyfpSmQl2aiPU8=
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/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 h1:vaRBY4YiA2UZFPK57RNuewypB8u0DzzQwqsL0XarpnI=
github.com/filecoin-project/go-multistore v0.0.3/go.mod h1:kaNqCC4IhU4B1uyr7YWFHd23TL4KM32aChS0jNkyUvQ= 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= github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 h1:+/4aUeUoKr6AKfPE3mBhXA5spIV6UcKdTYDPNU2Tdmg=

View File

@ -6,19 +6,22 @@ import (
"bytes" "bytes"
"context" "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" "golang.org/x/xerrors"
"github.com/ipfs/go-cid"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
cborutil "github.com/filecoin-project/go-cbor-util" cborutil "github.com/filecoin-project/go-cbor-util"
"github.com/filecoin-project/go-fil-markets/shared" "github.com/filecoin-project/go-fil-markets/shared"
"github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-fil-markets/storagemarket"
"github.com/filecoin-project/go-state-types/abi" "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/crypto"
"github.com/filecoin-project/go-state-types/exitcode" "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/build"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/events"
@ -30,7 +33,6 @@ import (
"github.com/filecoin-project/lotus/lib/sigs" "github.com/filecoin-project/lotus/lib/sigs"
"github.com/filecoin-project/lotus/markets/utils" "github.com/filecoin-project/lotus/markets/utils"
"github.com/filecoin-project/lotus/node/impl/full" "github.com/filecoin-project/lotus/node/impl/full"
"github.com/ipfs/go-cid"
) )
type ClientNodeAdapter struct { type ClientNodeAdapter struct {
@ -422,7 +424,9 @@ func (c *ClientNodeAdapter) SignProposal(ctx context.Context, signer address.Add
return nil, err 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 { if err != nil {
return nil, err 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) { func (c *ClientNodeAdapter) GetDefaultWalletAddress(ctx context.Context) (address.Address, error) {
addr, err := c.Wallet.GetDefault() addr, err := c.DefWallet.GetDefault()
return addr, err return addr, err
} }
@ -475,7 +479,9 @@ func (c *ClientNodeAdapter) SignBytes(ctx context.Context, signer address.Addres
return nil, err 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 { if err != nil {
return nil, err return nil, err
} }

View File

@ -44,6 +44,7 @@ import (
"github.com/filecoin-project/lotus/chain/metrics" "github.com/filecoin-project/lotus/chain/metrics"
"github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet/remotewallet"
sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage" 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/ffiwrapper"
"github.com/filecoin-project/lotus/extern/sector-storage/stores" "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.UpgradeSchedule), stmgr.DefaultUpgradeSchedule()),
Override(new(*stmgr.StateManager), stmgr.NewStateManagerWithUpgradeSchedule), Override(new(*stmgr.StateManager), stmgr.NewStateManagerWithUpgradeSchedule),
Override(new(stmgr.StateManagerAPI), From(new(*stmgr.StateManager))), 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(*messagesigner.MessageSigner), messagesigner.NewMessageSigner),
Override(new(dtypes.ChainGCLocker), blockstore.NewGCLocker), Override(new(dtypes.ChainGCLocker), blockstore.NewGCLocker),
@ -456,6 +459,9 @@ func ConfigFullNode(c interface{}) Option {
If(cfg.Metrics.HeadNotifs, If(cfg.Metrics.HeadNotifs,
Override(HeadMetricsKey, metrics.SendHeadNotifs(cfg.Metrics.Nickname)), Override(HeadMetricsKey, metrics.SendHeadNotifs(cfg.Metrics.Nickname)),
), ),
If(cfg.Wallet.RemoteBackend != "",
Override(new(api.WalletAPI), remotewallet.SetupRemoteWallet(cfg.Wallet.RemoteBackend)),
),
) )
} }

View File

@ -22,6 +22,7 @@ type FullNode struct {
Common Common
Client Client Client Client
Metrics Metrics Metrics Metrics
Wallet Wallet
} }
// // Common // // Common
@ -107,6 +108,10 @@ type Client struct {
IpfsUseForRetrieval bool IpfsUseForRetrieval bool
} }
type Wallet struct {
RemoteBackend string
}
func defCommon() Common { func defCommon() Common {
return Common{ return Common{
API: API{ API: API{

View File

@ -5,14 +5,6 @@ import (
"context" "context"
"strconv" "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" cid "github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
"go.uber.org/fx" "go.uber.org/fx"
@ -22,14 +14,19 @@ import (
"github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-bitfield"
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big" "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/extern/sector-storage/ffiwrapper"
"github.com/filecoin-project/lotus/api" "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/market"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner" "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/multisig"
"github.com/filecoin-project/lotus/chain/actors/builtin/power" "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/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/beacon"
"github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/gen"
"github.com/filecoin-project/lotus/chain/state" "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 // TODO: the wallet here is only needed because we have the MinerCreateBlock
// API attached to the state API. It probably should live somewhere better // API attached to the state API. It probably should live somewhere better
Wallet *wallet.Wallet Wallet api.WalletAPI
DefWallet wallet.Default
StateModuleAPI StateModuleAPI

View File

@ -3,13 +3,14 @@ package full
import ( import (
"context" "context"
"github.com/filecoin-project/go-address"
"go.uber.org/fx" "go.uber.org/fx"
"golang.org/x/xerrors" "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/big"
"github.com/filecoin-project/go-state-types/crypto" "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/stmgr"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/lotus/chain/wallet"
@ -20,19 +21,8 @@ type WalletAPI struct {
fx.In fx.In
StateManagerAPI stmgr.StateManagerAPI StateManagerAPI stmgr.StateManagerAPI
Wallet *wallet.Wallet Default wallet.Default
} api.WalletAPI
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()
} }
func (a *WalletAPI) WalletBalance(ctx context.Context, addr address.Address) (types.BigInt, error) { 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 { if err != nil {
return nil, xerrors.Errorf("failed to resolve ID address: %w", keyAddr) 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) { 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 { if err != nil {
return nil, xerrors.Errorf("failed to sign message: %w", err) 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) { 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 { func (a *WalletAPI) WalletSetDefault(ctx context.Context, addr address.Address) error {
return a.Wallet.SetDefault(addr) return a.Default.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)
} }
func (a *WalletAPI) WalletValidateAddress(ctx context.Context, str string) (address.Address, error) { func (a *WalletAPI) WalletValidateAddress(ctx context.Context, str string) (address.Address, error) {

View File

@ -44,6 +44,7 @@ const (
FullNode RepoType = iota FullNode RepoType = iota
StorageMiner StorageMiner
Worker Worker
Wallet
) )
func defConfForType(t RepoType) interface{} { func defConfForType(t RepoType) interface{} {
@ -54,6 +55,8 @@ func defConfForType(t RepoType) interface{} {
return config.DefaultStorageMiner() return config.DefaultStorageMiner()
case Worker: case Worker:
return &struct{}{} return &struct{}{}
case Wallet:
return &struct{}{}
default: default:
panic(fmt.Sprintf("unknown RepoType(%d)", int(t))) panic(fmt.Sprintf("unknown RepoType(%d)", int(t)))
} }
@ -93,6 +96,12 @@ func (fsr *FsRepo) Exists() (bool, error) {
notexist := os.IsNotExist(err) notexist := os.IsNotExist(err)
if notexist { if notexist {
err = nil err = nil
_, err = os.Stat(filepath.Join(fsr.path, fsKeystore))
notexist = os.IsNotExist(err)
if notexist {
err = nil
}
} }
return !notexist, err return !notexist, err
} }