diff --git a/app/submodule/wallet/remotewallet/remote.go b/app/submodule/wallet/remotewallet/remote.go index b6f0615492..2e9df35b6d 100644 --- a/app/submodule/wallet/remotewallet/remote.go +++ b/app/submodule/wallet/remotewallet/remote.go @@ -20,7 +20,7 @@ type remoteWallet struct { } func (w *remoteWallet) Addresses(ctx context.Context) []address.Address { - wallets, err := w.IWallet.WalletList(context.Background()) + wallets, err := w.IWallet.WalletList(ctx) if err != nil { return make([]address.Address, 0) } @@ -51,22 +51,27 @@ func SetupRemoteWallet(info string) (wallet.WalletIntersection, error) { } func (w *remoteWallet) HasAddress(ctx context.Context, addr address.Address) bool { - exist, err := w.IWallet.WalletHas(context.Background(), addr) + exist, err := w.IWallet.WalletHas(ctx, addr) if err != nil { return false } return exist } + func (w *remoteWallet) NewAddress(ctx context.Context, protocol address.Protocol) (address.Address, error) { - return w.IWallet.WalletNew(context.Background(), GetKeyType(protocol)) + return w.IWallet.WalletNew(ctx, GetKeyType(protocol)) +} + +func (w *remoteWallet) DeleteAddress(ctx context.Context, addr address.Address) error { + return w.IWallet.WalletDelete(ctx, addr) } func (w *remoteWallet) Import(ctx context.Context, key *crypto.KeyInfo) (address.Address, error) { - return w.IWallet.WalletImport(context.Background(), ConvertRemoteKeyInfo(key)) + return w.IWallet.WalletImport(ctx, ConvertRemoteKeyInfo(key)) } func (w *remoteWallet) Export(ctx context.Context, addr address.Address, password string) (*crypto.KeyInfo, error) { - key, err := w.IWallet.WalletExport(context.Background(), addr) + key, err := w.IWallet.WalletExport(ctx, addr) if err != nil { return nil, err } @@ -74,5 +79,5 @@ func (w *remoteWallet) Export(ctx context.Context, addr address.Address, passwor } func (w *remoteWallet) WalletSign(ctx context.Context, keyAddr address.Address, msg []byte, meta types.MsgMeta) (*crypto.Signature, error) { - return w.IWallet.WalletSign(context.Background(), keyAddr, msg, meta) + return w.IWallet.WalletSign(ctx, keyAddr, msg, meta) } diff --git a/app/submodule/wallet/wallet_api.go b/app/submodule/wallet/wallet_api.go index a9c58bb68b..f56f0b500a 100644 --- a/app/submodule/wallet/wallet_api.go +++ b/app/submodule/wallet/wallet_api.go @@ -107,6 +107,11 @@ func (walletAPI *WalletAPI) WalletExport(ctx context.Context, addr address.Addre return remotewallet.ConvertRemoteKeyInfo(ki), nil } +// WalletDelete delete the given walletModule address +func (walletAPI *WalletAPI) WalletDelete(ctx context.Context, addr address.Address) error { + return walletAPI.adapter.DeleteAddress(ctx, addr) +} + // WalletSign signs the given bytes using the given address. func (walletAPI *WalletAPI) WalletSign(ctx context.Context, k address.Address, msg []byte, meta types.MsgMeta) (*crypto.Signature, error) { keyAddr, err := walletAPI.walletModule.Chain.Stmgr.ResolveToKeyAddress(ctx, k, nil) diff --git a/cmd/address.go b/cmd/address.go index 8b22cd0e81..463046a38f 100644 --- a/cmd/address.go +++ b/cmd/address.go @@ -10,12 +10,14 @@ import ( "os" "strings" - "github.com/filecoin-project/go-address" "github.com/howeyc/gopass" + cmds "github.com/ipfs/go-ipfs-cmds" files "github.com/ipfs/go-ipfs-files" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/venus/app/node" "github.com/filecoin-project/venus/cmd/tablewriter" "github.com/filecoin-project/venus/pkg/crypto" @@ -37,6 +39,7 @@ var walletCmd = &cmds.Command{ "ls": addrsLsCmd, "new": addrsNewCmd, "default": defaultAddressCmd, + "delete": addrsDeleteCmd, "set-default": setDefaultAddressCmd, "lock": lockedCmd, "unlock": unlockedCmd, @@ -85,6 +88,39 @@ var addrsNewCmd = &cmds.Command{ }, } +var addrsDeleteCmd = &cmds.Command{ + Arguments: []cmds.Argument{ + cmds.StringArg("address", true, false, "wallet address"), + }, + Options: []cmds.Option{ + cmds.BoolOption("really-do-it", "Actually send transaction performing the action").WithDefault(false), + }, + Run: func(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) error { + if really := req.Options["really-do-it"].(bool); !really { + return fmt.Errorf("pass --really-do-it to actually execute this action") + } + + addr, err := address.NewFromString(req.Arguments[0]) + if err != nil { + return err + } + + if !env.(*node.Env).WalletAPI.HasPassword(req.Context) { + return errMissPassword + } + if env.(*node.Env).WalletAPI.WalletState(req.Context) == wallet.Lock { + return errWalletLocked + } + + err = env.(*node.Env).WalletAPI.WalletDelete(req.Context, addr) + if err != nil { + return err + } + + return printOneString(re, "Delete successfully!") + }, +} + var addrsLsCmd = &cmds.Command{ Options: []cmds.Option{ cmds.BoolOption("addr-only", "Only print addresses"), diff --git a/pkg/wallet/backend.go b/pkg/wallet/backend.go index c182ade637..2f0ea756ca 100644 --- a/pkg/wallet/backend.go +++ b/pkg/wallet/backend.go @@ -17,6 +17,8 @@ type Backend interface { // Contains returns true if this backend stores the passed in address. HasAddress(context.Context, address.Address) bool + DeleteAddress(context.Context, address.Address) error + // Sign cryptographically signs data with the private key associated with an address. SignBytes(context.Context, []byte, address.Address) (*crypto.Signature, error) diff --git a/pkg/wallet/dsbackend.go b/pkg/wallet/dsbackend.go index 870376671c..1e6d43bbef 100644 --- a/pkg/wallet/dsbackend.go +++ b/pkg/wallet/dsbackend.go @@ -188,6 +188,22 @@ func (backend *DSBackend) putKeyInfo(ctx context.Context, ki *crypto.KeyInfo) er return nil } +func (backend *DSBackend) DeleteAddress(ctx context.Context, addr address.Address) error { + backend.lk.RLock() + defer backend.lk.RUnlock() + + if _, ok := backend.cache[addr]; ok { + err := backend.ds.Delete(ctx, ds.NewKey(addr.String())) + if err != nil { + return err + } + delete(backend.cache, addr) + return nil + } + + return errors.New("backend does not contain address") +} + // SignBytes cryptographically signs `data` using the private key `priv`. func (backend *DSBackend) SignBytes(ctx context.Context, data []byte, addr address.Address) (*crypto.Signature, error) { backend.lk.Lock() diff --git a/pkg/wallet/dsbackend_test.go b/pkg/wallet/dsbackend_test.go index 9c3f6f492d..d40787e728 100644 --- a/pkg/wallet/dsbackend_test.go +++ b/pkg/wallet/dsbackend_test.go @@ -47,6 +47,11 @@ func TestDSBackendSimple(t *testing.T) { assert.NoError(t, err) assert.True(t, fs2.HasAddress(ctx, addr)) + + t.Log("delete the address") + err = fs2.DeleteAddress(ctx, addr) + assert.NoError(t, err) + assert.False(t, fs2.HasAddress(ctx, addr)) } func TestDSBackendKeyPairMatchAddress(t *testing.T) { diff --git a/pkg/wallet/wallet.go b/pkg/wallet/wallet.go index 77670560f9..5755505b44 100644 --- a/pkg/wallet/wallet.go +++ b/pkg/wallet/wallet.go @@ -25,9 +25,10 @@ var walletLog = logging.Logger("wallet") // WalletIntersection // nolint type WalletIntersection interface { - HasAddress(ctx context.Context, a address.Address) bool + HasAddress(ctx context.Context, addr address.Address) bool Addresses(ctx context.Context) []address.Address - NewAddress(ctx context.Context, p address.Protocol) (address.Address, error) + NewAddress(ctx context.Context, protocol address.Protocol) (address.Address, error) + DeleteAddress(ctx context.Context, addr address.Address) error Import(ctx context.Context, ki *crypto.KeyInfo) (address.Address, error) Export(ctx context.Context, addr address.Address, password string) (*crypto.KeyInfo, error) WalletSign(ctx context.Context, keyAddr address.Address, msg []byte, meta types.MsgMeta) (*crypto.Signature, error) @@ -133,6 +134,25 @@ func (w *Wallet) NewAddress(ctx context.Context, p address.Protocol) (address.Ad return backend.NewAddress(ctx, p) } +// DeleteAddress delete the given address from stored. +func (w *Wallet) DeleteAddress(ctx context.Context, addr address.Address) error { + w.lk.Lock() + defer w.lk.Unlock() + + for _, backends := range w.backends { + for _, backend := range backends { + if backend.HasAddress(ctx, addr) { + err := backend.DeleteAddress(ctx, addr) + if err != nil { + return err + } + } + } + } + + return nil +} + // GetPubKeyForAddress returns the public key in the keystore associated with // the given address. func (w *Wallet) GetPubKeyForAddress(ctx context.Context, addr address.Address) ([]byte, error) { diff --git a/pkg/wallet/wallet_test.go b/pkg/wallet/wallet_test.go index 4031635bd1..9fb81ecd1f 100644 --- a/pkg/wallet/wallet_test.go +++ b/pkg/wallet/wallet_test.go @@ -40,7 +40,7 @@ func TestWalletSimple(t *testing.T) { w, fs := newWalletAndDSBackend(t) t.Log("create a new address in the backend") - addr, err := fs.NewAddress(context.Background(), address.SECP256K1) + addr, err := fs.NewAddress(ctx, address.SECP256K1) assert.NoError(t, err) t.Log("test HasAddress") @@ -62,7 +62,7 @@ func TestWalletSimple(t *testing.T) { assert.Equal(t, list[0], addr) t.Log("addresses are sorted") - addr2, err := fs.NewAddress(context.Background(), address.SECP256K1) + addr2, err := fs.NewAddress(ctx, address.SECP256K1) assert.NoError(t, err) if bytes.Compare(addr2.Bytes(), addr.Bytes()) < 0 { @@ -74,6 +74,14 @@ func TestWalletSimple(t *testing.T) { assert.Equal(t, list[0], addr) assert.Equal(t, list[1], addr2) } + + t.Log("test DeleteAddress") + err = fs.DeleteAddress(ctx, addr) + assert.NoError(t, err) + err = fs.DeleteAddress(ctx, addr2) + assert.NoError(t, err) + assert.False(t, w.HasAddress(ctx, addr)) + assert.False(t, w.HasAddress(ctx, addr2)) } func TestWalletBLSKeys(t *testing.T) { diff --git a/venus-shared/api/chain/v0/method.md b/venus-shared/api/chain/v0/method.md index 0155376c9a..789d306521 100644 --- a/venus-shared/api/chain/v0/method.md +++ b/venus-shared/api/chain/v0/method.md @@ -184,6 +184,7 @@ * [WalletAddresses](#WalletAddresses) * [WalletBalance](#WalletBalance) * [WalletDefaultAddress](#WalletDefaultAddress) + * [WalletDelete](#WalletDelete) * [WalletExport](#WalletExport) * [WalletHas](#WalletHas) * [WalletImport](#WalletImport) @@ -5495,6 +5496,20 @@ Inputs: `[]` Response: `"f01234"` +### WalletDelete + + +Perms: admin + +Inputs: +```json +[ + "f01234" +] +``` + +Response: `{}` + ### WalletExport diff --git a/venus-shared/api/chain/v0/mock/mock_fullnode.go b/venus-shared/api/chain/v0/mock/mock_fullnode.go index 0b45514020..dd9215e93e 100644 --- a/venus-shared/api/chain/v0/mock/mock_fullnode.go +++ b/venus-shared/api/chain/v0/mock/mock_fullnode.go @@ -2562,6 +2562,20 @@ func (mr *MockFullNodeMockRecorder) WalletDefaultAddress(arg0 interface{}) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletDefaultAddress", reflect.TypeOf((*MockFullNode)(nil).WalletDefaultAddress), arg0) } +// WalletDelete mocks base method. +func (m *MockFullNode) WalletDelete(arg0 context.Context, arg1 address.Address) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WalletDelete", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// WalletDelete indicates an expected call of WalletDelete. +func (mr *MockFullNodeMockRecorder) WalletDelete(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletDelete", reflect.TypeOf((*MockFullNode)(nil).WalletDelete), arg0, arg1) +} + // WalletExport mocks base method. func (m *MockFullNode) WalletExport(arg0 context.Context, arg1 address.Address, arg2 string) (*types.KeyInfo, error) { m.ctrl.T.Helper() diff --git a/venus-shared/api/chain/v0/proxy_gen.go b/venus-shared/api/chain/v0/proxy_gen.go index 8a75df493b..3c3199e92f 100644 --- a/venus-shared/api/chain/v0/proxy_gen.go +++ b/venus-shared/api/chain/v0/proxy_gen.go @@ -759,6 +759,7 @@ type IWalletStruct struct { WalletAddresses func(ctx context.Context) []address.Address `perm:"admin"` WalletBalance func(ctx context.Context, addr address.Address) (abi.TokenAmount, error) `perm:"read"` WalletDefaultAddress func(ctx context.Context) (address.Address, error) `perm:"write"` + WalletDelete func(ctx context.Context, addr address.Address) error `perm:"admin"` WalletExport func(ctx context.Context, addr address.Address, password string) (*types.KeyInfo, error) `perm:"admin"` WalletHas func(ctx context.Context, addr address.Address) (bool, error) `perm:"write"` WalletImport func(ctx context.Context, key *types.KeyInfo) (address.Address, error) `perm:"admin"` @@ -787,6 +788,9 @@ func (s *IWalletStruct) WalletBalance(p0 context.Context, p1 address.Address) (a func (s *IWalletStruct) WalletDefaultAddress(p0 context.Context) (address.Address, error) { return s.Internal.WalletDefaultAddress(p0) } +func (s *IWalletStruct) WalletDelete(p0 context.Context, p1 address.Address) error { + return s.Internal.WalletDelete(p0, p1) +} func (s *IWalletStruct) WalletExport(p0 context.Context, p1 address.Address, p2 string) (*types.KeyInfo, error) { return s.Internal.WalletExport(p0, p1, p2) } diff --git a/venus-shared/api/chain/v0/wallet.go b/venus-shared/api/chain/v0/wallet.go index ae782d46f4..fa9c5a251b 100644 --- a/venus-shared/api/chain/v0/wallet.go +++ b/venus-shared/api/chain/v0/wallet.go @@ -14,6 +14,7 @@ type IWallet interface { WalletSign(ctx context.Context, k address.Address, msg []byte, meta types.MsgMeta) (*crypto.Signature, error) //perm:sign WalletExport(ctx context.Context, addr address.Address, password string) (*types.KeyInfo, error) //perm:admin WalletImport(ctx context.Context, key *types.KeyInfo) (address.Address, error) //perm:admin + WalletDelete(ctx context.Context, addr address.Address) error //perm:admin WalletHas(ctx context.Context, addr address.Address) (bool, error) //perm:write WalletNewAddress(ctx context.Context, protocol address.Protocol) (address.Address, error) //perm:write WalletBalance(ctx context.Context, addr address.Address) (abi.TokenAmount, error) //perm:read diff --git a/venus-shared/api/chain/v1/method.md b/venus-shared/api/chain/v1/method.md index d178fb117e..d0adca560a 100644 --- a/venus-shared/api/chain/v1/method.md +++ b/venus-shared/api/chain/v1/method.md @@ -192,6 +192,7 @@ * [WalletAddresses](#WalletAddresses) * [WalletBalance](#WalletBalance) * [WalletDefaultAddress](#WalletDefaultAddress) + * [WalletDelete](#WalletDelete) * [WalletExport](#WalletExport) * [WalletHas](#WalletHas) * [WalletImport](#WalletImport) @@ -6016,6 +6017,20 @@ Inputs: `[]` Response: `"f01234"` +### WalletDelete + + +Perms: admin + +Inputs: +```json +[ + "f01234" +] +``` + +Response: `{}` + ### WalletExport diff --git a/venus-shared/api/chain/v1/mock/mock_fullnode.go b/venus-shared/api/chain/v1/mock/mock_fullnode.go index 95b6da201f..58d413058a 100644 --- a/venus-shared/api/chain/v1/mock/mock_fullnode.go +++ b/venus-shared/api/chain/v1/mock/mock_fullnode.go @@ -2698,6 +2698,20 @@ func (mr *MockFullNodeMockRecorder) WalletDefaultAddress(arg0 interface{}) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletDefaultAddress", reflect.TypeOf((*MockFullNode)(nil).WalletDefaultAddress), arg0) } +// WalletDelete mocks base method. +func (m *MockFullNode) WalletDelete(arg0 context.Context, arg1 address.Address) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WalletDelete", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// WalletDelete indicates an expected call of WalletDelete. +func (mr *MockFullNodeMockRecorder) WalletDelete(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletDelete", reflect.TypeOf((*MockFullNode)(nil).WalletDelete), arg0, arg1) +} + // WalletExport mocks base method. func (m *MockFullNode) WalletExport(arg0 context.Context, arg1 address.Address, arg2 string) (*types.KeyInfo, error) { m.ctrl.T.Helper() diff --git a/venus-shared/api/chain/v1/proxy_gen.go b/venus-shared/api/chain/v1/proxy_gen.go index 69fafa303a..87bc9d4cce 100644 --- a/venus-shared/api/chain/v1/proxy_gen.go +++ b/venus-shared/api/chain/v1/proxy_gen.go @@ -789,6 +789,7 @@ type IWalletStruct struct { WalletAddresses func(ctx context.Context) []address.Address `perm:"admin"` WalletBalance func(ctx context.Context, addr address.Address) (abi.TokenAmount, error) `perm:"read"` WalletDefaultAddress func(ctx context.Context) (address.Address, error) `perm:"write"` + WalletDelete func(ctx context.Context, addr address.Address) error `perm:"admin"` WalletExport func(ctx context.Context, addr address.Address, password string) (*types.KeyInfo, error) `perm:"admin"` WalletHas func(ctx context.Context, addr address.Address) (bool, error) `perm:"write"` WalletImport func(ctx context.Context, key *types.KeyInfo) (address.Address, error) `perm:"admin"` @@ -817,6 +818,9 @@ func (s *IWalletStruct) WalletBalance(p0 context.Context, p1 address.Address) (a func (s *IWalletStruct) WalletDefaultAddress(p0 context.Context) (address.Address, error) { return s.Internal.WalletDefaultAddress(p0) } +func (s *IWalletStruct) WalletDelete(p0 context.Context, p1 address.Address) error { + return s.Internal.WalletDelete(p0, p1) +} func (s *IWalletStruct) WalletExport(p0 context.Context, p1 address.Address, p2 string) (*types.KeyInfo, error) { return s.Internal.WalletExport(p0, p1, p2) } diff --git a/venus-shared/api/chain/v1/wallet.go b/venus-shared/api/chain/v1/wallet.go index 9b6203663f..335dcdb303 100644 --- a/venus-shared/api/chain/v1/wallet.go +++ b/venus-shared/api/chain/v1/wallet.go @@ -14,6 +14,7 @@ type IWallet interface { WalletSign(ctx context.Context, k address.Address, msg []byte, meta types.MsgMeta) (*crypto.Signature, error) //perm:sign WalletExport(ctx context.Context, addr address.Address, password string) (*types.KeyInfo, error) //perm:admin WalletImport(ctx context.Context, key *types.KeyInfo) (address.Address, error) //perm:admin + WalletDelete(ctx context.Context, addr address.Address) error //perm:admin WalletHas(ctx context.Context, addr address.Address) (bool, error) //perm:write WalletNewAddress(ctx context.Context, protocol address.Protocol) (address.Address, error) //perm:write WalletBalance(ctx context.Context, addr address.Address) (abi.TokenAmount, error) //perm:read diff --git a/venus-shared/compatible-checks/api-diff.txt b/venus-shared/compatible-checks/api-diff.txt index 57366db181..1c7566fe93 100644 --- a/venus-shared/compatible-checks/api-diff.txt +++ b/venus-shared/compatible-checks/api-diff.txt @@ -105,7 +105,6 @@ github.com/filecoin-project/venus/venus-shared/api/chain/v0.FullNode <> github.c + VerifyEntry > Version {[func(context.Context) (types.Version, error) <> func(context.Context) (api.APIVersion, error)] base=func out type: #0 input; nested={[types.Version <> api.APIVersion] base=struct field; nested={[types.Version <> api.APIVersion] base=exported fields count: 2 != 3; nested=nil}}} + WalletAddresses - - WalletDelete > WalletExport {[func(context.Context, address.Address, string) (*types.KeyInfo, error) <> func(context.Context, address.Address) (*types.KeyInfo, error)] base=func in num: 3 != 2; nested=nil} - WalletList - WalletNew @@ -219,7 +218,6 @@ github.com/filecoin-project/venus/venus-shared/api/chain/v1.FullNode <> github.c + VerifyEntry > Version {[func(context.Context) (types.Version, error) <> func(context.Context) (api.APIVersion, error)] base=func out type: #0 input; nested={[types.Version <> api.APIVersion] base=struct field; nested={[types.Version <> api.APIVersion] base=exported fields count: 2 != 3; nested=nil}}} + WalletAddresses - - WalletDelete > WalletExport {[func(context.Context, address.Address, string) (*types.KeyInfo, error) <> func(context.Context, address.Address) (*types.KeyInfo, error)] base=func in num: 3 != 2; nested=nil} - WalletList - WalletNew