github.com/decred/dcrlnd@v0.7.6/lnrpc/walletrpc/walletkit_server.go (about) 1 //go:build !no_walletrpc 2 // +build !no_walletrpc 3 4 package walletrpc 5 6 import ( 7 "bytes" 8 "context" 9 "errors" 10 "fmt" 11 "io/ioutil" 12 "os" 13 "path/filepath" 14 "time" 15 16 "decred.org/dcrwallet/v4/wallet" 17 "github.com/decred/dcrd/blockchain/standalone/v2" 18 "github.com/decred/dcrd/chaincfg/chainhash" 19 "github.com/decred/dcrd/dcrec" 20 "github.com/decred/dcrd/dcrec/secp256k1/v4" 21 "github.com/decred/dcrd/dcrutil/v4" 22 "github.com/decred/dcrd/hdkeychain/v3" 23 "github.com/decred/dcrd/txscript/v4" 24 "github.com/decred/dcrd/txscript/v4/sign" 25 "github.com/decred/dcrd/txscript/v4/stdaddr" 26 "github.com/decred/dcrd/wire" 27 "github.com/decred/dcrlnd/input" 28 "github.com/decred/dcrlnd/internal/psbt" 29 "github.com/decred/dcrlnd/keychain" 30 "github.com/decred/dcrlnd/labels" 31 "github.com/decred/dcrlnd/lnrpc" 32 "github.com/decred/dcrlnd/lnrpc/signrpc" 33 "github.com/decred/dcrlnd/lnwallet" 34 "github.com/decred/dcrlnd/lnwallet/chainfee" 35 "github.com/decred/dcrlnd/lnwallet/dcrwallet" 36 "github.com/decred/dcrlnd/macaroons" 37 "github.com/decred/dcrlnd/sweep" 38 "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" 39 "google.golang.org/grpc" 40 "gopkg.in/macaroon-bakery.v2/bakery" 41 ) 42 43 const ( 44 // importedAddrsAccountName is the name of the account with imported 45 // scripts/pubkeys. 46 importedAddrsAccountName = "imported" 47 ) 48 49 var ( 50 // macaroonOps are the set of capabilities that our minted macaroon (if 51 // it doesn't already exist) will have. 52 macaroonOps = []bakery.Op{ 53 { 54 Entity: "address", 55 Action: "write", 56 }, 57 { 58 Entity: "address", 59 Action: "read", 60 }, 61 { 62 Entity: "onchain", 63 Action: "write", 64 }, 65 { 66 Entity: "onchain", 67 Action: "read", 68 }, 69 } 70 71 // macPermissions maps RPC calls to the permissions they require. 72 macPermissions = map[string][]bakery.Op{ 73 "/walletrpc.WalletKit/DeriveNextKey": {{ 74 Entity: "address", 75 Action: "read", 76 }}, 77 "/walletrpc.WalletKit/DeriveKey": {{ 78 Entity: "address", 79 Action: "read", 80 }}, 81 "/walletrpc.WalletKit/NextAddr": {{ 82 Entity: "address", 83 Action: "read", 84 }}, 85 "/walletrpc.WalletKit/PublishTransaction": {{ 86 Entity: "onchain", 87 Action: "write", 88 }}, 89 "/walletrpc.WalletKit/SendOutputs": {{ 90 Entity: "onchain", 91 Action: "write", 92 }}, 93 "/walletrpc.WalletKit/EstimateFee": {{ 94 Entity: "onchain", 95 Action: "read", 96 }}, 97 "/walletrpc.WalletKit/PendingSweeps": {{ 98 Entity: "onchain", 99 Action: "read", 100 }}, 101 "/walletrpc.WalletKit/BumpFee": {{ 102 Entity: "onchain", 103 Action: "write", 104 }}, 105 "/walletrpc.WalletKit/ListSweeps": {{ 106 Entity: "onchain", 107 Action: "read", 108 }}, 109 "/walletrpc.WalletKit/DeriveNextAccount": {{ 110 Entity: "onchain", 111 Action: "write", 112 }}, 113 "/walletrpc.WalletKit/ExportPrivateKey": {{ 114 Entity: "onchain", 115 Action: "write", 116 }}, 117 "/walletrpc.WalletKit/RescanWallet": {{ 118 Entity: "onchain", 119 Action: "read", 120 }}, 121 "/walletrpc.WalletKit/SpendUTXOs": {{ 122 Entity: "onchain", 123 Action: "write", 124 }}, 125 "/walletrpc.WalletKit/GetWalletTx": {{ 126 Entity: "onchain", 127 Action: "read", 128 }}, 129 "/walletrpc.WalletKit/LabelTransaction": {{ 130 Entity: "onchain", 131 Action: "write", 132 }}, 133 "/walletrpc.WalletKit/LeaseOutput": {{ 134 Entity: "onchain", 135 Action: "write", 136 }}, 137 "/walletrpc.WalletKit/ReleaseOutput": {{ 138 Entity: "onchain", 139 Action: "write", 140 }}, 141 "/walletrpc.WalletKit/ListLeases": {{ 142 Entity: "onchain", 143 Action: "read", 144 }}, 145 "/walletrpc.WalletKit/ListUnspent": {{ 146 Entity: "onchain", 147 Action: "read", 148 }}, 149 "/walletrpc.WalletKit/FundPsbt": {{ 150 Entity: "onchain", 151 Action: "write", 152 }}, 153 "/walletrpc.WalletKit/SignPsbt": {{ 154 Entity: "onchain", 155 Action: "write", 156 }}, 157 "/walletrpc.WalletKit/FinalizePsbt": {{ 158 Entity: "onchain", 159 Action: "write", 160 }}, 161 "/walletrpc.WalletKit/ListAccounts": {{ 162 Entity: "onchain", 163 Action: "read", 164 }}, 165 "/walletrpc.WalletKit/ImportAccount": {{ 166 Entity: "onchain", 167 Action: "write", 168 }}, 169 "/walletrpc.WalletKit/ImportPublicKey": {{ 170 Entity: "onchain", 171 Action: "write", 172 }}, 173 } 174 175 // DefaultWalletKitMacFilename is the default name of the wallet kit 176 // macaroon that we expect to find via a file handle within the main 177 // configuration file in this package. 178 DefaultWalletKitMacFilename = "walletkit.macaroon" 179 180 // LndInternalLockID is the binary representation of the SHA256 hash of 181 // the string "lnd-internal-lock-id" and is used for UTXO lock leases to 182 // identify that we ourselves are locking an UTXO, for example when 183 // giving out a funded PSBT. The ID corresponds to the hex value of 184 // ede19a92ed321a4705f8a1cccc1d4f6182545d4bb4fae08bd5937831b7e38f98. 185 LndInternalLockID = lnwallet.LockID{ 186 0xed, 0xe1, 0x9a, 0x92, 0xed, 0x32, 0x1a, 0x47, 187 0x05, 0xf8, 0xa1, 0xcc, 0xcc, 0x1d, 0x4f, 0x61, 188 0x82, 0x54, 0x5d, 0x4b, 0xb4, 0xfa, 0xe0, 0x8b, 189 0xd5, 0x93, 0x78, 0x31, 0xb7, 0xe3, 0x8f, 0x98, 190 } 191 ) 192 193 // ErrZeroLabel is returned when an attempt is made to label a transaction with 194 // an empty label. 195 var ErrZeroLabel = errors.New("cannot label transaction with empty label") 196 197 // ServerShell is a shell struct holding a reference to the actual sub-server. 198 // It is used to register the gRPC sub-server with the root server before we 199 // have the necessary dependencies to populate the actual sub-server. 200 type ServerShell struct { 201 WalletKitServer 202 } 203 204 // WalletKit is a sub-RPC server that exposes a tool kit which allows clients 205 // to execute common wallet operations. This includes requesting new addresses, 206 // keys (for contracts!), and publishing transactions. 207 type WalletKit struct { 208 cfg *Config 209 } 210 211 // A compile time check to ensure that WalletKit fully implements the 212 // WalletKitServer gRPC service. 213 var _ WalletKitServer = (*WalletKit)(nil) 214 215 // New creates a new instance of the WalletKit sub-RPC server. 216 func New(cfg *Config) (*WalletKit, lnrpc.MacaroonPerms, error) { 217 // If the path of the wallet kit macaroon wasn't specified, then we'll 218 // assume that it's found at the default network directory. 219 if cfg.WalletKitMacPath == "" { 220 cfg.WalletKitMacPath = filepath.Join( 221 cfg.NetworkDir, DefaultWalletKitMacFilename, 222 ) 223 } 224 225 // Now that we know the full path of the wallet kit macaroon, we can 226 // check to see if we need to create it or not. If stateless_init is set 227 // then we don't write the macaroons. 228 macFilePath := cfg.WalletKitMacPath 229 if cfg.MacService != nil && !cfg.MacService.StatelessInit && 230 !lnrpc.FileExists(macFilePath) { 231 232 log.Infof("Baking macaroons for WalletKit RPC Server at: %v", 233 macFilePath) 234 235 // At this point, we know that the wallet kit macaroon doesn't 236 // yet, exist, so we need to create it with the help of the 237 // main macaroon service. 238 walletKitMac, err := cfg.MacService.NewMacaroon( 239 context.Background(), macaroons.DefaultRootKeyID, 240 macaroonOps..., 241 ) 242 if err != nil { 243 return nil, nil, err 244 } 245 walletKitMacBytes, err := walletKitMac.M().MarshalBinary() 246 if err != nil { 247 return nil, nil, err 248 } 249 err = ioutil.WriteFile(macFilePath, walletKitMacBytes, 0644) 250 if err != nil { 251 _ = os.Remove(macFilePath) 252 return nil, nil, err 253 } 254 } 255 256 walletKit := &WalletKit{ 257 cfg: cfg, 258 } 259 260 return walletKit, macPermissions, nil 261 } 262 263 // Start launches any helper goroutines required for the sub-server to function. 264 // 265 // NOTE: This is part of the lnrpc.SubServer interface. 266 func (w *WalletKit) Start() error { 267 return nil 268 } 269 270 // Stop signals any active goroutines for a graceful closure. 271 // 272 // NOTE: This is part of the lnrpc.SubServer interface. 273 func (w *WalletKit) Stop() error { 274 return nil 275 } 276 277 // Name returns a unique string representation of the sub-server. This can be 278 // used to identify the sub-server and also de-duplicate them. 279 // 280 // NOTE: This is part of the lnrpc.SubServer interface. 281 func (w *WalletKit) Name() string { 282 return SubServerName 283 } 284 285 // RegisterWithRootServer will be called by the root gRPC server to direct a 286 // sub RPC server to register itself with the main gRPC root server. Until this 287 // is called, each sub-server won't be able to have requests routed towards it. 288 // 289 // NOTE: This is part of the lnrpc.GrpcHandler interface. 290 func (r *ServerShell) RegisterWithRootServer(grpcServer *grpc.Server) error { 291 // We make sure that we register it with the main gRPC server to ensure 292 // all our methods are routed properly. 293 RegisterWalletKitServer(grpcServer, r) 294 295 log.Debugf("WalletKit RPC server successfully registered with " + 296 "root gRPC server") 297 298 return nil 299 } 300 301 // RegisterWithRestServer will be called by the root REST mux to direct a sub 302 // RPC server to register itself with the main REST mux server. Until this is 303 // called, each sub-server won't be able to have requests routed towards it. 304 // 305 // NOTE: This is part of the lnrpc.GrpcHandler interface. 306 func (r *ServerShell) RegisterWithRestServer(ctx context.Context, 307 mux *runtime.ServeMux, dest string, opts []grpc.DialOption) error { 308 309 // We make sure that we register it with the main REST server to ensure 310 // all our methods are routed properly. 311 err := RegisterWalletKitHandlerFromEndpoint(ctx, mux, dest, opts) 312 if err != nil { 313 log.Errorf("Could not register WalletKit REST server "+ 314 "with root REST server: %v", err) 315 return err 316 } 317 318 log.Debugf("WalletKit REST server successfully registered with " + 319 "root REST server") 320 return nil 321 } 322 323 // CreateSubServer populates the subserver's dependencies using the passed 324 // SubServerConfigDispatcher. This method should fully initialize the 325 // sub-server instance, making it ready for action. It returns the macaroon 326 // permissions that the sub-server wishes to pass on to the root server for all 327 // methods routed towards it. 328 // 329 // NOTE: This is part of the lnrpc.GrpcHandler interface. 330 func (r *ServerShell) CreateSubServer(configRegistry lnrpc.SubServerConfigDispatcher) ( 331 lnrpc.SubServer, lnrpc.MacaroonPerms, error) { 332 333 subServer, macPermissions, err := createNewSubServer(configRegistry) 334 if err != nil { 335 return nil, nil, err 336 } 337 338 r.WalletKitServer = subServer 339 return subServer, macPermissions, nil 340 } 341 342 // ListUnspent returns useful information about each unspent output owned by the 343 // wallet, as reported by the underlying `ListUnspentWitness`; the information 344 // returned is: outpoint, amount in satoshis, address, address type, 345 // scriptPubKey in hex and number of confirmations. The result is filtered to 346 // contain outputs whose number of confirmations is between a 347 // minimum and maximum number of confirmations specified by the user, with 0 348 // meaning unconfirmed. 349 func (w *WalletKit) ListUnspent(ctx context.Context, 350 req *ListUnspentRequest) (*ListUnspentResponse, error) { 351 352 // Validate the confirmation arguments. 353 minConfs, maxConfs, err := lnrpc.ParseConfs(req.MinConfs, req.MaxConfs) 354 if err != nil { 355 return nil, err 356 } 357 358 // With our arguments validated, we'll query the internal wallet for 359 // the set of UTXOs that match our query. 360 // 361 // We'll acquire the global coin selection lock to ensure there aren't 362 // any other concurrent processes attempting to lock any UTXOs which may 363 // be shown available to us. 364 var utxos []*lnwallet.Utxo 365 err = w.cfg.CoinSelectionLocker.WithCoinSelectLock(func() error { 366 utxos, err = w.cfg.Wallet.ListUnspentWitness( 367 minConfs, maxConfs, req.Account, 368 ) 369 return err 370 }) 371 if err != nil { 372 return nil, err 373 } 374 375 rpcUtxos, err := lnrpc.MarshalUtxos(utxos, w.cfg.ChainParams) 376 if err != nil { 377 return nil, err 378 } 379 380 return &ListUnspentResponse{ 381 Utxos: rpcUtxos, 382 }, nil 383 } 384 385 // LeaseOutput locks an output to the given ID, preventing it from being 386 // available for any future coin selection attempts. The absolute time of the 387 // lock's expiration is returned. The expiration of the lock can be extended by 388 // successive invocations of this call. Outputs can be unlocked before their 389 // expiration through `ReleaseOutput`. 390 // 391 // If the output is not known, wtxmgr.ErrUnknownOutput is returned. If the 392 // output has already been locked to a different ID, then 393 // wtxmgr.ErrOutputAlreadyLocked is returned. 394 func (w *WalletKit) LeaseOutput(ctx context.Context, 395 req *LeaseOutputRequest) (*LeaseOutputResponse, error) { 396 397 if len(req.Id) != 32 { 398 return nil, errors.New("id must be 32 random bytes") 399 } 400 var lockID lnwallet.LockID 401 copy(lockID[:], req.Id) 402 403 // Don't allow ID's of 32 bytes, but all zeros. 404 if lockID == (lnwallet.LockID{}) { 405 return nil, errors.New("id must be 32 random bytes") 406 } 407 408 // Don't allow our internal ID to be used externally for locking. Only 409 // unlocking is allowed. 410 if lockID == LndInternalLockID { 411 return nil, errors.New("reserved id cannot be used") 412 } 413 414 op, err := unmarshallOutPoint(req.Outpoint) 415 if err != nil { 416 return nil, err 417 } 418 419 // Use the specified lock duration or fall back to the default. 420 duration := DefaultLockDuration 421 if req.ExpirationSeconds != 0 { 422 duration = time.Duration(req.ExpirationSeconds) * time.Second 423 } 424 425 // Acquire the global coin selection lock to ensure there aren't any 426 // other concurrent processes attempting to lease the same UTXO. 427 var expiration time.Time 428 err = w.cfg.CoinSelectionLocker.WithCoinSelectLock(func() error { 429 expiration, err = w.cfg.Wallet.LeaseOutput( 430 lockID, *op, duration, 431 ) 432 return err 433 }) 434 if err != nil { 435 return nil, err 436 } 437 438 return &LeaseOutputResponse{ 439 Expiration: uint64(expiration.Unix()), 440 }, nil 441 } 442 443 // ReleaseOutput unlocks an output, allowing it to be available for coin 444 // selection if it remains unspent. The ID should match the one used to 445 // originally lock the output. 446 func (w *WalletKit) ReleaseOutput(ctx context.Context, 447 req *ReleaseOutputRequest) (*ReleaseOutputResponse, error) { 448 449 if len(req.Id) != 32 { 450 return nil, errors.New("id must be 32 random bytes") 451 } 452 var lockID lnwallet.LockID 453 copy(lockID[:], req.Id) 454 455 op, err := unmarshallOutPoint(req.Outpoint) 456 if err != nil { 457 return nil, err 458 } 459 460 // Acquire the global coin selection lock to maintain consistency as 461 // it's acquired when we initially leased the output. 462 err = w.cfg.CoinSelectionLocker.WithCoinSelectLock(func() error { 463 return w.cfg.Wallet.ReleaseOutput(lockID, *op) 464 }) 465 if err != nil { 466 return nil, err 467 } 468 469 return &ReleaseOutputResponse{}, nil 470 } 471 472 // ListLeases returns a list of all currently locked utxos. 473 func (w *WalletKit) ListLeases(ctx context.Context, 474 req *ListLeasesRequest) (*ListLeasesResponse, error) { 475 476 leases, err := w.cfg.Wallet.ListLeasedOutputs() 477 if err != nil { 478 return nil, err 479 } 480 481 return &ListLeasesResponse{ 482 LockedUtxos: marshallLeases(leases), 483 }, nil 484 } 485 486 // DeriveNextKey attempts to derive the *next* key within the key family 487 // (account in BIP43) specified. This method should return the next external 488 // child within this branch. 489 func (w *WalletKit) DeriveNextKey(ctx context.Context, 490 req *KeyReq) (*signrpc.KeyDescriptor, error) { 491 492 nextKeyDesc, err := w.cfg.KeyRing.DeriveNextKey( 493 keychain.KeyFamily(req.KeyFamily), 494 ) 495 if err != nil { 496 return nil, err 497 } 498 499 return &signrpc.KeyDescriptor{ 500 KeyLoc: &signrpc.KeyLocator{ 501 KeyFamily: int32(nextKeyDesc.Family), 502 KeyIndex: int32(nextKeyDesc.Index), 503 }, 504 RawKeyBytes: nextKeyDesc.PubKey.SerializeCompressed(), 505 }, nil 506 } 507 508 // DeriveKey attempts to derive an arbitrary key specified by the passed 509 // KeyLocator. 510 func (w *WalletKit) DeriveKey(ctx context.Context, 511 req *signrpc.KeyLocator) (*signrpc.KeyDescriptor, error) { 512 513 keyDesc, err := w.cfg.KeyRing.DeriveKey(keychain.KeyLocator{ 514 Family: keychain.KeyFamily(req.KeyFamily), 515 Index: uint32(req.KeyIndex), 516 }) 517 if err != nil { 518 return nil, err 519 } 520 521 return &signrpc.KeyDescriptor{ 522 KeyLoc: &signrpc.KeyLocator{ 523 KeyFamily: int32(keyDesc.Family), 524 KeyIndex: int32(keyDesc.Index), 525 }, 526 RawKeyBytes: keyDesc.PubKey.SerializeCompressed(), 527 }, nil 528 } 529 530 // NextAddr returns the next unused address within the wallet. 531 func (w *WalletKit) NextAddr(ctx context.Context, 532 req *AddrRequest) (*AddrResponse, error) { 533 534 account := lnwallet.DefaultAccountName 535 if req.Account != "" { 536 account = req.Account 537 } 538 539 addrType := lnwallet.PubKeyHash 540 if req.Type != AddressType_UNKNOWN { 541 return nil, fmt.Errorf("only the default address type (0) is supported") 542 } 543 544 addr, err := w.cfg.Wallet.NewAddress(addrType, req.Change, account) 545 if err != nil { 546 return nil, err 547 } 548 549 return &AddrResponse{ 550 Addr: addr.String(), 551 }, nil 552 } 553 554 // Attempts to publish the passed transaction to the network. Once this returns 555 // without an error, the wallet will continually attempt to re-broadcast the 556 // transaction on start up, until it enters the chain. 557 func (w *WalletKit) PublishTransaction(ctx context.Context, 558 req *Transaction) (*PublishResponse, error) { 559 560 switch { 561 // If the client doesn't specify a transaction, then there's nothing to 562 // publish. 563 case len(req.TxHex) == 0: 564 return nil, fmt.Errorf("must provide a transaction to " + 565 "publish") 566 } 567 568 tx := &wire.MsgTx{} 569 txReader := bytes.NewReader(req.TxHex) 570 if err := tx.Deserialize(txReader); err != nil { 571 return nil, err 572 } 573 574 label, err := labels.ValidateAPI(req.Label) 575 if err != nil { 576 return nil, err 577 } 578 579 err = w.cfg.Wallet.PublishTransaction(tx, label) 580 if err != nil { 581 return nil, err 582 } 583 584 return &PublishResponse{}, nil 585 } 586 587 // SendOutputs is similar to the existing sendmany call in Bitcoind, and allows 588 // the caller to create a transaction that sends to several outputs at once. 589 // This is ideal when wanting to batch create a set of transactions. 590 func (w *WalletKit) SendOutputs(ctx context.Context, 591 req *SendOutputsRequest) (*SendOutputsResponse, error) { 592 593 switch { 594 // If the client didn't specify any outputs to create, then we can't 595 // proceed . 596 case len(req.Outputs) == 0: 597 return nil, fmt.Errorf("must specify at least one output " + 598 "to create") 599 } 600 601 // Before we can request this transaction to be created, we'll need to 602 // amp the protos back into the format that the internal wallet will 603 // recognize. 604 outputsToCreate := make([]*wire.TxOut, 0, len(req.Outputs)) 605 for _, output := range req.Outputs { 606 outputsToCreate = append(outputsToCreate, &wire.TxOut{ 607 Value: output.Value, 608 PkScript: output.PkScript, 609 }) 610 } 611 612 // Then, we'll extract the minimum number of confirmations that each 613 // output we use to fund the transaction should satisfy. 614 minConfs, err := lnrpc.ExtractMinConfs(req.MinConfs, req.SpendUnconfirmed) 615 if err != nil { 616 return nil, err 617 } 618 619 label, err := labels.ValidateAPI(req.Label) 620 if err != nil { 621 return nil, err 622 } 623 624 // Now that we have the outputs mapped, we can request that the wallet 625 // attempt to create this transaction. 626 tx, err := w.cfg.Wallet.SendOutputs( 627 outputsToCreate, chainfee.AtomPerKByte(req.AtomsPerKb), minConfs, label, 628 req.Account, 629 ) 630 if err != nil { 631 return nil, err 632 } 633 634 var b bytes.Buffer 635 if err := tx.Serialize(&b); err != nil { 636 return nil, err 637 } 638 639 return &SendOutputsResponse{ 640 RawTx: b.Bytes(), 641 }, nil 642 } 643 644 // EstimateFee attempts to query the internal fee estimator of the wallet to 645 // determine the fee (in atom/kB) to attach to a transaction in order to achieve 646 // the confirmation target. 647 func (w *WalletKit) EstimateFee(ctx context.Context, 648 req *EstimateFeeRequest) (*EstimateFeeResponse, error) { 649 650 switch { 651 // A confirmation target of zero doesn't make any sense. Similarly, we 652 // reject confirmation targets of 1 as they're unreasonable. 653 case req.ConfTarget == 0 || req.ConfTarget == 1: 654 return nil, fmt.Errorf("confirmation target must be greater " + 655 "than 1") 656 } 657 658 atPerKB, err := w.cfg.FeeEstimator.EstimateFeePerKB( 659 uint32(req.ConfTarget), 660 ) 661 if err != nil { 662 return nil, err 663 } 664 665 return &EstimateFeeResponse{ 666 AtomsPerKb: int64(atPerKB), 667 }, nil 668 } 669 670 // PendingSweeps returns lists of on-chain outputs that lnd is currently 671 // attempting to sweep within its central batching engine. Outputs with similar 672 // fee rates are batched together in order to sweep them within a single 673 // transaction. The fee rate of each sweeping transaction is determined by 674 // taking the average fee rate of all the outputs it's trying to sweep. 675 func (w *WalletKit) PendingSweeps(ctx context.Context, 676 in *PendingSweepsRequest) (*PendingSweepsResponse, error) { 677 678 // Retrieve all of the outputs the UtxoSweeper is currently trying to 679 // sweep. 680 pendingInputs, err := w.cfg.Sweeper.PendingInputs() 681 if err != nil { 682 return nil, err 683 } 684 685 // Convert them into their respective RPC format. 686 rpcPendingSweeps := make([]*PendingSweep, 0, len(pendingInputs)) 687 for _, pendingInput := range pendingInputs { 688 var witnessType WitnessType 689 switch pendingInput.WitnessType { 690 case input.CommitmentTimeLock: 691 witnessType = WitnessType_COMMITMENT_TIME_LOCK 692 case input.CommitmentNoDelay: 693 witnessType = WitnessType_COMMITMENT_NO_DELAY 694 case input.CommitmentRevoke: 695 witnessType = WitnessType_COMMITMENT_REVOKE 696 case input.HtlcOfferedRevoke: 697 witnessType = WitnessType_HTLC_OFFERED_REVOKE 698 case input.HtlcAcceptedRevoke: 699 witnessType = WitnessType_HTLC_ACCEPTED_REVOKE 700 case input.HtlcOfferedTimeoutSecondLevel: 701 witnessType = WitnessType_HTLC_OFFERED_TIMEOUT_SECOND_LEVEL 702 case input.HtlcAcceptedSuccessSecondLevel: 703 witnessType = WitnessType_HTLC_ACCEPTED_SUCCESS_SECOND_LEVEL 704 case input.HtlcOfferedRemoteTimeout: 705 witnessType = WitnessType_HTLC_OFFERED_REMOTE_TIMEOUT 706 case input.HtlcAcceptedRemoteSuccess: 707 witnessType = WitnessType_HTLC_ACCEPTED_REMOTE_SUCCESS 708 case input.HtlcSecondLevelRevoke: 709 witnessType = WitnessType_HTLC_SECOND_LEVEL_REVOKE 710 case input.WitnessKeyHash: 711 witnessType = WitnessType_WITNESS_KEY_HASH 712 case input.NestedWitnessKeyHash: 713 witnessType = WitnessType_NESTED_WITNESS_KEY_HASH 714 case input.CommitmentAnchor: 715 witnessType = WitnessType_COMMITMENT_ANCHOR 716 717 // Decred-specific. 718 case input.PublicKeyHash: 719 witnessType = WitnessType_PUBKEY_HASH 720 default: 721 log.Warnf("Unhandled witness type %v for input %v", 722 pendingInput.WitnessType, pendingInput.OutPoint) 723 } 724 725 op := &lnrpc.OutPoint{ 726 TxidBytes: pendingInput.OutPoint.Hash[:], 727 OutputIndex: pendingInput.OutPoint.Index, 728 } 729 amountAtoms := uint32(pendingInput.Amount) 730 atomsPerByte := uint32(pendingInput.LastFeeRate / 1000) 731 broadcastAttempts := uint32(pendingInput.BroadcastAttempts) 732 nextBroadcastHeight := pendingInput.NextBroadcastHeight 733 734 requestedFee := pendingInput.Params.Fee 735 requestedFeeRate := uint32(requestedFee.FeeRate / 1000) 736 737 rpcPendingSweeps = append(rpcPendingSweeps, &PendingSweep{ 738 Outpoint: op, 739 WitnessType: witnessType, 740 AmountAtoms: amountAtoms, 741 AtomsPerByte: atomsPerByte, 742 BroadcastAttempts: broadcastAttempts, 743 NextBroadcastHeight: nextBroadcastHeight, 744 RequestedAtomsPerByte: requestedFeeRate, 745 RequestedConfTarget: requestedFee.ConfTarget, 746 Force: pendingInput.Params.Force, 747 }) 748 } 749 750 return &PendingSweepsResponse{ 751 PendingSweeps: rpcPendingSweeps, 752 }, nil 753 } 754 755 // unmarshallOutPoint converts an outpoint from its lnrpc type to its canonical 756 // type. 757 func unmarshallOutPoint(op *lnrpc.OutPoint) (*wire.OutPoint, error) { 758 if op == nil { 759 return nil, fmt.Errorf("empty outpoint provided") 760 } 761 762 var hash chainhash.Hash 763 switch { 764 case len(op.TxidBytes) == 0 && len(op.TxidStr) == 0: 765 fallthrough 766 767 case len(op.TxidBytes) != 0 && len(op.TxidStr) != 0: 768 return nil, fmt.Errorf("either TxidBytes or TxidStr must be " + 769 "specified, but not both") 770 771 // The hash was provided as raw bytes. 772 case len(op.TxidBytes) != 0: 773 copy(hash[:], op.TxidBytes) 774 775 // The hash was provided as a hex-encoded string. 776 case len(op.TxidStr) != 0: 777 h, err := chainhash.NewHashFromStr(op.TxidStr) 778 if err != nil { 779 return nil, err 780 } 781 hash = *h 782 } 783 784 return &wire.OutPoint{ 785 Hash: hash, 786 Index: op.OutputIndex, 787 }, nil 788 } 789 790 // BumpFee allows bumping the fee rate of an arbitrary input. A fee preference 791 // can be expressed either as a specific fee rate or a delta of blocks in which 792 // the output should be swept on-chain within. If a fee preference is not 793 // explicitly specified, then an error is returned. The status of the input 794 // sweep can be checked through the PendingSweeps RPC. 795 func (w *WalletKit) BumpFee(ctx context.Context, 796 in *BumpFeeRequest) (*BumpFeeResponse, error) { 797 798 // Parse the outpoint from the request. 799 op, err := unmarshallOutPoint(in.Outpoint) 800 if err != nil { 801 return nil, err 802 } 803 804 // Construct the request's fee preference. 805 atomsPerKB := chainfee.AtomPerKByte(in.AtomsPerByte * 1000) 806 feePreference := sweep.FeePreference{ 807 ConfTarget: in.TargetConf, 808 FeeRate: atomsPerKB, 809 } 810 811 // We'll attempt to bump the fee of the input through the UtxoSweeper. 812 // If it is currently attempting to sweep the input, then it'll simply 813 // bump its fee, which will result in a replacement transaction (RBF) 814 // being broadcast. If it is not aware of the input however, 815 // lnwallet.ErrNotMine is returned. 816 params := sweep.ParamsUpdate{ 817 Fee: feePreference, 818 Force: in.Force, 819 } 820 821 _, err = w.cfg.Sweeper.UpdateParams(*op, params) 822 switch err { 823 case nil: 824 return &BumpFeeResponse{}, nil 825 case lnwallet.ErrNotMine: 826 break 827 default: 828 return nil, err 829 } 830 831 log.Debugf("Attempting to CPFP outpoint %s", op) 832 833 // Since we're unable to perform a bump through RBF, we'll assume the 834 // user is attempting to bump an unconfirmed transaction's fee rate by 835 // sweeping an output within it under control of the wallet with a 836 // higher fee rate, essentially performing a Child-Pays-For-Parent 837 // (CPFP). 838 // 839 // We'll gather all of the information required by the UtxoSweeper in 840 // order to sweep the output. 841 utxo, err := w.cfg.Wallet.FetchInputInfo(op) 842 if err != nil { 843 return nil, err 844 } 845 846 // We're only able to bump the fee of unconfirmed transactions. 847 if utxo.Confirmations > 0 { 848 return nil, errors.New("unable to bump fee of a confirmed " + 849 "transaction") 850 } 851 852 var witnessType input.WitnessType 853 switch utxo.AddressType { 854 case lnwallet.PubKeyHash: 855 witnessType = input.PublicKeyHash 856 default: 857 return nil, fmt.Errorf("unknown input witness %v", op) 858 } 859 860 signDesc := &input.SignDescriptor{ 861 Output: &wire.TxOut{ 862 PkScript: utxo.PkScript, 863 Value: int64(utxo.Value), 864 }, 865 HashType: txscript.SigHashAll, 866 } 867 868 // We'll use the current height as the height hint since we're dealing 869 // with an unconfirmed transaction. 870 _, currentHeight, err := w.cfg.Chain.GetBestBlock() 871 if err != nil { 872 return nil, fmt.Errorf("unable to retrieve current height: %v", 873 err) 874 } 875 876 input := input.NewBaseInput(op, witnessType, signDesc, uint32(currentHeight)) 877 if _, err = w.cfg.Sweeper.SweepInput(input, sweep.Params{Fee: feePreference}); err != nil { 878 return nil, err 879 } 880 881 return &BumpFeeResponse{}, nil 882 } 883 884 // ListSweeps returns a list of the sweeps that our node has published. 885 func (w *WalletKit) ListSweeps(ctx context.Context, 886 in *ListSweepsRequest) (*ListSweepsResponse, error) { 887 888 sweeps, err := w.cfg.Sweeper.ListSweeps() 889 if err != nil { 890 return nil, err 891 } 892 893 sweepTxns := make(map[string]bool) 894 for _, sweep := range sweeps { 895 sweepTxns[sweep.String()] = true 896 } 897 898 // Some of our sweeps could have been replaced by fee, or dropped out 899 // of the mempool. Here, we lookup our wallet transactions so that we 900 // can match our list of sweeps against the list of transactions that 901 // the wallet is still tracking. 902 transactions, err := w.cfg.Wallet.ListTransactionDetails( 903 0, dcrwallet.UnconfirmedHeight, lnwallet.DefaultAccountName, 904 ) 905 if err != nil { 906 return nil, err 907 } 908 909 var ( 910 txids []string 911 txDetails []*lnwallet.TransactionDetail 912 ) 913 914 for _, tx := range transactions { 915 _, ok := sweepTxns[tx.Hash.String()] 916 if !ok { 917 continue 918 } 919 920 // Add the txid or full tx details depending on whether we want 921 // verbose output or not. 922 if in.Verbose { 923 txDetails = append(txDetails, tx) 924 } else { 925 txids = append(txids, tx.Hash.String()) 926 } 927 } 928 929 if in.Verbose { 930 return &ListSweepsResponse{ 931 Sweeps: &ListSweepsResponse_TransactionDetails{ 932 TransactionDetails: lnrpc.RPCTransactionDetails( 933 txDetails, 934 ), 935 }, 936 }, nil 937 } 938 939 return &ListSweepsResponse{ 940 Sweeps: &ListSweepsResponse_TransactionIds{ 941 TransactionIds: &ListSweepsResponse_TransactionIDs{ 942 TransactionIds: txids, 943 }, 944 }, 945 }, nil 946 } 947 948 func (w *WalletKit) extendedWallet() (lnwallet.ExtendedWalletController, error) { 949 if ewc, ok := w.cfg.Wallet.(lnwallet.ExtendedWalletController); ok { 950 return ewc, nil 951 } 952 953 if lnw, ok := w.cfg.Wallet.(*lnwallet.LightningWallet); ok { 954 if ewc, ok := lnw.WalletController.(lnwallet.ExtendedWalletController); ok { 955 return ewc, nil 956 } 957 } 958 959 return nil, fmt.Errorf("underlying WalletController %T not an ExtendedWalletController", 960 w.cfg.Wallet) 961 } 962 963 // DeriveNextAccount generates the next account of the wallet. 964 func (w *WalletKit) DeriveNextAccount(_ context.Context, req *DeriveNextAccountRequest) (*DeriveNextAccountResponse, error) { 965 ewc, err := w.extendedWallet() 966 if err != nil { 967 return nil, err 968 } 969 return &DeriveNextAccountResponse{}, ewc.DeriveNextAccount(req.Name) 970 } 971 972 // ExportPrivateKey exports a private key that is derived from a wallet address. 973 func (w *WalletKit) ExportPrivateKey(_ context.Context, req *ExportPrivateKeyRequest) (*ExportPrivateKeyResponse, error) { 974 ewc, err := w.extendedWallet() 975 if err != nil { 976 return nil, err 977 } 978 addr, err := stdaddr.DecodeAddress(req.Address, w.cfg.ChainParams) 979 if err != nil { 980 return nil, err 981 } 982 pk, err := ewc.ExportPrivKey(addr) 983 if err != nil { 984 return nil, err 985 } 986 wif, err := dcrutil.NewWIF(pk.Serialize(), w.cfg.ChainParams.PrivateKeyID, 987 dcrec.STEcdsaSecp256k1) 988 if err != nil { 989 return nil, err 990 } 991 res := &ExportPrivateKeyResponse{ 992 Wif: wif.String(), 993 } 994 return res, nil 995 } 996 997 func (w *WalletKit) RescanWallet(req *RescanWalletRequest, 998 server WalletKit_RescanWalletServer) error { 999 1000 progressFunc := func(scannedThrough int32) error { 1001 return server.Send(&RescanWalletResponse{ScannedThroughHeight: scannedThrough}) 1002 } 1003 ewc, err := w.extendedWallet() 1004 if err != nil { 1005 return err 1006 } 1007 return ewc.RescanWallet(req.BeginHeight, progressFunc) 1008 } 1009 1010 // SpendUTXOs performs a custom on-chain spend of UTXOs. 1011 func (w *WalletKit) SpendUTXOs(ctx context.Context, req *SpendUTXOsRequest) (*SpendUTXOsResponse, error) { 1012 1013 // An empty sigScript, to help in sizing the tx for fee determination. 1014 pseudoSigScript := make([]byte, input.P2PKHSigScriptSize) 1015 1016 type sigPK struct { 1017 Version uint16 1018 PKScript []byte 1019 PrivKey []byte 1020 } 1021 sigPKs := make([]sigPK, 0, len(req.Utxos)) 1022 1023 // Build the tx. 1024 var totalIn, totalOut int64 1025 tx := wire.NewMsgTx() 1026 for _, utxo := range req.Utxos { 1027 wif, err := dcrutil.DecodeWIF(utxo.PrivateKeyWif, w.cfg.ChainParams.PrivateKeyID) 1028 if err != nil { 1029 return nil, fmt.Errorf("%s is not a valid wif: %s", 1030 utxo.PrivateKeyWif, err) 1031 } 1032 1033 txid, err := chainhash.NewHash(utxo.Txid) 1034 if err != nil { 1035 return nil, fmt.Errorf("%x is not a chainhash.Hash: %v", 1036 utxo.Txid, err) 1037 } 1038 outp := &wire.OutPoint{Hash: *txid, Index: utxo.Index, Tree: int8(utxo.Tree)} 1039 1040 addr, err := stdaddr.DecodeAddress(utxo.Address, w.cfg.ChainParams) 1041 if err != nil { 1042 return nil, fmt.Errorf("utxo address %s is not a stdaddr: %v", 1043 utxo.Address, err) 1044 } 1045 1046 _, script := addr.PaymentScript() 1047 1048 txout, err := w.cfg.Chain.GetUtxo(outp, script, utxo.HeightHint, ctx.Done()) 1049 if err != nil { 1050 return nil, fmt.Errorf("unable to query for utxo %s: %v", 1051 outp, err) 1052 } 1053 1054 totalIn += txout.Value 1055 txin := wire.NewTxIn(outp, txout.Value, pseudoSigScript) 1056 tx.AddTxIn(txin) 1057 1058 pk := sigPK{PKScript: script, PrivKey: wif.PrivKey(), Version: txout.Version} 1059 sigPKs = append(sigPKs, pk) 1060 } 1061 1062 for _, out := range req.Outputs { 1063 addr, err := stdaddr.DecodeAddress(out.Address, w.cfg.ChainParams) 1064 if err != nil { 1065 return nil, fmt.Errorf("output address %s is not a stdaddr: %v", out.Address, err) 1066 } 1067 1068 version, script := addr.PaymentScript() 1069 1070 txout := wire.NewTxOut(out.Amount, script) 1071 txout.Version = version 1072 tx.AddTxOut(txout) 1073 totalOut += out.Amount 1074 } 1075 1076 sizeNoChange := int64(tx.SerializeSize()) 1077 feeRate := w.cfg.FeeEstimator.RelayFeePerKB() 1078 feeNoChange := int64(feeRate.FeeForSize(sizeNoChange)) 1079 dustLimit := int64(lnwallet.DustThresholdForRelayFee(feeRate)) 1080 1081 if totalIn-totalOut < feeNoChange { 1082 return nil, fmt.Errorf("total input amount %d cannot be spent to "+ 1083 "to total output %d and fee %d", totalIn, totalOut, feeNoChange) 1084 } 1085 1086 // If the change (after fees) is > than the dustLimit, create a change 1087 // output. 1088 if totalIn-totalOut-feeNoChange > dustLimit { 1089 // Send change to a wallet address. 1090 addr, err := w.cfg.Wallet.NewAddress(lnwallet.PubKeyHash, true, lnwallet.DefaultAccountName) 1091 if err != nil { 1092 return nil, fmt.Errorf("unable to generate change address: %v", err) 1093 } 1094 version, script := addr.PaymentScript() 1095 1096 // Create the txOut with zero amount to recalculate the fee 1097 // below. 1098 txout := wire.NewTxOut(0, script) 1099 txout.Version = version 1100 tx.AddTxOut(txout) 1101 1102 // Recalculate fee. 1103 size := int64(tx.SerializeSize()) 1104 fee := int64(feeRate.FeeForSize(size)) 1105 changeAmt := totalIn - totalOut - fee 1106 if changeAmt < dustLimit { 1107 // Adding the change output made change < dust, so 1108 // remove the change output and proceed with higher fee. 1109 tx.TxOut = tx.TxOut[:len(tx.TxOut)-1] 1110 } else { 1111 txout.Value = changeAmt 1112 } 1113 } 1114 1115 // Sign it. 1116 for i := range req.Utxos { 1117 sigScript, err := sign.SignatureScript(tx, i, sigPKs[i].PKScript, 1118 txscript.SigHashAll, sigPKs[i].PrivKey, dcrec.STEcdsaSecp256k1, 1119 true) 1120 if err != nil { 1121 return nil, fmt.Errorf("unable to sign input %d: %v", 1122 i, err) 1123 } 1124 tx.TxIn[i].SignatureScript = sigScript 1125 } 1126 1127 // Double check tx is valid. 1128 err := standalone.CheckTransactionSanity(tx, uint64(w.cfg.ChainParams.MaxTxSize)) 1129 if err != nil { 1130 return nil, fmt.Errorf("signed transaction not sane: %v", err) 1131 } 1132 for i := range tx.TxIn { 1133 vm, err := txscript.NewEngine( 1134 sigPKs[i].PKScript, tx, i, 1135 input.ScriptVerifyFlags, sigPKs[i].Version, nil, 1136 ) 1137 if err != nil { 1138 return nil, fmt.Errorf("unable to create VM to check input %d: %v", 1139 i, err) 1140 } 1141 if err = vm.Execute(); err != nil { 1142 return nil, fmt.Errorf("tx input %d failed script execution: %v", 1143 i, err) 1144 } 1145 } 1146 1147 // Broadcast it 1148 err = w.cfg.Wallet.PublishTransaction(tx, "") 1149 if err != nil { 1150 return nil, fmt.Errorf("unable to publish tx: %v", err) 1151 } 1152 rawTx, err := tx.Bytes() 1153 if err != nil { 1154 return nil, err 1155 } 1156 txId := tx.TxHash() 1157 res := &SpendUTXOsResponse{ 1158 Txid: txId[:], 1159 RawTx: rawTx, 1160 } 1161 return res, nil 1162 } 1163 1164 func (w *WalletKit) GetWalletTx(ctx context.Context, req *GetWalletTxRequest) ( 1165 *GetWalletTxResponse, error) { 1166 ewc, err := w.extendedWallet() 1167 if err != nil { 1168 return nil, err 1169 } 1170 1171 txh, err := chainhash.NewHash(req.Txid) 1172 if err != nil { 1173 return nil, err 1174 } 1175 1176 tx, err := ewc.GetWalletTransaction(*txh) 1177 if err != nil { 1178 return nil, err 1179 } 1180 res := &GetWalletTxResponse{ 1181 RawTx: tx.RawTx, 1182 Confirmations: tx.Confirmations, 1183 } 1184 if tx.BlockHash != nil { 1185 res.BlockHash = tx.BlockHash[:] 1186 } 1187 return res, nil 1188 } 1189 1190 // LabelTransaction adds a label to a transaction. 1191 func (w *WalletKit) LabelTransaction(ctx context.Context, 1192 req *LabelTransactionRequest) (*LabelTransactionResponse, error) { 1193 1194 // Check that the label provided in non-zero. 1195 if len(req.Label) == 0 { 1196 return nil, ErrZeroLabel 1197 } 1198 1199 // Validate the length of the non-zero label. We do not need to use the 1200 // label returned here, because the original is non-zero so will not 1201 // be replaced. 1202 if _, err := labels.ValidateAPI(req.Label); err != nil { 1203 return nil, err 1204 } 1205 1206 hash, err := chainhash.NewHash(req.Txid) 1207 if err != nil { 1208 return nil, err 1209 } 1210 1211 err = w.cfg.Wallet.LabelTransaction(*hash, req.Label, req.Overwrite) 1212 return &LabelTransactionResponse{}, err 1213 } 1214 1215 // FundPsbt creates a fully populated PSBT that contains enough inputs to fund 1216 // the outputs specified in the template. There are two ways of specifying a 1217 // template: Either by passing in a PSBT with at least one output declared or 1218 // by passing in a raw TxTemplate message. If there are no inputs specified in 1219 // the template, coin selection is performed automatically. If the template does 1220 // contain any inputs, it is assumed that full coin selection happened 1221 // externally and no additional inputs are added. If the specified inputs aren't 1222 // enough to fund the outputs with the given fee rate, an error is returned. 1223 // After either selecting or verifying the inputs, all input UTXOs are locked 1224 // with an internal app ID. 1225 // 1226 // NOTE: If this method returns without an error, it is the caller's 1227 // responsibility to either spend the locked UTXOs (by finalizing and then 1228 // publishing the transaction) or to unlock/release the locked UTXOs in case of 1229 // an error on the caller's side. 1230 func (w *WalletKit) FundPsbt(_ context.Context, 1231 req *FundPsbtRequest) (*FundPsbtResponse, error) { 1232 1233 var ( 1234 err error 1235 packet *psbt.Packet 1236 feeAtomsPerKB chainfee.AtomPerKByte 1237 locks []*lnwallet.LockedOutput 1238 rawPsbt bytes.Buffer 1239 ) 1240 1241 // There are two ways a user can specify what we call the template (a 1242 // list of inputs and outputs to use in the PSBT): Either as a PSBT 1243 // packet directly or as a special RPC message. Find out which one the 1244 // user wants to use, they are mutually exclusive. 1245 switch { 1246 // The template is specified as a PSBT. All we have to do is parse it. 1247 case req.GetPsbt() != nil: 1248 r := bytes.NewReader(req.GetPsbt()) 1249 packet, err = psbt.NewFromRawBytes(r, false) 1250 if err != nil { 1251 return nil, fmt.Errorf("could not parse PSBT: %v", err) 1252 } 1253 1254 // The template is specified as a RPC message. We need to create a new 1255 // PSBT and copy the RPC information over. 1256 case req.GetRaw() != nil: 1257 tpl := req.GetRaw() 1258 1259 txOut := make([]*wire.TxOut, 0, len(tpl.Outputs)) 1260 for addrStr, amt := range tpl.Outputs { 1261 addr, err := stdaddr.DecodeAddress( 1262 addrStr, w.cfg.ChainParams, 1263 ) 1264 if err != nil { 1265 return nil, fmt.Errorf("error parsing address "+ 1266 "%s for network %s: %v", addrStr, 1267 w.cfg.ChainParams.Name, err) 1268 } 1269 scriptVersion, pkScript := addr.PaymentScript() 1270 txOut = append(txOut, &wire.TxOut{ 1271 Value: int64(amt), 1272 PkScript: pkScript, 1273 Version: scriptVersion, 1274 }) 1275 } 1276 1277 txIn := make([]*wire.OutPoint, len(tpl.Inputs)) 1278 for idx, in := range tpl.Inputs { 1279 op, err := unmarshallOutPoint(in) 1280 if err != nil { 1281 return nil, fmt.Errorf("error parsing "+ 1282 "outpoint: %v", err) 1283 } 1284 txIn[idx] = op 1285 } 1286 1287 sequences := make([]uint32, len(txIn)) 1288 packet, err = psbt.New(txIn, txOut, 2, 0, sequences) 1289 if err != nil { 1290 return nil, fmt.Errorf("could not create PSBT: %v", err) 1291 } 1292 1293 default: 1294 return nil, fmt.Errorf("transaction template missing, need " + 1295 "to specify either PSBT or raw TX template") 1296 } 1297 1298 // Determine the desired transaction fee. 1299 switch { 1300 // Estimate the fee by the target number of blocks to confirmation. 1301 case req.GetTargetConf() != 0: 1302 targetConf := req.GetTargetConf() 1303 if targetConf < 2 { 1304 return nil, fmt.Errorf("confirmation target must be " + 1305 "greater than 1") 1306 } 1307 1308 feeAtomsPerKB, err = w.cfg.FeeEstimator.EstimateFeePerKB( 1309 targetConf, 1310 ) 1311 if err != nil { 1312 return nil, fmt.Errorf("could not estimate fee: %v", 1313 err) 1314 } 1315 1316 // Convert the fee to sat/kW from the specified sat/vByte. 1317 case req.GetAtomsPerByte() != 0: 1318 feeAtomsPerKB = chainfee.AtomPerKByte( 1319 req.GetAtomsPerByte() * 1000, 1320 ) 1321 1322 default: 1323 return nil, fmt.Errorf("fee definition missing, need to " + 1324 "specify either target_conf or sat_per_vbyte") 1325 } 1326 1327 // Then, we'll extract the minimum number of confirmations that each 1328 // output we use to fund the transaction should satisfy. 1329 minConfs, err := lnrpc.ExtractMinConfs( 1330 req.GetMinConfs(), req.GetSpendUnconfirmed(), 1331 ) 1332 if err != nil { 1333 return nil, err 1334 } 1335 1336 // The RPC parsing part is now over. Several of the following operations 1337 // require us to hold the global coin selection lock so we do the rest 1338 // of the tasks while holding the lock. The result is a list of locked 1339 // UTXOs. 1340 changeIndex := int32(-1) 1341 err = w.cfg.CoinSelectionLocker.WithCoinSelectLock(func() error { 1342 // In case the user did specify inputs, we need to make sure 1343 // they are known to us, still unspent and not yet locked. 1344 if len(packet.UnsignedTx.TxIn) > 0 { 1345 // Get a list of all unspent witness outputs. 1346 utxos, err := w.cfg.Wallet.ListUnspentWitness( 1347 minConfs, defaultMaxConf, req.Account, 1348 ) 1349 if err != nil { 1350 return err 1351 } 1352 1353 // Validate all inputs against our known list of UTXOs 1354 // now. 1355 err = verifyInputsUnspent(packet.UnsignedTx.TxIn, utxos) 1356 if err != nil { 1357 return err 1358 } 1359 } 1360 1361 // We made sure the input from the user is as sane as possible. 1362 // We can now ask the wallet to fund the TX. This will not yet 1363 // lock any coins but might still change the wallet DB by 1364 // generating a new change address. 1365 changeIndex, err = w.cfg.Wallet.FundPsbt( 1366 packet, minConfs, feeAtomsPerKB, req.Account, 1367 ) 1368 if err != nil { 1369 return fmt.Errorf("wallet couldn't fund PSBT: %v", err) 1370 } 1371 1372 // Make sure we can properly serialize the packet. If this goes 1373 // wrong then something isn't right with the inputs and we 1374 // probably shouldn't try to lock any of them. 1375 err = packet.Serialize(&rawPsbt) 1376 if err != nil { 1377 return fmt.Errorf("error serializing funded PSBT: %v", 1378 err) 1379 } 1380 1381 // Now we have obtained a set of coins that can be used to fund 1382 // the TX. Let's lock them to be sure they aren't spent by the 1383 // time the PSBT is published. This is the action we do here 1384 // that could cause an error. Therefore if some of the UTXOs 1385 // cannot be locked, the rollback of the other's locks also 1386 // happens in this function. If we ever need to do more after 1387 // this function, we need to extract the rollback needs to be 1388 // extracted into a defer. 1389 locks, err = lockInputs(w.cfg.Wallet, packet) 1390 if err != nil { 1391 return fmt.Errorf("could not lock inputs: %v", err) 1392 } 1393 1394 return nil 1395 }) 1396 if err != nil { 1397 return nil, err 1398 } 1399 1400 // Convert the lock leases to the RPC format. 1401 rpcLocks := marshallLeases(locks) 1402 1403 return &FundPsbtResponse{ 1404 FundedPsbt: rawPsbt.Bytes(), 1405 ChangeOutputIndex: changeIndex, 1406 LockedUtxos: rpcLocks, 1407 }, nil 1408 } 1409 1410 // marshallLeases converts the lock leases to the RPC format. 1411 func marshallLeases(locks []*lnwallet.LockedOutput) []*UtxoLease { 1412 rpcLocks := make([]*UtxoLease, len(locks)) 1413 for idx, lock := range locks { 1414 rpcLocks[idx] = &UtxoLease{ 1415 Id: lock.LockID[:], 1416 Outpoint: &lnrpc.OutPoint{ 1417 TxidBytes: lock.Outpoint.Hash[:], 1418 TxidStr: lock.Outpoint.Hash.String(), 1419 OutputIndex: lock.Outpoint.Index, 1420 }, 1421 Expiration: uint64(lock.Expiration.Unix()), 1422 } 1423 } 1424 1425 return rpcLocks 1426 } 1427 1428 // SignPsbt expects a partial transaction with all inputs and outputs fully 1429 // declared and tries to sign all unsigned inputs that have all required fields 1430 // (UTXO information, BIP32 derivation information, witness or sig scripts) 1431 // set. 1432 // If no error is returned, the PSBT is ready to be given to the next signer or 1433 // to be finalized if lnd was the last signer. 1434 // 1435 // NOTE: This RPC only signs inputs (and only those it can sign), it does not 1436 // perform any other tasks (such as coin selection, UTXO locking or 1437 // input/output/fee value validation, PSBT finalization). Any input that is 1438 // incomplete will be skipped. 1439 func (w *WalletKit) SignPsbt(_ context.Context, req *SignPsbtRequest) ( 1440 *SignPsbtResponse, error) { 1441 1442 packet, err := psbt.NewFromRawBytes( 1443 bytes.NewReader(req.FundedPsbt), false, 1444 ) 1445 if err != nil { 1446 log.Debugf("Error parsing PSBT: %v, raw input: %x", err, 1447 req.FundedPsbt) 1448 return nil, fmt.Errorf("error parsing PSBT: %v", err) 1449 } 1450 1451 // Let the wallet do the heavy lifting. This will sign all inputs that 1452 // we have the UTXO for. If some inputs can't be signed and don't have 1453 // witness data attached, they will just be skipped. 1454 err = w.cfg.Wallet.SignPsbt(packet) 1455 if err != nil { 1456 return nil, fmt.Errorf("error signing PSBT: %v", err) 1457 } 1458 1459 // Serialize the signed PSBT in both the packet and wire format. 1460 var signedPsbtBytes bytes.Buffer 1461 err = packet.Serialize(&signedPsbtBytes) 1462 if err != nil { 1463 return nil, fmt.Errorf("error serializing PSBT: %v", err) 1464 } 1465 1466 return &SignPsbtResponse{ 1467 SignedPsbt: signedPsbtBytes.Bytes(), 1468 }, nil 1469 } 1470 1471 // FinalizePsbt expects a partial transaction with all inputs and outputs fully 1472 // declared and tries to sign all inputs that belong to the wallet. Lnd must be 1473 // the last signer of the transaction. That means, if there are any unsigned 1474 // non-witness inputs or inputs without UTXO information attached or inputs 1475 // without witness data that do not belong to lnd's wallet, this method will 1476 // fail. If no error is returned, the PSBT is ready to be extracted and the 1477 // final TX within to be broadcast. 1478 // 1479 // NOTE: This method does NOT publish the transaction once finalized. It is the 1480 // caller's responsibility to either publish the transaction on success or 1481 // unlock/release any locked UTXOs in case of an error in this method. 1482 func (w *WalletKit) FinalizePsbt(_ context.Context, 1483 req *FinalizePsbtRequest) (*FinalizePsbtResponse, error) { 1484 1485 // Parse the funded PSBT. No additional checks are required at this 1486 // level as the wallet will perform all of them. 1487 packet, err := psbt.NewFromRawBytes( 1488 bytes.NewReader(req.FundedPsbt), false, 1489 ) 1490 if err != nil { 1491 return nil, fmt.Errorf("error parsing PSBT: %v", err) 1492 } 1493 1494 // Let the wallet do the heavy lifting. This will sign all inputs that 1495 // we have the UTXO for. If some inputs can't be signed and don't have 1496 // witness data attached, this will fail. 1497 err = w.cfg.Wallet.FinalizePsbt(packet) 1498 if err != nil { 1499 return nil, fmt.Errorf("error finalizing PSBT: %v", err) 1500 } 1501 1502 var ( 1503 finalPsbtBytes bytes.Buffer 1504 finalTxBytes bytes.Buffer 1505 ) 1506 1507 // Serialize the finalized PSBT in both the packet and wire format. 1508 err = packet.Serialize(&finalPsbtBytes) 1509 if err != nil { 1510 return nil, fmt.Errorf("error serializing PSBT: %v", err) 1511 } 1512 finalTx, err := psbt.Extract(packet) 1513 if err != nil { 1514 return nil, fmt.Errorf("unable to extract final TX: %v", err) 1515 } 1516 err = finalTx.Serialize(&finalTxBytes) 1517 if err != nil { 1518 return nil, fmt.Errorf("error serializing final TX: %v", err) 1519 } 1520 1521 return &FinalizePsbtResponse{ 1522 SignedPsbt: finalPsbtBytes.Bytes(), 1523 RawFinalTx: finalTxBytes.Bytes(), 1524 }, nil 1525 } 1526 1527 // marshalWalletAccount converts the properties of an account into its RPC 1528 // representation. 1529 func marshalWalletAccount(account *wallet.AccountProperties) (*Account, error) { 1530 rpcAccount := &Account{ 1531 Name: account.AccountName, 1532 ExternalKeyCount: account.LastReturnedExternalIndex + 1, 1533 InternalKeyCount: account.LastReturnedInternalIndex + 1, 1534 // WatchOnly: account.IsWatchOnly, 1535 } 1536 1537 return rpcAccount, nil 1538 } 1539 1540 // ListAccounts retrieves all accounts belonging to the wallet by default. A 1541 // name and key scope filter can be provided to filter through all of the wallet 1542 // accounts and return only those matching. 1543 func (w *WalletKit) ListAccounts(ctx context.Context, 1544 req *ListAccountsRequest) (*ListAccountsResponse, error) { 1545 1546 accounts, err := w.cfg.Wallet.ListAccounts(req.Name) 1547 if err != nil { 1548 return nil, err 1549 } 1550 1551 rpcAccounts := make([]*Account, 0, len(accounts)) 1552 for _, account := range accounts { 1553 // Don't include the default imported accounts created by the 1554 // wallet in the response if they don't have any keys imported. 1555 if account.AccountName == importedAddrsAccountName && 1556 account.ImportedKeyCount == 0 { 1557 continue 1558 } 1559 1560 rpcAccount, err := marshalWalletAccount(&account) 1561 if err != nil { 1562 return nil, err 1563 } 1564 rpcAccounts = append(rpcAccounts, rpcAccount) 1565 } 1566 1567 return &ListAccountsResponse{Accounts: rpcAccounts}, nil 1568 } 1569 1570 // ImportAccount imports an account backed by an account extended public key. 1571 func (w *WalletKit) ImportAccount(ctx context.Context, 1572 req *ImportAccountRequest) (*ImportAccountResponse, error) { 1573 1574 accountPubKey, err := hdkeychain.NewKeyFromString(req.ExtendedPublicKey, 1575 w.cfg.ChainParams) 1576 1577 if err != nil { 1578 return nil, err 1579 } 1580 1581 accountProps, extAddrs, intAddrs, err := w.cfg.Wallet.ImportAccount( 1582 req.Name, accountPubKey, req.DryRun, 1583 ) 1584 if err != nil { 1585 return nil, err 1586 } 1587 1588 rpcAccount, err := marshalWalletAccount(accountProps) 1589 if err != nil { 1590 return nil, err 1591 } 1592 1593 resp := &ImportAccountResponse{Account: rpcAccount} 1594 if !req.DryRun { 1595 return resp, nil 1596 } 1597 1598 resp.DryRunExternalAddrs = make([]string, len(extAddrs)) 1599 for i := 0; i < len(extAddrs); i++ { 1600 resp.DryRunExternalAddrs[i] = extAddrs[i].String() 1601 } 1602 resp.DryRunInternalAddrs = make([]string, len(intAddrs)) 1603 for i := 0; i < len(intAddrs); i++ { 1604 resp.DryRunInternalAddrs[i] = intAddrs[i].String() 1605 } 1606 1607 return resp, nil 1608 } 1609 1610 // ImportPublicKey imports a single derived public key into the wallet. 1611 func (w *WalletKit) ImportPublicKey(ctx context.Context, 1612 req *ImportPublicKeyRequest) (*ImportPublicKeyResponse, error) { 1613 1614 pubKey, err := secp256k1.ParsePubKey(req.PublicKey) 1615 if err != nil { 1616 return nil, err 1617 } 1618 if err := w.cfg.Wallet.ImportPublicKey(pubKey); err != nil { 1619 return nil, err 1620 } 1621 1622 return &ImportPublicKeyResponse{}, nil 1623 }