github.com/decred/dcrlnd@v0.7.6/chanbackup/single.go (about)

     1  package chanbackup
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"net"
     8  
     9  	"github.com/decred/dcrd/chaincfg/chainhash"
    10  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
    11  	"github.com/decred/dcrd/dcrutil/v4"
    12  	"github.com/decred/dcrd/wire"
    13  	"github.com/decred/dcrlnd/channeldb"
    14  	"github.com/decred/dcrlnd/keychain"
    15  	"github.com/decred/dcrlnd/lnwire"
    16  )
    17  
    18  // SingleBackupVersion denotes the version of the single static channel backup.
    19  // Based on this version, we know how to pack/unpack serialized versions of the
    20  // backup.
    21  type SingleBackupVersion byte
    22  
    23  const (
    24  	// DefaultSingleVersion is the default version of the single channel
    25  	// backup. The serialized version of this static channel backup is
    26  	// simply: version || SCB. Where SCB is the known format of the
    27  	// version.
    28  	DefaultSingleVersion = 0
    29  
    30  	// TweaklessCommitVersion is the second SCB version. This version
    31  	// implicitly denotes that this channel uses the new tweakless commit
    32  	// format.
    33  	TweaklessCommitVersion = 1
    34  
    35  	// AnchorsCommitVersion is the third SCB version. This version
    36  	// implicitly denotes that this channel uses the new anchor commitment
    37  	// format.
    38  	AnchorsCommitVersion = 2
    39  
    40  	// AnchorsZeroFeeHtlcTxCommitVersion is a version that denotes this
    41  	// channel is using the zero-fee second-level anchor commitment format.
    42  	AnchorsZeroFeeHtlcTxCommitVersion = 3
    43  
    44  	// ScriptEnforcedLeaseVersion is a version that denotes this channel is
    45  	// using the zero-fee second-level anchor commitment format along with
    46  	// an additional CLTV requirement of the channel lease maturity on any
    47  	// commitment and HTLC outputs that pay directly to the channel
    48  	// initiator.
    49  	ScriptEnforcedLeaseVersion = 4
    50  )
    51  
    52  // Single is a static description of an existing channel that can be used for
    53  // the purposes of backing up. The fields in this struct allow a node to
    54  // recover the settled funds within a channel in the case of partial or
    55  // complete data loss. We provide the network address that we last used to
    56  // connect to the peer as well, in case the node stops advertising the IP on
    57  // the network for whatever reason.
    58  //
    59  // TODO(roasbeef): suffix version into struct?
    60  type Single struct {
    61  	// Version is the version that should be observed when attempting to
    62  	// pack the single backup.
    63  	Version SingleBackupVersion
    64  
    65  	// IsInitiator is true if we were the initiator of the channel, and
    66  	// false otherwise. We'll need to know this information in order to
    67  	// properly re-derive the state hint information.
    68  	IsInitiator bool
    69  
    70  	// ChainHash is a hash which represents the blockchain that this
    71  	// channel will be opened within. This value is typically the genesis
    72  	// hash. In the case that the original chain went through a contentious
    73  	// hard-fork, then this value will be tweaked using the unique fork
    74  	// point on each branch.
    75  	ChainHash chainhash.Hash
    76  
    77  	// FundingOutpoint is the outpoint of the final funding transaction.
    78  	// This value uniquely and globally identities the channel within the
    79  	// target blockchain as specified by the chain hash parameter.
    80  	FundingOutpoint wire.OutPoint
    81  
    82  	// ShortChannelID encodes the exact location in the chain in which the
    83  	// channel was initially confirmed. This includes: the block height,
    84  	// transaction index, and the output within the target transaction.
    85  	// Channels that were not confirmed at the time of backup creation will
    86  	// have the funding TX broadcast height set as their block height in
    87  	// the ShortChannelID.
    88  	ShortChannelID lnwire.ShortChannelID
    89  
    90  	// RemoteNodePub is the identity public key of the remote node this
    91  	// channel has been established with.
    92  	RemoteNodePub *secp256k1.PublicKey
    93  
    94  	// Addresses is a list of IP address in which either we were able to
    95  	// reach the node over in the past, OR we received an incoming
    96  	// authenticated connection for the stored identity public key.
    97  	Addresses []net.Addr
    98  
    99  	// Capacity is the size of the original channel.
   100  	Capacity dcrutil.Amount
   101  
   102  	// LocalChanCfg is our local channel configuration. It contains all the
   103  	// information we need to re-derive the keys we used within the
   104  	// channel. Most importantly, it allows to derive the base public
   105  	// that's used to deriving the key used within the non-delayed
   106  	// pay-to-self output on the commitment transaction for a node. With
   107  	// this information, we can re-derive the private key needed to sweep
   108  	// the funds on-chain.
   109  	//
   110  	// NOTE: Of the items in the ChannelConstraints, we only write the CSV
   111  	// delay.
   112  	LocalChanCfg channeldb.ChannelConfig
   113  
   114  	// RemoteChanCfg is the remote channel confirmation. We store this as
   115  	// well since we'll need some of their keys to re-derive things like
   116  	// the state hint obfuscator which will allow us to recognize the state
   117  	// their broadcast on chain.
   118  	//
   119  	// NOTE: Of the items in the ChannelConstraints, we only write the CSV
   120  	// delay.
   121  	RemoteChanCfg channeldb.ChannelConfig
   122  
   123  	// ShaChainRootDesc describes how to derive the private key that was
   124  	// used as the shachain root for this channel.
   125  	ShaChainRootDesc keychain.KeyDescriptor
   126  
   127  	// LeaseExpiry represents the absolute expiration as a height of the
   128  	// chain of a channel lease that is applied to every output that pays
   129  	// directly to the channel initiator in addition to the usual CSV
   130  	// requirement.
   131  	//
   132  	// NOTE: This field will only be present for the following versions:
   133  	//
   134  	// - ScriptEnforcedLeaseVersion
   135  	LeaseExpiry uint32
   136  }
   137  
   138  // NewSingle creates a new static channel backup based on an existing open
   139  // channel. We also pass in the set of addresses that we used in the past to
   140  // connect to the channel peer.
   141  func NewSingle(channel *channeldb.OpenChannel,
   142  	nodeAddrs []net.Addr) Single {
   143  
   144  	var shaChainRootDesc keychain.KeyDescriptor
   145  
   146  	// If the channel has a populated RevocationKeyLocator, then we can
   147  	// just store that instead of the public key.
   148  	if channel.RevocationKeyLocator.Family == keychain.KeyFamilyRevocationRoot {
   149  		shaChainRootDesc = keychain.KeyDescriptor{
   150  			KeyLocator: channel.RevocationKeyLocator,
   151  		}
   152  	} else {
   153  		// If the RevocationKeyLocator is not populated, then we'll need
   154  		// to obtain a public point for the shachain root and store that.
   155  		// This is the legacy scheme.
   156  		var b bytes.Buffer
   157  		_ = channel.RevocationProducer.Encode(&b) // Can't return an error.
   158  
   159  		// Once we have the root, we'll make a public key from it, such that
   160  		// the backups plaintext don't carry any private information. When we
   161  		// go to recover, we'll present this in order to derive the private
   162  		// key.
   163  		shaChainPoint := secp256k1.PrivKeyFromBytes(b.Bytes()).PubKey()
   164  
   165  		shaChainRootDesc = keychain.KeyDescriptor{
   166  			PubKey: shaChainPoint,
   167  			KeyLocator: keychain.KeyLocator{
   168  				Family: keychain.KeyFamilyRevocationRoot,
   169  			},
   170  		}
   171  	}
   172  
   173  	// If a channel is unconfirmed, the block height of the ShortChannelID
   174  	// is zero. This will lead to problems when trying to restore that
   175  	// channel as the spend notifier would get a height hint of zero.
   176  	// To work around that problem, we add the channel broadcast height
   177  	// to the channel ID so we can use that as height hint on restore.
   178  	chanID := channel.ShortChanID()
   179  	if chanID.BlockHeight == 0 {
   180  		chanID.BlockHeight = channel.FundingBroadcastHeight
   181  	}
   182  
   183  	single := Single{
   184  		IsInitiator:      channel.IsInitiator,
   185  		ChainHash:        channel.ChainHash,
   186  		FundingOutpoint:  channel.FundingOutpoint,
   187  		ShortChannelID:   chanID,
   188  		RemoteNodePub:    channel.IdentityPub,
   189  		Addresses:        nodeAddrs,
   190  		Capacity:         channel.Capacity,
   191  		LocalChanCfg:     channel.LocalChanCfg,
   192  		RemoteChanCfg:    channel.RemoteChanCfg,
   193  		ShaChainRootDesc: shaChainRootDesc,
   194  	}
   195  
   196  	switch {
   197  	case channel.ChanType.HasLeaseExpiration():
   198  		single.Version = ScriptEnforcedLeaseVersion
   199  		single.LeaseExpiry = channel.ThawHeight
   200  
   201  	case channel.ChanType.ZeroHtlcTxFee():
   202  		single.Version = AnchorsZeroFeeHtlcTxCommitVersion
   203  
   204  	case channel.ChanType.HasAnchors():
   205  		single.Version = AnchorsCommitVersion
   206  
   207  	case channel.ChanType.IsTweakless():
   208  		single.Version = TweaklessCommitVersion
   209  
   210  	default:
   211  		single.Version = DefaultSingleVersion
   212  	}
   213  
   214  	return single
   215  }
   216  
   217  // Serialize attempts to write out the serialized version of the target
   218  // StaticChannelBackup into the passed io.Writer.
   219  func (s *Single) Serialize(w io.Writer) error {
   220  	// Check to ensure that we'll only attempt to serialize a version that
   221  	// we're aware of.
   222  	switch s.Version {
   223  	case DefaultSingleVersion:
   224  	case TweaklessCommitVersion:
   225  	case AnchorsCommitVersion:
   226  	case AnchorsZeroFeeHtlcTxCommitVersion:
   227  	case ScriptEnforcedLeaseVersion:
   228  	default:
   229  		return fmt.Errorf("unable to serialize w/ unknown "+
   230  			"version: %v", s.Version)
   231  	}
   232  
   233  	// If the sha chain root has specified a public key (which is
   234  	// optional), then we'll encode it now.
   235  	var shaChainPub [33]byte
   236  	if s.ShaChainRootDesc.PubKey != nil {
   237  		copy(
   238  			shaChainPub[:],
   239  			s.ShaChainRootDesc.PubKey.SerializeCompressed(),
   240  		)
   241  	}
   242  
   243  	// First we gather the SCB as is into a temporary buffer so we can
   244  	// determine the total length. Before we write out the serialized SCB,
   245  	// we write the length which allows us to skip any Singles that we
   246  	// don't know of when decoding a multi.
   247  	var singleBytes bytes.Buffer
   248  	if err := lnwire.WriteElements(
   249  		&singleBytes,
   250  		s.IsInitiator,
   251  		s.ChainHash[:],
   252  		s.FundingOutpoint,
   253  		s.ShortChannelID,
   254  		s.RemoteNodePub,
   255  		s.Addresses,
   256  		s.Capacity,
   257  
   258  		s.LocalChanCfg.CsvDelay,
   259  
   260  		// We only need to write out the KeyLocator portion of the
   261  		// local channel config.
   262  		uint32(s.LocalChanCfg.MultiSigKey.Family),
   263  		s.LocalChanCfg.MultiSigKey.Index,
   264  		uint32(s.LocalChanCfg.RevocationBasePoint.Family),
   265  		s.LocalChanCfg.RevocationBasePoint.Index,
   266  		uint32(s.LocalChanCfg.PaymentBasePoint.Family),
   267  		s.LocalChanCfg.PaymentBasePoint.Index,
   268  		uint32(s.LocalChanCfg.DelayBasePoint.Family),
   269  		s.LocalChanCfg.DelayBasePoint.Index,
   270  		uint32(s.LocalChanCfg.HtlcBasePoint.Family),
   271  		s.LocalChanCfg.HtlcBasePoint.Index,
   272  
   273  		s.RemoteChanCfg.CsvDelay,
   274  
   275  		// We only need to write out the raw pubkey for the remote
   276  		// channel config.
   277  		s.RemoteChanCfg.MultiSigKey.PubKey,
   278  		s.RemoteChanCfg.RevocationBasePoint.PubKey,
   279  		s.RemoteChanCfg.PaymentBasePoint.PubKey,
   280  		s.RemoteChanCfg.DelayBasePoint.PubKey,
   281  		s.RemoteChanCfg.HtlcBasePoint.PubKey,
   282  
   283  		shaChainPub[:],
   284  		uint32(s.ShaChainRootDesc.KeyLocator.Family),
   285  		s.ShaChainRootDesc.KeyLocator.Index,
   286  	); err != nil {
   287  		return err
   288  	}
   289  	if s.Version == ScriptEnforcedLeaseVersion {
   290  		err := lnwire.WriteElements(&singleBytes, s.LeaseExpiry)
   291  		if err != nil {
   292  			return err
   293  		}
   294  	}
   295  
   296  	// TODO(yy): remove the type assertion when we finished refactoring db
   297  	// into using write buffer.
   298  	buf, ok := w.(*bytes.Buffer)
   299  	if !ok {
   300  		return fmt.Errorf("expect io.Writer to be *bytes.Buffer")
   301  	}
   302  
   303  	return lnwire.WriteElements(
   304  		buf,
   305  		byte(s.Version),
   306  		uint16(len(singleBytes.Bytes())),
   307  		singleBytes.Bytes(),
   308  	)
   309  }
   310  
   311  // PackToWriter is similar to the Serialize method, but takes the operation a
   312  // step further by encryption the raw bytes of the static channel back up. For
   313  // encryption we use the chacah20poly1305 AEAD cipher with a 24 byte nonce and
   314  // 32-byte key size. We use a 24-byte nonce, as we can't ensure that we have a
   315  // global counter to use as a sequence number for nonces, and want to ensure
   316  // that we're able to decrypt these blobs without any additional context. We
   317  // derive the key that we use for encryption via a SHA2 operation of the with
   318  // the golden keychain.KeyFamilyStaticBackup base encryption key.  We then take
   319  // the serialized resulting shared secret point, and hash it using sha256 to
   320  // obtain the key that we'll use for encryption. When using the AEAD, we pass
   321  // the nonce as associated data such that we'll be able to package the two
   322  // together for storage. Before writing out the encrypted payload, we prepend
   323  // the nonce to the final blob.
   324  func (s *Single) PackToWriter(w io.Writer, keyRing keychain.KeyRing) error {
   325  	// First, we'll serialize the SCB (StaticChannelBackup) into a
   326  	// temporary buffer so we can store it in a temporary place before we
   327  	// go to encrypt the entire thing.
   328  	var rawBytes bytes.Buffer
   329  	if err := s.Serialize(&rawBytes); err != nil {
   330  		return err
   331  	}
   332  
   333  	// Finally, we'll encrypt the raw serialized SCB (using the nonce as
   334  	// associated data), and write out the ciphertext prepend with the
   335  	// nonce that we used to the passed io.Reader.
   336  	return encryptPayloadToWriter(rawBytes, w, keyRing)
   337  }
   338  
   339  // readLocalKeyDesc reads a KeyDescriptor encoded within an unpacked Single.
   340  // For local KeyDescs, we only write out the KeyLocator information as we can
   341  // re-derive the pubkey from it.
   342  func readLocalKeyDesc(r io.Reader) (keychain.KeyDescriptor, error) {
   343  	var keyDesc keychain.KeyDescriptor
   344  
   345  	var keyFam uint32
   346  	if err := lnwire.ReadElements(r, &keyFam); err != nil {
   347  		return keyDesc, err
   348  	}
   349  	keyDesc.Family = keychain.KeyFamily(keyFam)
   350  
   351  	if err := lnwire.ReadElements(r, &keyDesc.Index); err != nil {
   352  		return keyDesc, err
   353  	}
   354  
   355  	return keyDesc, nil
   356  }
   357  
   358  // readRemoteKeyDesc reads a remote KeyDescriptor encoded within an unpacked
   359  // Single. For remote KeyDescs, we write out only the PubKey since we don't
   360  // actually have the KeyLocator data.
   361  func readRemoteKeyDesc(r io.Reader) (keychain.KeyDescriptor, error) {
   362  	var (
   363  		keyDesc keychain.KeyDescriptor
   364  		pub     [33]byte
   365  	)
   366  
   367  	_, err := io.ReadFull(r, pub[:])
   368  	if err != nil {
   369  		return keychain.KeyDescriptor{}, err
   370  	}
   371  
   372  	keyDesc.PubKey, err = secp256k1.ParsePubKey(pub[:])
   373  	if err != nil {
   374  		return keychain.KeyDescriptor{}, err
   375  	}
   376  
   377  	return keyDesc, nil
   378  }
   379  
   380  // Deserialize attempts to read the raw plaintext serialized SCB from the
   381  // passed io.Reader. If the method is successful, then the target
   382  // StaticChannelBackup will be fully populated.
   383  func (s *Single) Deserialize(r io.Reader) error {
   384  	// First, we'll need to read the version of this single-back up so we
   385  	// can know how to unpack each of the SCB.
   386  	var version byte
   387  	err := lnwire.ReadElements(r, &version)
   388  	if err != nil {
   389  		return err
   390  	}
   391  
   392  	s.Version = SingleBackupVersion(version)
   393  
   394  	switch s.Version {
   395  	case DefaultSingleVersion:
   396  	case TweaklessCommitVersion:
   397  	case AnchorsCommitVersion:
   398  	case AnchorsZeroFeeHtlcTxCommitVersion:
   399  	case ScriptEnforcedLeaseVersion:
   400  	default:
   401  		return fmt.Errorf("unable to de-serialize w/ unknown "+
   402  			"version: %v", s.Version)
   403  	}
   404  
   405  	var length uint16
   406  	if err := lnwire.ReadElements(r, &length); err != nil {
   407  		return err
   408  	}
   409  
   410  	err = lnwire.ReadElements(
   411  		r, &s.IsInitiator, s.ChainHash[:], &s.FundingOutpoint,
   412  		&s.ShortChannelID, &s.RemoteNodePub, &s.Addresses, &s.Capacity,
   413  	)
   414  	if err != nil {
   415  		return err
   416  	}
   417  
   418  	err = lnwire.ReadElements(r, &s.LocalChanCfg.CsvDelay)
   419  	if err != nil {
   420  		return err
   421  	}
   422  	s.LocalChanCfg.MultiSigKey, err = readLocalKeyDesc(r)
   423  	if err != nil {
   424  		return err
   425  	}
   426  	s.LocalChanCfg.RevocationBasePoint, err = readLocalKeyDesc(r)
   427  	if err != nil {
   428  		return err
   429  	}
   430  	s.LocalChanCfg.PaymentBasePoint, err = readLocalKeyDesc(r)
   431  	if err != nil {
   432  		return err
   433  	}
   434  	s.LocalChanCfg.DelayBasePoint, err = readLocalKeyDesc(r)
   435  	if err != nil {
   436  		return err
   437  	}
   438  	s.LocalChanCfg.HtlcBasePoint, err = readLocalKeyDesc(r)
   439  	if err != nil {
   440  		return err
   441  	}
   442  
   443  	err = lnwire.ReadElements(r, &s.RemoteChanCfg.CsvDelay)
   444  	if err != nil {
   445  		return err
   446  	}
   447  	s.RemoteChanCfg.MultiSigKey, err = readRemoteKeyDesc(r)
   448  	if err != nil {
   449  		return err
   450  	}
   451  	s.RemoteChanCfg.RevocationBasePoint, err = readRemoteKeyDesc(r)
   452  	if err != nil {
   453  		return err
   454  	}
   455  	s.RemoteChanCfg.PaymentBasePoint, err = readRemoteKeyDesc(r)
   456  	if err != nil {
   457  		return err
   458  	}
   459  	s.RemoteChanCfg.DelayBasePoint, err = readRemoteKeyDesc(r)
   460  	if err != nil {
   461  		return err
   462  	}
   463  	s.RemoteChanCfg.HtlcBasePoint, err = readRemoteKeyDesc(r)
   464  	if err != nil {
   465  		return err
   466  	}
   467  
   468  	// Finally, we'll parse out the ShaChainRootDesc.
   469  	var (
   470  		shaChainPub [33]byte
   471  		zeroPub     [33]byte
   472  	)
   473  	if err := lnwire.ReadElements(r, shaChainPub[:]); err != nil {
   474  		return err
   475  	}
   476  
   477  	// Since this field is optional, we'll check to see if the pubkey has
   478  	// been specified or not.
   479  	if !bytes.Equal(shaChainPub[:], zeroPub[:]) {
   480  		s.ShaChainRootDesc.PubKey, err = secp256k1.ParsePubKey(
   481  			shaChainPub[:],
   482  		)
   483  		if err != nil {
   484  			return err
   485  		}
   486  	}
   487  
   488  	var shaKeyFam uint32
   489  	if err := lnwire.ReadElements(r, &shaKeyFam); err != nil {
   490  		return err
   491  	}
   492  	s.ShaChainRootDesc.KeyLocator.Family = keychain.KeyFamily(shaKeyFam)
   493  	err = lnwire.ReadElements(r, &s.ShaChainRootDesc.KeyLocator.Index)
   494  	if err != nil {
   495  		return err
   496  	}
   497  
   498  	if s.Version == ScriptEnforcedLeaseVersion {
   499  		if err := lnwire.ReadElement(r, &s.LeaseExpiry); err != nil {
   500  			return err
   501  		}
   502  	}
   503  
   504  	return nil
   505  }
   506  
   507  // UnpackFromReader is similar to Deserialize method, but it expects the passed
   508  // io.Reader to contain an encrypt SCB. Refer to the SerializeAndEncrypt method
   509  // for details w.r.t the encryption scheme used. If we're unable to decrypt the
   510  // payload for whatever reason (wrong key, wrong nonce, etc), then this method
   511  // will return an error.
   512  func (s *Single) UnpackFromReader(r io.Reader, keyRing keychain.KeyRing) error {
   513  	plaintext, err := decryptPayloadFromReader(r, keyRing)
   514  	if err != nil {
   515  		return err
   516  	}
   517  
   518  	// Finally, we'll pack the bytes into a reader to we can deserialize
   519  	// the plaintext bytes of the SCB.
   520  	backupReader := bytes.NewReader(plaintext)
   521  	return s.Deserialize(backupReader)
   522  }
   523  
   524  // PackStaticChanBackups accepts a set of existing open channels, and a
   525  // keychain.KeyRing, and returns a map of outpoints to the serialized+encrypted
   526  // static channel backups. The passed keyRing should be backed by the users
   527  // root HD seed in order to ensure full determinism.
   528  func PackStaticChanBackups(backups []Single,
   529  	keyRing keychain.KeyRing) (map[wire.OutPoint][]byte, error) {
   530  
   531  	packedBackups := make(map[wire.OutPoint][]byte)
   532  	for _, chanBackup := range backups {
   533  		chanPoint := chanBackup.FundingOutpoint
   534  
   535  		var b bytes.Buffer
   536  		err := chanBackup.PackToWriter(&b, keyRing)
   537  		if err != nil {
   538  			return nil, fmt.Errorf("unable to pack chan backup "+
   539  				"for %v: %v", chanPoint, err)
   540  		}
   541  
   542  		packedBackups[chanPoint] = b.Bytes()
   543  	}
   544  
   545  	return packedBackups, nil
   546  }
   547  
   548  // PackedSingles represents a series of fully packed SCBs. This may be the
   549  // combination of a series of individual SCBs in order to batch their
   550  // unpacking.
   551  type PackedSingles [][]byte
   552  
   553  // Unpack attempts to decrypt the passed set of encrypted SCBs and deserialize
   554  // each one into a new SCB struct. The passed keyRing should be backed by the
   555  // same HD seed as was used to encrypt the set of backups in the first place.
   556  // If we're unable to decrypt any of the back ups, then we'll return an error.
   557  func (p PackedSingles) Unpack(keyRing keychain.KeyRing) ([]Single, error) {
   558  
   559  	backups := make([]Single, len(p))
   560  	for i, encryptedBackup := range p {
   561  		var backup Single
   562  
   563  		backupReader := bytes.NewReader(encryptedBackup)
   564  		err := backup.UnpackFromReader(backupReader, keyRing)
   565  		if err != nil {
   566  			return nil, err
   567  		}
   568  
   569  		backups[i] = backup
   570  	}
   571  
   572  	return backups, nil
   573  }
   574  
   575  // TODO(roasbeef): make codec package?