diff --git a/build/builder.go b/build/builder.go index 1c04fe0..8ae13e9 100644 --- a/build/builder.go +++ b/build/builder.go @@ -16,6 +16,7 @@ import ( "github.com/gbrlsnchs/jwt/v3" "github.com/ipfs-force-community/venus-gateway/types" "go.uber.org/fx" + "gorm.io/gorm" wallet_api "github.com/filecoin-project/venus/venus-shared/api/wallet" ) @@ -62,10 +63,11 @@ func WalletOpt(repo filemgr.Repo, walletPwd string) Option { Override(new(filemgr.Repo), repo), Override(new(*config.DBConfig), c.DB), Override(new(EventBus.Bus), EventBus.New), - Override(new(*sqlite.Conn), sqlite.NewSQLiteConn), + Override(new(*gorm.DB), sqlite.NewDB), Override(new(*config.CryptoFactor), c.Factor), Override(new(storage.KeyMiddleware), storage.NewKeyMiddleware), Override(new(storage.KeyStore), sqlite.NewKeyStore), + Override(new(storage.IRecorder), sqlite.NewSqliteRecorder), Override(new(wallet.GetPwdFunc), func() wallet.GetPwdFunc { return func() string { return walletPwd diff --git a/cli/cmds.go b/cli/cmds.go index 9f345ae..5b0311f 100644 --- a/cli/cmds.go +++ b/cli/cmds.go @@ -18,4 +18,5 @@ var Commands = []*cli.Command{ walletLock, walletLockState, supportCmds, + recordCmd, } diff --git a/cli/helper/helper.go b/cli/helper/helper.go index 699060a..97ad833 100644 --- a/cli/helper/helper.go +++ b/cli/helper/helper.go @@ -2,12 +2,15 @@ package helper import ( "context" + "encoding/json" "fmt" + "io" "net" "net/http" "os" "os/signal" "syscall" + "text/tabwriter" "time" jsonrpc "github.com/filecoin-project/go-jsonrpc" @@ -196,3 +199,16 @@ func (e *PrintHelpErr) Is(o error) bool { _, ok := o.(*PrintHelpErr) return ok } + +func NewTabWriter(w io.Writer) *tabwriter.Writer { + return tabwriter.NewWriter(w, 2, 4, 2, ' ', 0) +} + +func PrintJSON(v interface{}) error { + bytes, err := json.MarshalIndent(v, " ", "\t") + if err != nil { + return err + } + fmt.Println(string(bytes)) + return nil +} diff --git a/cli/record.go b/cli/record.go new file mode 100644 index 0000000..7bc93d2 --- /dev/null +++ b/cli/record.go @@ -0,0 +1,203 @@ +package cli + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "reflect" + "time" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/venus-wallet/cli/helper" + "github.com/filecoin-project/venus-wallet/storage/wallet" + "github.com/filecoin-project/venus/venus-shared/types" + "github.com/urfave/cli/v2" +) + +var recordCmd = &cli.Command{ + Name: "record", + Usage: "manipulate sign record", + Subcommands: []*cli.Command{ + recordList, + }, +} + +var recordList = &cli.Command{ + Name: "query", + Usage: "query sign record", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "address", + Usage: "address to query", + }, + &cli.StringFlag{ + Name: "type", + Usage: "sign type to query", + }, + &cli.TimestampFlag{ + Name: "from", + Aliases: []string{"after", "f"}, + Usage: "from time to query", + Timezone: time.Local, + Layout: "2006-1-2-15:04:05", + }, + &cli.TimestampFlag{ + Name: "to", + Aliases: []string{"before"}, + Timezone: time.Local, + Usage: "to time to query", + Layout: "2006-1-2-15:04:05", + }, + &cli.IntFlag{ + Name: "limit", + Usage: "limit to query", + }, + &cli.IntFlag{ + Name: "offset", + Aliases: []string{"skip"}, + Usage: "offset to query", + }, + &cli.BoolFlag{ + Name: "error", + Usage: "query error record", + }, + &cli.StringFlag{ + Name: "id", + Usage: "query record by id", + }, + &cli.BoolFlag{ + Name: "verbose", + Usage: "verbose output", + Aliases: []string{"v"}, + }, + }, + Action: func(cctx *cli.Context) error { + api, closer, err := helper.GetAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := helper.ReqContext(cctx) + + QueryParams := types.QuerySignRecordParams{} + + if cctx.IsSet("address") { + addrStr := cctx.String("address") + addr, err := address.NewFromString(addrStr) + if err != nil { + return fmt.Errorf("parse address %s : %w", addrStr, err) + } + QueryParams.Signer = addr + } + + if cctx.IsSet("type") { + t := types.MsgType(cctx.String("type")) + _, ok := wallet.SupportedMsgTypes[t] + if !ok { + + fmt.Println("supported types:") + for k := range wallet.SupportedMsgTypes { + fmt.Println(k) + } + return fmt.Errorf("unsupported type %s", t) + } + QueryParams.Type = t + } + if cctx.IsSet("from") { + from := cctx.Timestamp("from") + QueryParams.After = *from + } + if cctx.IsSet("to") { + to := cctx.Timestamp("to") + QueryParams.Before = *to + } + if cctx.IsSet("limit") { + limit := cctx.Int("limit") + QueryParams.Limit = limit + } + if cctx.IsSet("offset") { + offset := cctx.Int("offset") + QueryParams.Skip = offset + } + if cctx.IsSet("error") { + QueryParams.IsError = cctx.Bool("error") + } + if cctx.IsSet("id") { + QueryParams.ID = cctx.String("id") + } + + records, err := api.ListSignedRecord(ctx, &QueryParams) + if err != nil { + return fmt.Errorf("query sign record: %w", err) + } + + if cctx.Bool("verbose") { + output := make([]interface{}, len(records)) + type temp struct { + types.SignRecord + Detail json.RawMessage + } + + for i, r := range records { + detail, err := GetDetailInJsonRawMessage(&r) + if err != nil { + return err + } + output[i] = temp{ + SignRecord: r, + Detail: detail, + } + } + + return helper.PrintJSON(output) + } else { + // output in table format + w := helper.NewTabWriter(cctx.App.Writer) + fmt.Fprintln(w, "SIGNER\tTYPE\tTIME\tERROR") + for _, r := range records { + errStr := "no error" + if r.Err != nil { + errStr = r.Err.Error() + } + fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", r.Signer, r.Type, r.CreateAt, errStr) + } + w.Flush() + } + + return nil + }, +} + +func GetDetailInJsonRawMessage(r *types.SignRecord) (json.RawMessage, error) { + t, ok := wallet.SupportedMsgTypes[r.Type] + if !ok { + return nil, fmt.Errorf("unsupported type %s", r.Type) + } + + wrap := func(err error) error { + return fmt.Errorf("get detail: %w", err) + } + + if r.RawMsg == nil { + return nil, wrap(fmt.Errorf("msg is nil")) + } + + if r.Type == types.MTVerifyAddress || r.Type == types.MTUnknown { + // encode into hex string + output := struct { + Hex string + }{ + Hex: hex.EncodeToString(r.RawMsg), + } + + return json.Marshal(output) + } + + signObj := reflect.New(t.Type).Interface() + if err := wallet.CborDecodeInto(r.RawMsg, signObj); err != nil { + return nil, fmt.Errorf("decode msg:%w", err) + } + return json.Marshal(signObj) + +} diff --git a/common/api_common.go b/common/api_common.go index 45cfb38..8b4298a 100644 --- a/common/api_common.go +++ b/common/api_common.go @@ -11,6 +11,8 @@ import ( "github.com/gbrlsnchs/jwt/v3" logging "github.com/ipfs/go-log/v2" "go.uber.org/fx" + + "github.com/filecoin-project/venus-wallet/storage" ) type ICommon = api.ICommon @@ -20,6 +22,7 @@ var _ ICommon = &Common{} type Common struct { fx.In APISecret *jwt.HMACSHA + Recorder storage.IRecorder } type jwtPayload struct { @@ -55,3 +58,7 @@ func (a *Common) LogList(context.Context) ([]string, error) { func (a *Common) LogSetLevel(ctx context.Context, subsystem, level string) error { return logging.SetLogLevel(subsystem, level) } + +func (a *Common) ListSignedRecord(ctx context.Context, param *types.QuerySignRecordParams) ([]types.SignRecord, error) { + return a.Recorder.QueryRecord(param) +} diff --git a/common/api_common_test.go b/common/api_common_test.go index 25975ff..e0e80aa 100644 --- a/common/api_common_test.go +++ b/common/api_common_test.go @@ -9,6 +9,7 @@ import ( "github.com/filecoin-project/go-jsonrpc/auth" "github.com/filecoin-project/venus-wallet/filemgr" + "github.com/filecoin-project/venus-wallet/storage" "github.com/gbrlsnchs/jwt/v3" "github.com/stretchr/testify/require" "go.uber.org/fx" @@ -27,6 +28,7 @@ func TestCommon_AuthVerify(t *testing.T) { app := fxtest.New(t, fx.Provide(func() *jwt.HMACSHA { return jwt.NewHS256(sec) }), + fx.Provide(func() storage.IRecorder { return nil }), fx.Populate(&c), ) defer app.RequireStart().RequireStop() diff --git a/filemgr/config_manager.go b/filemgr/config_manager.go index 431e27d..dd2d043 100644 --- a/filemgr/config_manager.go +++ b/filemgr/config_manager.go @@ -18,7 +18,7 @@ func (fsr *FsRepo) defConfig() *config.Config { ListenAddress: "/ip4/127.0.0.1/tcp/5678/http", }, DB: &config.DBConfig{ - Conn: filepath.Join(fsr.path, skKeyStore), + Conn: filepath.Join(fsr.path, dbName), Type: "sqlite", DebugMode: true, }, diff --git a/filemgr/default.go b/filemgr/default.go index 7bf63b3..0fbe90e 100644 --- a/filemgr/default.go +++ b/filemgr/default.go @@ -3,6 +3,6 @@ package filemgr type systemKeyword = string const ( - skConfig systemKeyword = "config.toml" - skKeyStore systemKeyword = "keystore.sqlit" + skConfig systemKeyword = "config.toml" + dbName systemKeyword = "keystore.sqlit" ) diff --git a/filemgr/fs.go b/filemgr/fs.go index 7053f2b..31a4c27 100644 --- a/filemgr/fs.go +++ b/filemgr/fs.go @@ -83,12 +83,12 @@ func (fsr *FsRepo) init() error { } func (fsr *FsRepo) exists() (bool, error) { - _, err := os.Stat(filepath.Join(fsr.path, skKeyStore)) - notexist := os.IsNotExist(err) - if notexist { + _, err := os.Stat(filepath.Join(fsr.path, dbName)) + notExist := os.IsNotExist(err) + if notExist { err = nil } - return !notexist, err + return !notExist, err } func (fsr *FsRepo) Config() *config.Config { diff --git a/go.mod b/go.mod index 8323d6b..ee91ec7 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( contrib.go.opencensus.io/exporter/jaeger v0.2.1 - github.com/BurntSushi/toml v1.2.0 + github.com/BurntSushi/toml v1.2.1 github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef github.com/filecoin-project/go-address v1.1.0 github.com/filecoin-project/go-cbor-util v0.0.1 @@ -13,7 +13,7 @@ require ( github.com/filecoin-project/go-jsonrpc v0.1.5 github.com/filecoin-project/go-state-types v0.10.0-rc3 github.com/filecoin-project/specs-actors/v2 v2.3.6 - github.com/filecoin-project/venus v1.10.0-rc2 + github.com/filecoin-project/venus v1.10.0-rc2.0.20230224083402-a219433346fd github.com/fsnotify/fsnotify v1.5.4 github.com/gbrlsnchs/jwt/v3 v3.0.1 github.com/google/uuid v1.3.0 @@ -27,7 +27,7 @@ require ( github.com/spf13/viper v1.12.0 github.com/stretchr/testify v1.8.1 github.com/supranational/blst v0.3.4 - github.com/urfave/cli/v2 v2.16.3 + github.com/urfave/cli/v2 v2.24.0 go.opencensus.io v0.23.0 go.uber.org/fx v1.15.0 golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 @@ -37,6 +37,12 @@ require ( gotest.tools v2.2.0+incompatible ) +require ( + github.com/golang/glog v1.0.0 // indirect + github.com/xlab/c-for-go v0.0.0-20201112171043-ea6dce5809cb // indirect + modernc.org/golex v1.0.1 // indirect +) + require ( contrib.go.opencensus.io/exporter/graphite v0.0.0-20200424223504-26b90655e0ce // indirect contrib.go.opencensus.io/exporter/prometheus v0.4.0 // indirect @@ -51,8 +57,8 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/deepmap/oapi-codegen v1.3.13 // indirect github.com/dgraph-io/badger/v2 v2.2007.3 // indirect - github.com/dgraph-io/badger/v3 v3.2011.1 // indirect - github.com/dgraph-io/ristretto v0.0.4-0.20210122082011-bb5d392ed82d // indirect + github.com/dgraph-io/badger/v3 v3.2103.0 // indirect + github.com/dgraph-io/ristretto v0.1.0 // indirect github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect github.com/dustin/go-humanize v1.0.0 // indirect github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20201006184820-924ee87a1349 // indirect diff --git a/go.sum b/go.sum index e61cdcf..76f8385 100644 --- a/go.sum +++ b/go.sum @@ -74,8 +74,8 @@ github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOv github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0= -github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= @@ -262,12 +262,15 @@ github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlN github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE= github.com/dgraph-io/badger/v2 v2.2007.3 h1:Sl9tQWz92WCbVSe8pj04Tkqlm2boW+KAxd+XSs58SQI= github.com/dgraph-io/badger/v2 v2.2007.3/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= -github.com/dgraph-io/badger/v3 v3.2011.1 h1:Hmyof0WMEF/QtutX5SQHzIMnJQxb/IrSzhjckV2SD6g= github.com/dgraph-io/badger/v3 v3.2011.1/go.mod h1:0rLLrQpKVQAL0or/lBLMQznhr6dWWX7h5AKnmnqx268= +github.com/dgraph-io/badger/v3 v3.2103.0 h1:abkD2EnP3+6Tj8h5LI1y00dJ9ICKTIAzvG9WmZ8S2c4= +github.com/dgraph-io/badger/v3 v3.2103.0/go.mod h1:GHMCYxuDWyzbHkh4k3yyg4PM61tJPFfEGSMbE3Vd5QE= github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgraph-io/ristretto v0.0.4-0.20210122082011-bb5d392ed82d h1:eQYOG6A4td1tht0NdJB9Ls6DsXRGb2Ft6X9REU/MbbE= github.com/dgraph-io/ristretto v0.0.4-0.20210122082011-bb5d392ed82d/go.mod h1:tv2ec8nA7vRpSYX7/MbP52ihrUMXIHit54CQMq8npXQ= +github.com/dgraph-io/ristretto v0.0.4-0.20210309073149-3836124cdc5a/go.mod h1:MIonLggsKgZLUSt414ExgwNtlOL5MuEoAJP514mwGe8= +github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= +github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= @@ -429,8 +432,8 @@ github.com/filecoin-project/storetheindex v0.3.5/go.mod h1:0r3d0kSpK63O6AvLr1CjA github.com/filecoin-project/storetheindex v0.4.30-0.20221114113647-683091f8e893 h1:6GCuzxLVHBzlz7y+FkbHh6n0UyoEGWqDwJKQPJoz7bE= github.com/filecoin-project/test-vectors/schema v0.0.5/go.mod h1:iQ9QXLpYWL3m7warwvK1JC/pTri8mnfEmKygNDqqY6E= github.com/filecoin-project/venus v1.2.4/go.mod h1:hJULXHGAnWuq5S5KRtPkwbT8DqgM9II7NwyNU7t59D0= -github.com/filecoin-project/venus v1.10.0-rc2 h1:bSPtGuLnLFTALFdHuHRpo9bkN4bnZ/2RlpNyiKC68Fs= -github.com/filecoin-project/venus v1.10.0-rc2/go.mod h1:khIm31fH1i/2q1aLBgRo5ULB+LbSKiNsKfwQORKD+PY= +github.com/filecoin-project/venus v1.10.0-rc2.0.20230224083402-a219433346fd h1:eEffqweopCwulfsEoLBcMgySaSXax3N/dfCMVvuo2gI= +github.com/filecoin-project/venus v1.10.0-rc2.0.20230224083402-a219433346fd/go.mod h1:ejOZiBnEC+0qFY9Xp7PjVV8HUqXLJfpXlBPaOtlhds0= github.com/filecoin-project/venus-auth v1.3.2/go.mod h1:m5Jog2GYxztwP7w3m/iJdv/V1/bTcAVU9rm/CbhxRQU= github.com/filecoin-project/venus-auth v1.10.0-rc2 h1:mC2kRcUmXaL2nPky8iiogFjrygMTUXGXHjvEV9msPgk= github.com/filecoin-project/venus-auth v1.10.0-rc2/go.mod h1:bJT0owiiQfQq7u8QBpIf22JHNRZdsx9rAr4wMEsg+ds= @@ -546,6 +549,8 @@ github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -1973,8 +1978,8 @@ github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= -github.com/urfave/cli/v2 v2.16.3 h1:gHoFIwpPjoyIMbJp/VFd+/vuD0dAgFK4B6DpEMFJfQk= -github.com/urfave/cli/v2 v2.16.3/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= +github.com/urfave/cli/v2 v2.24.0 h1:GneGgpg7Ysp03BpliEWGIkbQqQwVmT6T13SiSwQSBWE= +github.com/urfave/cli/v2 v2.24.0/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= @@ -2031,8 +2036,9 @@ github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7V github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xlab/c-for-go v0.0.0-20200718154222-87b0065af829 h1:wb7xrDzfkLgPHsSEBm+VSx6aDdi64VtV0xvP0E6j8bk= github.com/xlab/c-for-go v0.0.0-20200718154222-87b0065af829/go.mod h1:h/1PEBwj7Ym/8kOuMWvO2ujZ6Lt+TMbySEXNhjjR87I= +github.com/xlab/c-for-go v0.0.0-20201112171043-ea6dce5809cb h1:/7/dQyiKnxAOj9L69FhST7uMe17U015XPzX7cy+5ykM= +github.com/xlab/c-for-go v0.0.0-20201112171043-ea6dce5809cb/go.mod h1:pbNsDSxn1ICiNn9Ct4ZGNrwzfkkwYbx/lw8VuyutFIg= github.com/xlab/pkgconfig v0.0.0-20170226114623-cea12a0fd245 h1:Sw125DKxZhPUI4JLlWugkzsrlB50jR9v2khiD9FxuSo= github.com/xlab/pkgconfig v0.0.0-20170226114623-cea12a0fd245/go.mod h1:C+diUUz7pxhNY6KAoLgrTYARGWnt82zWTylZlxT92vk= github.com/xorcare/golden v0.6.0/go.mod h1:7T39/ZMvaSEZlBPoYfVFmsBLmUl3uz9IuzWj/U6FtvQ= @@ -2191,6 +2197,7 @@ golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5 golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -2855,8 +2862,12 @@ lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= modernc.org/cc v1.0.0 h1:nPibNuDEx6tvYrUAtvDTTw98rx5juGsa5zuDnKwEEQQ= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= -modernc.org/golex v1.0.0 h1:wWpDlbK8ejRfSyi0frMyhilD3JBvtcx2AdGDnU+JtsE= +modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/golex v1.0.1 h1:EYKY1a3wStt0RzHaH8mdSRNg78Ub0OHxYfCRWw35YtM= +modernc.org/golex v1.0.1/go.mod h1:QCA53QtsT1NdGkaZZkF5ezFwk4IXh4BGNafAARTC254= +modernc.org/lex v1.0.0/go.mod h1:G6rxMTy3cH2iA0iXL/HRRv4Znu8MK4higxph/lE7ypk= +modernc.org/lexer v1.0.0/go.mod h1:F/Dld0YKYdZCLQ7bD0USbWL4YKCyTDRDHiDTOs0q0vk= modernc.org/mathutil v1.1.1 h1:FeylZSVX8S+58VsyJlkEj2bcpdytmp9MmDKZkKx8OIE= modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/strutil v1.1.0 h1:+1/yCzZxY2pZwwrsbH+4T7BQMoLQ9QiBshRC9eicYsc= diff --git a/storage/sqlite/conn.go b/storage/sqlite/conn.go index 63cc5c4..aa56669 100644 --- a/storage/sqlite/conn.go +++ b/storage/sqlite/conn.go @@ -9,18 +9,13 @@ import ( "gorm.io/gorm" ) -// for sqlite use a single file socket -type Conn struct { - DB *gorm.DB -} - type TableName = string const ( TBWallet TableName = "wallets" ) -func NewSQLiteConn(cfg *config.DBConfig) (*Conn, error) { +func NewDB(cfg *config.DBConfig) (*gorm.DB, error) { db, err := gorm.Open(sqlite.Open(cfg.Conn), &gorm.Config{}) var sqldb *sql.DB if err != nil { @@ -41,5 +36,5 @@ func NewSQLiteConn(cfg *config.DBConfig) (*Conn, error) { } } - return &Conn{DB: db}, nil + return db, nil } diff --git a/storage/sqlite/key_store.go b/storage/sqlite/key_store.go index d1afe60..d58c5ba 100644 --- a/storage/sqlite/key_store.go +++ b/storage/sqlite/key_store.go @@ -11,7 +11,7 @@ import ( "gorm.io/gorm" ) -var ksLog = logging.Logger("main") +var ksLog = logging.Logger("key_store") // keystore sqlite implementation type sqliteStorage struct { @@ -19,8 +19,8 @@ type sqliteStorage struct { walletTB string } -func NewKeyStore(conn *Conn) storage.KeyStore { - store := &sqliteStorage{db: conn.DB, walletTB: TBWallet} +func NewKeyStore(db *gorm.DB) storage.KeyStore { + store := &sqliteStorage{db: db, walletTB: TBWallet} _ = store.migrateCompatibleAddress() return store } diff --git a/storage/sqlite/key_store_test.go b/storage/sqlite/key_store_test.go index ff23a1e..6a82ad4 100644 --- a/storage/sqlite/key_store_test.go +++ b/storage/sqlite/key_store_test.go @@ -20,7 +20,7 @@ import ( ) func setup(t *testing.T) storage.KeyStore { - conn, err := NewSQLiteConn(&config.DBConfig{ + conn, err := NewDB(&config.DBConfig{ Conn: "file::memory:", }) assert.NoError(t, err) diff --git a/storage/sqlite/sign_record.go b/storage/sqlite/sign_record.go new file mode 100644 index 0000000..5164f8e --- /dev/null +++ b/storage/sqlite/sign_record.go @@ -0,0 +1,140 @@ +package sqlite + +import ( + "fmt" + "time" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/venus-wallet/storage" + "github.com/filecoin-project/venus/venus-shared/types" + logging "github.com/ipfs/go-log/v2" + "gorm.io/gorm" +) + +const MTUndefined types.MsgType = "" + +var log = logging.Logger("recorder") + +type sqliteSignRecord struct { + ID string `gorm:"primaryKey;type:varchar(256);index;not null"` + CreatedAt time.Time `gorm:"index"` + Type types.MsgType `gorm:"index"` + Signer string `gorm:"type:varchar(256);index;not null"` + Err string `gorm:"type:varchar(256);default:null"` + RawMsg []byte `gorm:"type:blob;default:null"` + Signature *crypto.Signature `gorm:"embedded;embeddedPrefix:signature_"` +} + +func (s *sqliteSignRecord) TableName() string { + return "sign_record" +} + +func newFromSignRecord(record *storage.SignRecord) *sqliteSignRecord { + ret := &sqliteSignRecord{ + ID: record.ID, + CreatedAt: record.CreateAt, + Type: record.Type, + Signer: record.Signer.String(), + RawMsg: record.RawMsg, + Signature: record.Signature, + } + if record.Err != nil { + ret.Err = record.Err.Error() + } + return ret +} + +func (s *sqliteSignRecord) toSignRecord() *storage.SignRecord { + ret := &storage.SignRecord{ + ID: s.ID, + CreateAt: s.CreatedAt, + Type: s.Type, + Signer: MustParseAddress(s.Signer), + Err: fmt.Errorf(s.Err), + RawMsg: s.RawMsg, + Signature: s.Signature, + } + if s.Err == "" { + ret.Err = nil + } + return ret +} + +type SqliteRecorder struct { + db *gorm.DB +} + +func NewSqliteRecorder(db *gorm.DB) (storage.IRecorder, error) { + err := db.AutoMigrate(&sqliteSignRecord{}) + if err != nil { + return nil, fmt.Errorf("init sqlite_recorder: %w", err) + } + + go func() { + ticker := time.NewTicker(time.Hour) + for { + <-ticker.C + err := db.Where("created_at < ?", time.Now().Add(-time.Hour*24*7)).Delete(&sqliteSignRecord{}).Error + if err != nil { + log.Errorf("clean sqlite recorder: %s", err) + } + } + }() + + return &SqliteRecorder{db: db}, nil +} + +func (s *SqliteRecorder) Record(record *storage.SignRecord) error { + return s.db.Create(newFromSignRecord(record)).Error +} + +func (s *SqliteRecorder) QueryRecord(params *storage.QueryParams) ([]storage.SignRecord, error) { + var records []*sqliteSignRecord + query := s.db + + if params.ID != "" { + query = query.Where("id = ?", params.ID) + } else { + if params.Signer != address.Undef { + query = query.Where("signer = ?", params.Signer.String()) + } + if !params.After.IsZero() { + query = query.Where("created_at >= ?", params.After) + } + if !params.Before.IsZero() { + query = query.Where("created_at <= ?", params.Before) + } + if params.IsError { + query = query.Where("err is not null") + } + if params.Type != MTUndefined { + query = query.Where("type = ?", params.Type) + } + if params.Skip > 0 { + query = query.Offset(params.Skip) + } + if params.Limit > 0 { + query = query.Limit(params.Limit) + } + } + + err := query.Order("created_at desc").Find(&records).Error + if err != nil { + return nil, err + } + + ret := make([]storage.SignRecord, 0, len(records)) + for _, r := range records { + ret = append(ret, *r.toSignRecord()) + } + return ret, nil +} + +func MustParseAddress(addr string) address.Address { + a, err := address.NewFromString(addr) + if err != nil { + panic(err) + } + return a +} diff --git a/storage/sqlite/sign_record_test.go b/storage/sqlite/sign_record_test.go new file mode 100644 index 0000000..a4349a6 --- /dev/null +++ b/storage/sqlite/sign_record_test.go @@ -0,0 +1,33 @@ +package sqlite + +import ( + "fmt" + "testing" + "time" + + "github.com/filecoin-project/venus/venus-shared/types" + "github.com/stretchr/testify/assert" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +func TestSingRecord(t *testing.T) { + db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{}) + assert.NoError(t, err) + + // Migrate the schema + s, err := NewSqliteRecorder(db) + assert.NoError(t, err) + + err = s.Record(&types.SignRecord{ + RawMsg: []byte("hello"), + Err: fmt.Errorf("error"), + Type: types.MTVerifyAddress, + CreateAt: time.Now(), + }) + assert.NoError(t, err) + res, err := s.QueryRecord(&types.QuerySignRecordParams{}) + assert.NoError(t, err) + assert.Equal(t, 1, len(res)) + +} diff --git a/storage/keystore.go b/storage/store.go similarity index 75% rename from storage/keystore.go rename to storage/store.go index 16956a4..84d9649 100644 --- a/storage/keystore.go +++ b/storage/store.go @@ -5,6 +5,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/venus-wallet/crypto/aes" + "github.com/filecoin-project/venus/venus-shared/types" ) var ( @@ -26,3 +27,12 @@ type KeyStore interface { // Delete removes a key from keystore Delete(addr address.Address) error } + +type QueryParams = types.QuerySignRecordParams + +type SignRecord = types.SignRecord + +type IRecorder interface { + Record(rcd *SignRecord) error + QueryRecord(params *QueryParams) ([]SignRecord, error) +} diff --git a/storage/wallet/sign_type.go b/storage/wallet/sign_type.go index 7350314..5124789 100644 --- a/storage/wallet/sign_type.go +++ b/storage/wallet/sign_type.go @@ -2,6 +2,7 @@ package wallet import ( "bytes" + "errors" "fmt" "reflect" @@ -21,15 +22,25 @@ import ( // Types Abstract data types to be signed type Types struct { Type reflect.Type - signBytes FGetSignBytes - parseObj FParseObj + SignBytes FGetSignBytes + ParseObj FParseObj } type ( - FGetSignBytes func(in interface{}) ([]byte, error) - FParseObj func([]byte, types.MsgMeta) (interface{}, error) + FGetSignBytes func(signObj interface{}) ([]byte, error) + FParseObj func(toSign []byte, meta types.MsgMeta) (interface{}, error) ) +var defaultPaseObjFunc = func(t reflect.Type) FParseObj { + return func(b []byte, meta types.MsgMeta) (interface{}, error) { + obj := reflect.New(t).Interface() + if err := CborDecodeInto(b, obj); err != nil { + return nil, err + } + return obj, nil + } +} + func RegisterSupportedMsgTypes(msgType types.MsgType, p reflect.Type, fGetSignBytes FGetSignBytes, fParseObj FParseObj, ) (replaced bool) { @@ -40,74 +51,125 @@ func RegisterSupportedMsgTypes(msgType types.MsgType, p reflect.Type, // SupportedMsgTypes signature type factory var SupportedMsgTypes = map[types.MsgType]*Types{ - types.MTDealProposal: {reflect.TypeOf(market.DealProposal{}), func(i interface{}) ([]byte, error) { - return cborutil.Dump(i) - }, nil}, - types.MTClientDeal: {reflect.TypeOf(market.ClientDealProposal{}), func(in interface{}) ([]byte, error) { - ni, err := cborutil.AsIpld(in) - if err != nil { - return nil, err - } - return ni.Cid().Bytes(), nil - }, nil}, - types.MTDrawRandomParam: {reflect.TypeOf(types2.DrawRandomParams{}), func(in interface{}) ([]byte, error) { - param := in.(*types2.DrawRandomParams) - return param.SignBytes() - }, nil}, - types.MTSignedVoucher: {reflect.TypeOf(paych.SignedVoucher{}), func(in interface{}) ([]byte, error) { - return (in.(*paych.SignedVoucher)).SigningBytes() - }, nil}, - types.MTStorageAsk: {reflect.TypeOf(storagemarket.StorageAsk{}), func(in interface{}) ([]byte, error) { - return cborutil.Dump(in) - }, nil}, - types.MTAskResponse: {Type: reflect.TypeOf(network.AskResponse{}), signBytes: func(in interface{}) ([]byte, error) { - newAsk := in.(*network.AskResponse).Ask.Ask - oldAsk := &migrations.StorageAsk0{ - Price: newAsk.Price, VerifiedPrice: newAsk.VerifiedPrice, MinPieceSize: newAsk.MinPieceSize, - MaxPieceSize: newAsk.MaxPieceSize, Miner: newAsk.Miner, Timestamp: newAsk.Timestamp, Expiry: newAsk.Expiry, SeqNo: newAsk.SeqNo, - } - return cborutil.Dump(oldAsk) - }}, - types.MTNetWorkResponse: {reflect.TypeOf(network.Response{}), func(in interface{}) ([]byte, error) { - return cborutil.Dump(in) - }, nil}, + types.MTDealProposal: { + Type: reflect.TypeOf(market.DealProposal{}), + SignBytes: func(i interface{}) ([]byte, error) { + return cborutil.Dump(i) + }, + ParseObj: defaultPaseObjFunc(reflect.TypeOf(market.DealProposal{})), + }, + types.MTClientDeal: { + Type: reflect.TypeOf(market.ClientDealProposal{}), + SignBytes: func(in interface{}) ([]byte, error) { + ni, err := cborutil.AsIpld(in) + if err != nil { + return nil, err + } + return ni.Cid().Bytes(), nil + }, + ParseObj: defaultPaseObjFunc(reflect.TypeOf(market.ClientDealProposal{})), + }, + types.MTDrawRandomParam: { + Type: reflect.TypeOf(types2.DrawRandomParams{}), + SignBytes: func(in interface{}) ([]byte, error) { + param := in.(*types2.DrawRandomParams) + return param.SignBytes() + }, + ParseObj: defaultPaseObjFunc(reflect.TypeOf(types2.DrawRandomParams{})), + }, + types.MTSignedVoucher: { + Type: reflect.TypeOf(paych.SignedVoucher{}), + SignBytes: func(in interface{}) ([]byte, error) { + return (in.(*paych.SignedVoucher)).SigningBytes() + }, + ParseObj: defaultPaseObjFunc(reflect.TypeOf(paych.SignedVoucher{})), + }, + types.MTStorageAsk: { + Type: reflect.TypeOf(storagemarket.StorageAsk{}), + SignBytes: func(in interface{}) ([]byte, error) { + return cborutil.Dump(in) + }, + ParseObj: defaultPaseObjFunc(reflect.TypeOf(storagemarket.StorageAsk{})), + }, + types.MTAskResponse: { + Type: reflect.TypeOf(network.AskResponse{}), + SignBytes: func(in interface{}) ([]byte, error) { + newAsk := in.(*network.AskResponse).Ask.Ask + oldAsk := &migrations.StorageAsk0{ + Price: newAsk.Price, VerifiedPrice: newAsk.VerifiedPrice, MinPieceSize: newAsk.MinPieceSize, + MaxPieceSize: newAsk.MaxPieceSize, Miner: newAsk.Miner, Timestamp: newAsk.Timestamp, Expiry: newAsk.Expiry, SeqNo: newAsk.SeqNo, + } + return cborutil.Dump(oldAsk) + }, + ParseObj: defaultPaseObjFunc(reflect.TypeOf(network.AskResponse{})), + }, + types.MTNetWorkResponse: { + Type: reflect.TypeOf(network.Response{}), + SignBytes: func(in interface{}) ([]byte, error) { + return cborutil.Dump(in) + }, + ParseObj: defaultPaseObjFunc(reflect.TypeOf(network.Response{})), + }, + + types.MTBlock: { + Type: reflect.TypeOf(types.BlockHeader{}), + SignBytes: func(in interface{}) ([]byte, error) { + return in.(*types.BlockHeader).SignatureData() + }, + ParseObj: defaultPaseObjFunc(reflect.TypeOf(types.BlockHeader{})), + }, + types.MTChainMsg: { + Type: reflect.TypeOf(types.Message{}), + SignBytes: func(in interface{}) ([]byte, error) { + msg := in.(*types.Message) + return msg.Cid().Bytes(), nil + }, + ParseObj: func(in []byte, meta types.MsgMeta) (interface{}, error) { + if len(meta.Extra) == 0 { + return nil, errors.New("msg type must contain extra data") + } + msg, err := types.DecodeMessage(meta.Extra) + if err != nil { + return nil, err + } - types.MTBlock: {reflect.TypeOf(types.BlockHeader{}), func(in interface{}) ([]byte, error) { - return in.(*types.BlockHeader).SignatureData() - }, nil}, - types.MTChainMsg: {reflect.TypeOf(types.Message{}), func(in interface{}) ([]byte, error) { - msg := in.(*types.Message) - return msg.Cid().Bytes(), nil - }, nil}, + return msg, nil + }, + }, types.MTProviderDealState: { - reflect.TypeOf(storagemarket.ProviderDealState{}), func(in interface{}) ([]byte, error) { + Type: reflect.TypeOf(storagemarket.ProviderDealState{}), + SignBytes: func(in interface{}) ([]byte, error) { return cborutil.Dump(in) - }, nil, + }, + ParseObj: defaultPaseObjFunc(reflect.TypeOf(storagemarket.ProviderDealState{})), }, // chain/gen/gen.go:659, // in method 'ComputeVRF' sign bytes with MsgType='MTUnknown' // so, must deal 'MTUnknown' MsgType, and this may case safe problem - types.MTUnknown: {reflect.TypeOf([]byte{}), func(in interface{}) ([]byte, error) { - msg, isok := in.([]byte) - if !isok { - return nil, fmt.Errorf("MTUnkown must be []byte") - } - return msg, nil - }, func(in []byte, meta types.MsgMeta) (interface{}, error) { - if meta.Type == types.MTUnknown { - return in, nil - } - return nil, fmt.Errorf("un-expected MsgType:%s", meta.Type) - }}, + types.MTUnknown: { + Type: reflect.TypeOf([]byte{}), + SignBytes: func(in interface{}) ([]byte, error) { + msg, isOk := in.([]byte) + if !isOk { + return nil, fmt.Errorf("MTUnknown must be []byte") + } + return msg, nil + }, + ParseObj: func(in []byte, meta types.MsgMeta) (interface{}, error) { + if meta.Type == types.MTUnknown { + return in, nil + } + return nil, fmt.Errorf("un-expected MsgType:%s", meta.Type) + }}, // the data to sign is divide into 2 parts: // first part: is from venus-gateway, which here should be `meta.Extra` // second part: is from venus-wallet, which here is `wallet_event.RandomBytes` types.MTVerifyAddress: { Type: reflect.TypeOf([]byte{}), - signBytes: func(in interface{}) ([]byte, error) { + SignBytes: func(in interface{}) ([]byte, error) { return in.([]byte), nil }, - parseObj: func(in []byte, meta types.MsgMeta) (interface{}, error) { + ParseObj: func(in []byte, meta types.MsgMeta) (interface{}, error) { expected := walletevent.GetSignData(meta.Extra, walletevent.RandomBytes) if !bytes.Equal(in, expected) { return nil, fmt.Errorf("sign data not match, actual %v, expected %v", in, expected) @@ -117,29 +179,30 @@ var SupportedMsgTypes = map[types.MsgType]*Types{ }, } -// GetSignBytes Matches the type and returns the data that needs to be signed -func GetSignBytes(toSign []byte, meta types.MsgMeta) (interface{}, []byte, error) { +// GetSignBytesAndObj Matches the type and returns the data that needs to be signed +func GetSignBytesAndObj(toSign []byte, meta types.MsgMeta) (interface{}, []byte, error) { t := SupportedMsgTypes[meta.Type] if t == nil { return nil, nil, fmt.Errorf("unsupported msgtype:%s", meta.Type) } var in interface{} var err error - if t.parseObj != nil { - if in, err = t.parseObj(toSign, meta); err != nil { - return nil, nil, fmt.Errorf("parseObj failed:%w", err) - } - } else { // treat as cbor unmarshal-able object by default - in = reflect.New(t.Type).Interface() - unmarshaler, isok := in.(cbor.Unmarshaler) - if !isok { - return nil, nil, fmt.Errorf("type:%s is is not an 'unmarhsaler'", t.Type.Name()) - } - if err := unmarshaler.UnmarshalCBOR(bytes.NewReader(toSign)); err != nil { - return nil, nil, fmt.Errorf("cborunmarshal to %s failed:%w", t.Type.Name(), err) - } + if in, err = t.ParseObj(toSign, meta); err != nil { + return nil, nil, fmt.Errorf("parseObj failed:%w", err) } + var data []byte - data, err = t.signBytes(in) + data, err = t.SignBytes(in) return in, data, err } + +func CborDecodeInto(r []byte, v interface{}) error { + unmarshaler, isOk := v.(cbor.Unmarshaler) + if !isOk { + return fmt.Errorf("not an 'unmarhsaler'") + } + if err := unmarshaler.UnmarshalCBOR(bytes.NewReader(r)); err != nil { + return fmt.Errorf("cbor unmarshal:%w", err) + } + return nil +} diff --git a/storage/wallet/wallet.go b/storage/wallet/wallet.go index e57e601..53b308a 100644 --- a/storage/wallet/wallet.go +++ b/storage/wallet/wallet.go @@ -2,11 +2,12 @@ package wallet import ( "context" - "errors" "fmt" "sync" "github.com/filecoin-project/go-address" + cborutil "github.com/filecoin-project/go-cbor-util" + "github.com/google/uuid" "github.com/asaskevich/EventBus" wallet_api "github.com/filecoin-project/venus/venus-shared/api/wallet" @@ -33,11 +34,13 @@ type wallet struct { bus EventBus.Bus filter ISignMsgFilter m sync.RWMutex + recorder storage.IRecorder } -func NewWallet(ks storage.KeyStore, mw storage.KeyMiddleware, filter ISignMsgFilter, bus EventBus.Bus, getPwd GetPwdFunc) wallet_api.ILocalWallet { +func NewWallet(ks storage.KeyStore, rd storage.IRecorder, mw storage.KeyMiddleware, filter ISignMsgFilter, bus EventBus.Bus, getPwd GetPwdFunc) wallet_api.ILocalWallet { w := &wallet{ ws: ks, + recorder: rd, mw: mw, bus: bus, filter: filter, @@ -137,52 +140,26 @@ func (w *wallet) WalletList(ctx context.Context) ([]address.Address, error) { return addrs, nil } -func (w *wallet) WalletSign(ctx context.Context, signer address.Address, toSign []byte, meta types.MsgMeta) (*c.Signature, error) { +func (w *wallet) WalletSign(ctx context.Context, signer address.Address, data []byte, meta types.MsgMeta) (*c.Signature, error) { if err := w.mw.Next(); err != nil { return nil, err } - var ( - owner address.Address - data []byte - ) - // Do not validate strategy - if meta.Type == types.MTVerifyAddress { - _, toSign, err := GetSignBytes(toSign, meta) - if err != nil { - return nil, fmt.Errorf("get sign bytes failed: %v", err) - } - owner = signer - data = toSign - } else if meta.Type == types.MTChainMsg { - if len(meta.Extra) == 0 { - return nil, errors.New("msg type must contain extra data") - } - msg, err := types.DecodeMessage(meta.Extra) - if err != nil { - return nil, err - } - //Check filter - err = w.filter.CheckSignMsg(ctx, SignMsg{ - SignType: types.MTChainMsg, - Data: msg, - }) - if err != nil { - return nil, err - } + // parse msg + signObj, toSign, err := GetSignBytesAndObj(data, meta) + if err != nil { + return nil, fmt.Errorf("get sign bytes: %w", err) + } - owner = msg.From - if signer.String() != owner.String() { - return nil, fmt.Errorf("singe %s does not match from in MSG %s", signer, owner) - } - data = msg.Cid().Bytes() - } else { - signObj, toSign, err := GetSignBytes(toSign, meta) - if err != nil { - return nil, fmt.Errorf("get sign bytes failed: %w", err) + // check owner + if meta.Type == types.MTChainMsg { + if signer != signObj.(*types.Message).From { + return nil, fmt.Errorf("signer(%s) is not msg sender(%s)", signer, signObj.(*types.Message).From) } + } - //Check filter + // check filter + if meta.Type != types.MTVerifyAddress { err = w.filter.CheckSignMsg(ctx, SignMsg{ SignType: meta.Type, Data: signObj, @@ -190,12 +167,12 @@ func (w *wallet) WalletSign(ctx context.Context, signer address.Address, toSign if err != nil { return nil, err } - owner = signer - data = toSign } - prvKey := w.cacheKey(owner) + + // sign + prvKey := w.cacheKey(signer) if prvKey == nil { - key, err := w.ws.Get(owner) + key, err := w.ws.Get(signer) if err != nil { return nil, err } @@ -203,9 +180,30 @@ func (w *wallet) WalletSign(ctx context.Context, signer address.Address, toSign if err != nil { return nil, err } - w.pushCache(owner, prvKey) + w.pushCache(signer, prvKey) } - return prvKey.Sign(data) + signature, signErr := prvKey.Sign(toSign) + + // record + go func() { + msg, err := cborutil.Dump(signObj) + if err != nil { + log.Errorf("dump signObj failed %v", err) + } + + err = w.recorder.Record(&storage.SignRecord{ + ID: uuid.New().String(), + Type: meta.Type, + Signer: signer, + RawMsg: msg, + Err: signErr, + }) + if err != nil { + log.Errorf("record sign failed: %v", err) + } + }() + + return signature, signErr } func (w *wallet) WalletExport(ctx context.Context, addr address.Address) (*types.KeyInfo, error) {