diff --git a/cgo/addresses.go b/cgo/addresses.go index d719869..98c1b67 100644 --- a/cgo/addresses.go +++ b/cgo/addresses.go @@ -18,10 +18,11 @@ func currentReceiveAddress(cName *C.char) *C.char { return errCResponse("wallet with name %q is not loaded", goString(cName)) } - // Don't return an address if not synced! - synced, _ := w.IsSynced(w.ctx) - if !synced { - return errCResponseWithCode(ErrCodeNotSynced, "currentReceiveAddress requested on an unsynced wallet") + if !w.allowUnsyncedAddrs { + synced, _ := w.IsSynced(w.ctx) + if !synced { + return errCResponseWithCode(ErrCodeNotSynced, "currentReceiveAddress requested on an unsynced wallet") + } } addr, err := w.CurrentAddress(udb.DefaultAccountNum) @@ -39,10 +40,11 @@ func newExternalAddress(cName *C.char) *C.char { return errCResponse("wallet with name %q is not loaded", goString(cName)) } - // Don't return an address if not synced! - synced, _ := w.IsSynced(w.ctx) - if !synced { - return errCResponseWithCode(ErrCodeNotSynced, "newExternalAddress requested on an unsynced wallet") + if !w.allowUnsyncedAddrs { + synced, _ := w.IsSynced(w.ctx) + if !synced { + return errCResponseWithCode(ErrCodeNotSynced, "newExternalAddress requested on an unsynced wallet") + } } _, err := w.NewExternalAddress(w.ctx, udb.DefaultAccountNum) @@ -158,9 +160,8 @@ func addresses(cName, cNUsed, cNUnused *C.char) *C.char { Unused: []string{}, Index: index, } - // Avoid returning unused addresses if we are not synced. synced, _ := w.IsSynced(w.ctx) - if synced { + if synced || w.allowUnsyncedAddrs { res.Unused = unused } diff --git a/cgo/transactions.go b/cgo/transactions.go index c075717..d4c2e94 100644 --- a/cgo/transactions.go +++ b/cgo/transactions.go @@ -163,19 +163,26 @@ func listTransactions(cName, cFrom, cCount *C.char) *C.char { if err != nil { return errCResponse("unable to get transactions: %v", err) } + _, blockHeight := w.MainWallet().MainChainTip(w.ctx) ltRes := make([]*ListTransactionRes, len(res)) for i, ltw := range res { // Use earliest of receive time or block time if the transaction is mined. receiveTime := ltw.TimeReceived - if ltw.BlockTime < ltw.TimeReceived { + if ltw.BlockTime != 0 && ltw.BlockTime < ltw.TimeReceived { receiveTime = ltw.BlockTime } + var height int64 + if ltw.Confirmations > 0 { + height = int64(blockHeight) - ltw.Confirmations + 1 + } + lt := &ListTransactionRes{ Address: ltw.Address, Amount: ltw.Amount, Category: ltw.Category, Confirmations: ltw.Confirmations, + Height: height, Fee: ltw.Fee, Time: receiveTime, TxID: ltw.TxID, diff --git a/cgo/types.go b/cgo/types.go index 64bd7c8..bf0218b 100644 --- a/cgo/types.go +++ b/cgo/types.go @@ -134,6 +134,7 @@ type ListTransactionRes struct { Amount float64 `json:"amount"` Category string `json:"category"` Confirmations int64 `json:"confirmations"` + Height int64 `json:"height"` Fee *float64 `json:"fee,omitempty"` Time int64 `json:"time"` TxID string `json:"txid"` @@ -153,3 +154,16 @@ type AddressesRes struct { Unused []string `json:"unused"` Index uint32 `json:"index"` } + +type Config struct { + Name string `json:"name"` + // Allow getting unused addresses when not synced. + AllowUnsyncedAddrs bool `json:"unsyncedaddrs"` + Net string `json:"net"` + DataDir string `json:"datadir"` + // Only needed during creation. + Pass string `json:"pass"` + Mnemonic string `json:"mnemonic"` + // Only needed during watching only creation. + PubKey string `json:"pubkey"` +} diff --git a/cgo/walletloader.go b/cgo/walletloader.go index 3d637d1..1742ee0 100644 --- a/cgo/walletloader.go +++ b/cgo/walletloader.go @@ -25,23 +25,29 @@ type wallet struct { syncStatusMtx sync.RWMutex syncStatusCode SyncStatusCode targetHeight, cfiltersHeight, headersHeight, rescanHeight, numPeers int - rescanning bool + rescanning, allowUnsyncedAddrs bool } //export createWallet -func createWallet(cName, cDataDir, cNet, cPass, cMnemonic *C.char) *C.char { +func createWallet(cConfig *C.char) *C.char { walletsMtx.Lock() defer walletsMtx.Unlock() if !initialized { return errCResponse("libwallet is not initialized") } - name := goString(cName) + configJSON := goString(cConfig) + var cfg Config + if err := json.Unmarshal([]byte(configJSON), &cfg); err != nil { + return errCResponse("malformed config: %v", err) + } + + name := cfg.Name if _, exists := wallets[name]; exists { return errCResponse("wallet already exists with name: %q", name) } - network, err := asset.NetFromString(goString(cNet)) + network, err := asset.NetFromString(cfg.Net) if err != nil { return errCResponse("%v", err) } @@ -51,17 +57,16 @@ func createWallet(cName, cDataDir, cNet, cPass, cMnemonic *C.char) *C.char { params := asset.CreateWalletParams{ OpenWalletParams: asset.OpenWalletParams{ Net: network, - DataDir: goString(cDataDir), + DataDir: cfg.DataDir, DbDriver: "bdb", // use badgerdb for mobile! Logger: logger, }, - Pass: []byte(goString(cPass)), + Pass: []byte(cfg.Pass), } - mnemonicStr := goString(cMnemonic) var recoveryConfig *asset.RecoveryCfg - if mnemonicStr != "" { - seed, birthday, err := mnemonic.DecodeMnemonic(mnemonicStr) + if cfg.Mnemonic != "" { + seed, birthday, err := mnemonic.DecodeMnemonic(cfg.Mnemonic) if err != nil { return errCResponse("unable to decode wallet mnemonic: %v", err) } @@ -70,6 +75,7 @@ func createWallet(cName, cDataDir, cNet, cPass, cMnemonic *C.char) *C.char { Birthday: birthday, } } + walletCtx, cancel := context.WithCancel(mainCtx) w, err := dcr.CreateWallet(walletCtx, params, recoveryConfig) @@ -79,28 +85,35 @@ func createWallet(cName, cDataDir, cNet, cPass, cMnemonic *C.char) *C.char { } wallets[name] = &wallet{ - Wallet: w, - log: logger, - ctx: walletCtx, - cancelCtx: cancel, + Wallet: w, + log: logger, + ctx: walletCtx, + cancelCtx: cancel, + allowUnsyncedAddrs: cfg.AllowUnsyncedAddrs, } return successCResponse("wallet created") } //export createWatchOnlyWallet -func createWatchOnlyWallet(cName, cDataDir, cNet, cPub *C.char) *C.char { +func createWatchOnlyWallet(cConfig *C.char) *C.char { walletsMtx.Lock() defer walletsMtx.Unlock() if !initialized { return errCResponse("libwallet is not initialized") } - name := goString(cName) + configJSON := goString(cConfig) + var cfg Config + if err := json.Unmarshal([]byte(configJSON), &cfg); err != nil { + return errCResponse("malformed config: %v", err) + } + + name := cfg.Name if _, exists := wallets[name]; exists { return errCResponse("wallet already exists with name: %q", name) } - network, err := asset.NetFromString(goString(cNet)) + network, err := asset.NetFromString(cfg.Net) if err != nil { return errCResponse("%v", err) } @@ -110,7 +123,7 @@ func createWatchOnlyWallet(cName, cDataDir, cNet, cPub *C.char) *C.char { params := asset.CreateWalletParams{ OpenWalletParams: asset.OpenWalletParams{ Net: network, - DataDir: goString(cDataDir), + DataDir: cfg.DataDir, DbDriver: "bdb", Logger: logger, }, @@ -118,35 +131,42 @@ func createWatchOnlyWallet(cName, cDataDir, cNet, cPub *C.char) *C.char { walletCtx, cancel := context.WithCancel(mainCtx) - w, err := dcr.CreateWatchOnlyWallet(walletCtx, goString(cPub), params) + w, err := dcr.CreateWatchOnlyWallet(walletCtx, cfg.PubKey, params) if err != nil { cancel() return errCResponse("%v", err) } wallets[name] = &wallet{ - Wallet: w, - log: logger, - ctx: walletCtx, - cancelCtx: cancel, + Wallet: w, + log: logger, + ctx: walletCtx, + cancelCtx: cancel, + allowUnsyncedAddrs: cfg.AllowUnsyncedAddrs, } return successCResponse("wallet created") } //export loadWallet -func loadWallet(cName, cDataDir, cNet *C.char) *C.char { +func loadWallet(cConfig *C.char) *C.char { walletsMtx.Lock() defer walletsMtx.Unlock() if !initialized { return errCResponse("libwallet is not initialized") } - name := goString(cName) + configJSON := goString(cConfig) + var cfg Config + if err := json.Unmarshal([]byte(configJSON), &cfg); err != nil { + return errCResponse("malformed config: %v", err) + } + + name := cfg.Name if _, exists := wallets[name]; exists { return successCResponse("wallet already loaded") // not an error, already loaded } - network, err := asset.NetFromString(goString(cNet)) + network, err := asset.NetFromString(cfg.Net) if err != nil { return errCResponse("%v", err) } @@ -155,7 +175,7 @@ func loadWallet(cName, cDataDir, cNet *C.char) *C.char { logger.SetLevel(slog.LevelTrace) params := asset.OpenWalletParams{ Net: network, - DataDir: goString(cDataDir), + DataDir: cfg.DataDir, DbDriver: "bdb", // use badgerdb for mobile! Logger: logger, } @@ -174,10 +194,11 @@ func loadWallet(cName, cDataDir, cNet *C.char) *C.char { } wallets[name] = &wallet{ - Wallet: w, - log: logger, - ctx: walletCtx, - cancelCtx: cancel, + Wallet: w, + log: logger, + ctx: walletCtx, + cancelCtx: cancel, + allowUnsyncedAddrs: cfg.AllowUnsyncedAddrs, } return successCResponse("wallet %q loaded", name) }