github.com/decred/dcrlnd@v0.7.6/contractcourt/nursery_store.go (about)

     1  package contractcourt
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"github.com/decred/dcrd/chaincfg/chainhash"
     9  	"github.com/decred/dcrd/wire"
    10  	"github.com/decred/dcrlnd/channeldb"
    11  	"github.com/decred/dcrlnd/kvdb"
    12  )
    13  
    14  //	              Overview of Nursery Store Storage Hierarchy
    15  //
    16  //   CHAIN SEGMENTATION
    17  //
    18  //   The root directory of a nursery store is bucketed by the chain hash and
    19  //   the 'utxn' prefix. This allows multiple utxo nurseries for distinct chains
    20  //   to simultaneously use the same channel.DB instance. This is critical for
    21  //   providing replay protection and more to isolate chain-specific data in the
    22  //   multichain setting.
    23  //
    24  //   utxn<chain-hash>/
    25  //   |
    26  //   |   CHANNEL INDEX
    27  //   |
    28  //   |   The channel index contains a directory for each channel that has a
    29  //   |   non-zero number of outputs being tracked by the nursery store.
    30  //   |   Inside each channel directory are files containing serialized spendable
    31  //   |   outputs that are awaiting some state transition. The name of each file
    32  //   |   contains the outpoint of the spendable output in the file, and is
    33  //   |   prefixed with 4-byte state prefix, indicating whether the spendable
    34  //   |   output is a crib, preschool, or kindergarten, or graduated output. The
    35  //   |   nursery store supports the ability to enumerate all outputs for a
    36  //   |   particular channel, which is useful in constructing nursery reports.
    37  //   |
    38  //   ├── channel-index-key/
    39  //   │   ├── <chan-point-1>/                      <- CHANNEL BUCKET
    40  //   |   |   ├── <state-prefix><outpoint-1>: <spendable-output-1>
    41  //   |   |   └── <state-prefix><outpoint-2>: <spendable-output-2>
    42  //   │   ├── <chan-point-2>/
    43  //   |   |   └── <state-prefix><outpoint-3>: <spendable-output-3>
    44  //   │   └── <chan-point-3>/
    45  //   |       ├── <state-prefix><outpoint-4>: <spendable-output-4>
    46  //   |       └── <state-prefix><outpoint-5>: <spendable-output-5>
    47  //   |
    48  //   |   HEIGHT INDEX
    49  //   |
    50  //   |   The height index contains a directory for each height at which the
    51  //   |   nursery still has scheduled actions. If an output is a crib or
    52  //   |   kindergarten output, it will have an associated entry in the height
    53  //   |   index. Inside a particular height directory, the structure is similar
    54  //   |   to that of the channel index, containing multiple channel directories,
    55  //   |   each of which contains subdirectories named with a prefixed outpoint
    56  //   |   belonging to the channel. Enumerating these combinations yields a
    57  //   |   relative file path:
    58  //   |     e.g. <chan-point-3>/<prefix><outpoint-2>/
    59  //   |   that can be queried in the channel index to retrieve the serialized
    60  //   |   output.
    61  //   |
    62  //   └── height-index-key/
    63  //       ├── <height-1>/                             <- HEIGHT BUCKET
    64  //       |   ├── <chan-point-3>/                     <- HEIGHT-CHANNEL BUCKET
    65  //       |   |    ├── <state-prefix><outpoint-4>: "" <- PREFIXED OUTPOINT
    66  //       |   |    └── <state-prefix><outpoint-5>: ""
    67  //       |   ├── <chan-point-2>/
    68  //       |   |    └── <state-prefix><outpoint-3>: ""
    69  //       └── <height-2>/
    70  //           └── <chan-point-1>/
    71  //                └── <state-prefix><outpoint-1>: ""
    72  //                └── <state-prefix><outpoint-2>: ""
    73  
    74  // TODO(joostjager): Add database migration to clean up now unused last
    75  // graduated height and finalized txes. This also prevents people downgrading
    76  // and surprising the downgraded nursery with missing data.
    77  
    78  // NurseryStorer abstracts the persistent storage layer for the utxo nursery.
    79  // Concretely, it stores commitment and htlc outputs until any time-bounded
    80  // constraints have fully matured. The store exposes methods for enumerating its
    81  // contents, and persisting state transitions detected by the utxo nursery.
    82  type NurseryStorer interface {
    83  	// Incubate registers a set of CSV delayed outputs (incoming HTLC's on
    84  	// our commitment transaction, or a commitment output), and a slice of
    85  	// outgoing htlc outputs to be swept back into the user's wallet. The
    86  	// event is persisted to disk, such that the nursery can resume the
    87  	// incubation process after a potential crash.
    88  	Incubate([]kidOutput, []babyOutput) error
    89  
    90  	// CribToKinder atomically moves a babyOutput in the crib bucket to the
    91  	// kindergarten bucket. Baby outputs are outgoing HTLC's which require
    92  	// us to go to the second-layer to claim. The now mature kidOutput
    93  	// contained in the babyOutput will be stored as it waits out the
    94  	// kidOutput's CSV delay.
    95  	CribToKinder(*babyOutput) error
    96  
    97  	// PreschoolToKinder atomically moves a kidOutput from the preschool
    98  	// bucket to the kindergarten bucket. This transition should be executed
    99  	// after receiving confirmation of the preschool output. Incoming HTLC's
   100  	// we need to go to the second-layer to claim, and also our commitment
   101  	// outputs fall into this class.
   102  	//
   103  	// An additional parameter specifies the last graduated height. This is
   104  	// used in case of late registration. It schedules the output for sweep
   105  	// at the next epoch even though it has already expired earlier.
   106  	PreschoolToKinder(kid *kidOutput, lastGradHeight uint32) error
   107  
   108  	// GraduateKinder atomically moves an output at the provided height into
   109  	// the graduated status. This involves removing the kindergarten entries
   110  	// from both the height and channel indexes. The height bucket will be
   111  	// opportunistically pruned from the height index as outputs are
   112  	// removed.
   113  	GraduateKinder(height uint32, output *kidOutput) error
   114  
   115  	// FetchPreschools returns a list of all outputs currently stored in
   116  	// the preschool bucket.
   117  	FetchPreschools() ([]kidOutput, error)
   118  
   119  	// FetchClass returns a list of kindergarten and crib outputs whose
   120  	// timelocks expire at the given height.
   121  	FetchClass(height uint32) ([]kidOutput, []babyOutput, error)
   122  
   123  	// HeightsBelowOrEqual returns the lowest non-empty heights in the
   124  	// height index, that exist at or below the provided upper bound.
   125  	HeightsBelowOrEqual(height uint32) ([]uint32, error)
   126  
   127  	// ForChanOutputs iterates over all outputs being incubated for a
   128  	// particular channel point. This method accepts a callback that allows
   129  	// the caller to process each key-value pair. The key will be a prefixed
   130  	// outpoint, and the value will be the serialized bytes for an output,
   131  	// whose type should be inferred from the key's prefix.
   132  	ForChanOutputs(*wire.OutPoint, func([]byte, []byte) error, func()) error
   133  
   134  	// ListChannels returns all channels the nursery is currently tracking.
   135  	ListChannels() ([]wire.OutPoint, error)
   136  
   137  	// IsMatureChannel determines the whether or not all of the outputs in a
   138  	// particular channel bucket have been marked as graduated.
   139  	IsMatureChannel(*wire.OutPoint) (bool, error)
   140  
   141  	// RemoveChannel channel erases all entries from the channel bucket for
   142  	// the provided channel point, this method should only be called if
   143  	// IsMatureChannel indicates the channel is ready for removal.
   144  	RemoveChannel(*wire.OutPoint) error
   145  }
   146  
   147  var (
   148  	// utxnChainPrefix is used to prefix a particular chain hash and create
   149  	// the root-level, chain-segmented bucket for each nursery store.
   150  	utxnChainPrefix = []byte("utxn")
   151  
   152  	// channelIndexKey is a static key used to lookup the bucket containing
   153  	// all of the nursery's active channels.
   154  	channelIndexKey = []byte("channel-index")
   155  
   156  	// channelIndexKey is a static key used to retrieve a directory
   157  	// containing all heights for which the nursery will need to take
   158  	// action.
   159  	heightIndexKey = []byte("height-index")
   160  )
   161  
   162  // Defines the state prefixes that will be used to persistently track an
   163  // output's progress through the nursery.
   164  // NOTE: Each state prefix MUST be exactly 4 bytes in length, the nursery logic
   165  // depends on the ability to create keys for a different state by overwriting
   166  // an existing state prefix.
   167  var (
   168  	// cribPrefix is the state prefix given to htlc outputs waiting for
   169  	// their first-stage, absolute locktime to elapse.
   170  	cribPrefix = []byte("crib")
   171  
   172  	// psclPrefix is the state prefix given to commitment outputs awaiting
   173  	// the confirmation of the commitment transaction, as this solidifies
   174  	// the absolute height at which they can be spent.
   175  	psclPrefix = []byte("pscl")
   176  
   177  	// kndrPrefix is the state prefix given to all CSV delayed outputs,
   178  	// either from the commitment transaction, or a stage-one htlc
   179  	// transaction, whose maturity height has solidified. Outputs marked in
   180  	// this state are in their final stage of incubation within the nursery,
   181  	// and will be swept into the wallet after waiting out the relative
   182  	// timelock.
   183  	kndrPrefix = []byte("kndr")
   184  
   185  	// gradPrefix is the state prefix given to all outputs that have been
   186  	// completely incubated. Once all outputs have been marked as graduated,
   187  	// this serves as a persistent marker that the nursery should mark the
   188  	// channel fully closed in the channeldb.
   189  	gradPrefix = []byte("grad")
   190  )
   191  
   192  // prefixChainKey creates the root level keys for the nursery store. The keys
   193  // are comprised of a nursery-specific prefix and the intended chain hash that
   194  // this nursery store will be used for. This allows multiple nursery stores to
   195  // isolate their state when operating on multiple chains or forks.
   196  func prefixChainKey(sysPrefix []byte, hash *chainhash.Hash) ([]byte, error) {
   197  	// Create a buffer to which we will write the system prefix, e.g.
   198  	// "utxn", followed by the provided chain hash.
   199  	var pfxChainBuffer bytes.Buffer
   200  	if _, err := pfxChainBuffer.Write(sysPrefix); err != nil {
   201  		return nil, err
   202  	}
   203  
   204  	if _, err := pfxChainBuffer.Write(hash[:]); err != nil {
   205  		return nil, err
   206  	}
   207  
   208  	return pfxChainBuffer.Bytes(), nil
   209  }
   210  
   211  // prefixOutputKey creates a serialized key that prefixes the serialized
   212  // outpoint with the provided state prefix. The returned bytes will be of the
   213  // form <prefix><outpoint>.
   214  func prefixOutputKey(statePrefix []byte,
   215  	outpoint *wire.OutPoint) ([]byte, error) {
   216  
   217  	// Create a buffer to which we will first write the state prefix,
   218  	// followed by the outpoint.
   219  	var pfxOutputBuffer bytes.Buffer
   220  	if _, err := pfxOutputBuffer.Write(statePrefix); err != nil {
   221  		return nil, err
   222  	}
   223  
   224  	err := writeOutpoint(&pfxOutputBuffer, outpoint)
   225  	if err != nil {
   226  		return nil, err
   227  	}
   228  
   229  	return pfxOutputBuffer.Bytes(), nil
   230  }
   231  
   232  // NurseryStore is a concrete instantiation of a NurseryStore that is backed by
   233  // a channeldb.DB instance.
   234  type NurseryStore struct {
   235  	chainHash chainhash.Hash
   236  	db        *channeldb.DB
   237  
   238  	pfxChainKey []byte
   239  }
   240  
   241  // NewNurseryStore accepts a chain hash and a channeldb.DB instance, returning
   242  // an instance of NurseryStore who's database is properly segmented for the
   243  // given chain.
   244  func NewNurseryStore(chainHash *chainhash.Hash,
   245  	db *channeldb.DB) (*NurseryStore, error) {
   246  
   247  	// Prefix the provided chain hash with "utxn" to create the key for the
   248  	// nursery store's root bucket, ensuring each one has proper chain
   249  	// segmentation.
   250  	pfxChainKey, err := prefixChainKey(utxnChainPrefix, chainHash)
   251  	if err != nil {
   252  		return nil, err
   253  	}
   254  
   255  	return &NurseryStore{
   256  		chainHash:   *chainHash,
   257  		db:          db,
   258  		pfxChainKey: pfxChainKey,
   259  	}, nil
   260  }
   261  
   262  // Incubate persists the beginning of the incubation process for the
   263  // CSV-delayed outputs (commitment and incoming HTLC's), commitment output and
   264  // a list of outgoing two-stage htlc outputs.
   265  func (ns *NurseryStore) Incubate(kids []kidOutput, babies []babyOutput) error {
   266  	return kvdb.Update(ns.db, func(tx kvdb.RwTx) error {
   267  		// If we have any kid outputs to incubate, then we'll attempt
   268  		// to add each of them to the nursery store. Any duplicate
   269  		// outputs will be ignored.
   270  		for _, kid := range kids {
   271  			if err := ns.enterPreschool(tx, &kid); err != nil {
   272  				return err
   273  			}
   274  		}
   275  
   276  		// Next, we'll Add all htlc outputs to the crib bucket.
   277  		// Similarly, we'll ignore any outputs that have already been
   278  		// inserted.
   279  		for _, baby := range babies {
   280  			if err := ns.enterCrib(tx, &baby); err != nil {
   281  				return err
   282  			}
   283  		}
   284  
   285  		return nil
   286  	}, func() {})
   287  }
   288  
   289  // CribToKinder atomically moves a babyOutput in the crib bucket to the
   290  // kindergarten bucket. The now mature kidOutput contained in the babyOutput
   291  // will be stored as it waits out the kidOutput's CSV delay.
   292  func (ns *NurseryStore) CribToKinder(bby *babyOutput) error {
   293  	return kvdb.Update(ns.db, func(tx kvdb.RwTx) error {
   294  
   295  		// First, retrieve or create the channel bucket corresponding to
   296  		// the baby output's origin channel point.
   297  		chanPoint := bby.OriginChanPoint()
   298  		chanBucket, err := ns.createChannelBucket(tx, chanPoint)
   299  		if err != nil {
   300  			return err
   301  		}
   302  
   303  		// The babyOutput should currently be stored in the crib bucket.
   304  		// So, we create a key that prefixes the babyOutput's outpoint
   305  		// with the crib prefix, allowing us to reference it in the
   306  		// store.
   307  		pfxOutputKey, err := prefixOutputKey(cribPrefix, bby.OutPoint())
   308  		if err != nil {
   309  			return err
   310  		}
   311  
   312  		// Since the babyOutput is being moved to the kindergarten
   313  		// bucket, we remove the entry from the channel bucket under the
   314  		// crib-prefixed outpoint key.
   315  		if err := chanBucket.Delete(pfxOutputKey); err != nil {
   316  			return err
   317  		}
   318  
   319  		// Remove the crib output's entry in the height index.
   320  		err = ns.removeOutputFromHeight(tx, bby.expiry, chanPoint,
   321  			pfxOutputKey)
   322  		if err != nil {
   323  			return err
   324  		}
   325  
   326  		// Since we are moving this output from the crib bucket to the
   327  		// kindergarten bucket, we overwrite the existing prefix of this
   328  		// key with the kindergarten prefix.
   329  		copy(pfxOutputKey, kndrPrefix)
   330  
   331  		// Now, serialize babyOutput's encapsulated kidOutput such that
   332  		// it can be written to the channel bucket under the new
   333  		// kindergarten-prefixed key.
   334  		var kidBuffer bytes.Buffer
   335  		if err := bby.kidOutput.Encode(&kidBuffer); err != nil {
   336  			return err
   337  		}
   338  		kidBytes := kidBuffer.Bytes()
   339  
   340  		// Persist the serialized kidOutput under the
   341  		// kindergarten-prefixed outpoint key.
   342  		if err := chanBucket.Put(pfxOutputKey, kidBytes); err != nil {
   343  			return err
   344  		}
   345  
   346  		// Now, compute the height at which this kidOutput's CSV delay
   347  		// will expire.  This is done by adding the required delay to
   348  		// the block height at which the output was confirmed.
   349  		maturityHeight := bby.ConfHeight() + bby.BlocksToMaturity()
   350  
   351  		// Retrieve or create a height-channel bucket corresponding to
   352  		// the kidOutput's maturity height.
   353  		hghtChanBucketCsv, err := ns.createHeightChanBucket(tx,
   354  			maturityHeight, chanPoint)
   355  		if err != nil {
   356  			return err
   357  		}
   358  
   359  		utxnLog.Tracef("Transitioning (crib -> baby) output for "+
   360  			"chan_point=%v at height_index=%v", chanPoint,
   361  			maturityHeight)
   362  
   363  		// Register the kindergarten output's prefixed output key in the
   364  		// height-channel bucket corresponding to its maturity height.
   365  		// This informs the utxo nursery that it should attempt to spend
   366  		// this output when the blockchain reaches the maturity height.
   367  		return hghtChanBucketCsv.Put(pfxOutputKey, []byte{})
   368  	}, func() {})
   369  }
   370  
   371  // PreschoolToKinder atomically moves a kidOutput from the preschool bucket to
   372  // the kindergarten bucket. This transition should be executed after receiving
   373  // confirmation of the preschool output's commitment transaction.
   374  func (ns *NurseryStore) PreschoolToKinder(kid *kidOutput,
   375  	lastGradHeight uint32) error {
   376  
   377  	return kvdb.Update(ns.db, func(tx kvdb.RwTx) error {
   378  		// Create or retrieve the channel bucket corresponding to the
   379  		// kid output's origin channel point.
   380  		chanPoint := kid.OriginChanPoint()
   381  		chanBucket, err := ns.createChannelBucket(tx, chanPoint)
   382  		if err != nil {
   383  			return err
   384  		}
   385  
   386  		// First, we will attempt to remove the existing serialized
   387  		// output from the channel bucket, where the kid's outpoint will
   388  		// be prefixed by a preschool prefix.
   389  
   390  		// Generate the key of existing serialized kid output by
   391  		// prefixing its outpoint with the preschool prefix...
   392  		pfxOutputKey, err := prefixOutputKey(psclPrefix, kid.OutPoint())
   393  		if err != nil {
   394  			return err
   395  		}
   396  
   397  		// And remove the old serialized output from the database.
   398  		if err := chanBucket.Delete(pfxOutputKey); err != nil {
   399  			return err
   400  		}
   401  
   402  		// Next, we will write the provided kid outpoint to the channel
   403  		// bucket, using a key prefixed by the kindergarten prefix.
   404  
   405  		// Convert the preschool prefix key into a kindergarten key for
   406  		// the same outpoint.
   407  		copy(pfxOutputKey, kndrPrefix)
   408  
   409  		// Reserialize the kid here to capture any differences in the
   410  		// new and old kid output, such as the confirmation height.
   411  		var kidBuffer bytes.Buffer
   412  		if err := kid.Encode(&kidBuffer); err != nil {
   413  			return err
   414  		}
   415  		kidBytes := kidBuffer.Bytes()
   416  
   417  		// And store the kid output in its channel bucket using the
   418  		// kindergarten prefixed key.
   419  		if err := chanBucket.Put(pfxOutputKey, kidBytes); err != nil {
   420  			return err
   421  		}
   422  
   423  		// If this output has an absolute time lock, then we'll set the
   424  		// maturity height directly.
   425  		var maturityHeight uint32
   426  		if kid.BlocksToMaturity() == 0 {
   427  			maturityHeight = kid.absoluteMaturity
   428  		} else {
   429  			// Otherwise, since the CSV delay on the kid output has
   430  			// now begun ticking, we must insert a record of in the
   431  			// height index to remind us to revisit this output
   432  			// once it has fully matured.
   433  			//
   434  			// Compute the maturity height, by adding the output's
   435  			// CSV delay to its confirmation height.
   436  			maturityHeight = kid.ConfHeight() + kid.BlocksToMaturity()
   437  		}
   438  
   439  		if maturityHeight <= lastGradHeight {
   440  			utxnLog.Debugf("Late Registration for kid output=%v "+
   441  				"detected: class_height=%v, "+
   442  				"last_graduated_height=%v", kid.OutPoint(),
   443  				maturityHeight, lastGradHeight)
   444  
   445  			maturityHeight = lastGradHeight + 1
   446  		}
   447  
   448  		utxnLog.Infof("Transitioning (crib -> kid) output for "+
   449  			"chan_point=%v at height_index=%v", chanPoint,
   450  			maturityHeight)
   451  
   452  		// Create or retrieve the height-channel bucket for this
   453  		// channel. This method will first create a height bucket for
   454  		// the given maturity height if none exists.
   455  		hghtChanBucket, err := ns.createHeightChanBucket(tx,
   456  			maturityHeight, chanPoint)
   457  		if err != nil {
   458  			return err
   459  		}
   460  
   461  		// Finally, we touch a key in the height-channel created above.
   462  		// The key is named using a kindergarten prefixed key, signaling
   463  		// that this CSV delayed output will be ready to broadcast at
   464  		// the maturity height, after a brief period of incubation.
   465  		return hghtChanBucket.Put(pfxOutputKey, []byte{})
   466  	}, func() {})
   467  }
   468  
   469  // GraduateKinder atomically moves an output at the provided height into the
   470  // graduated status. This involves removing the kindergarten entries from both
   471  // the height and channel indexes. The height bucket will be opportunistically
   472  // pruned from the height index as outputs are removed.
   473  func (ns *NurseryStore) GraduateKinder(height uint32, kid *kidOutput) error {
   474  	return kvdb.Update(ns.db, func(tx kvdb.RwTx) error {
   475  
   476  		hghtBucket := ns.getHeightBucket(tx, height)
   477  		if hghtBucket == nil {
   478  			// Nothing to delete, bucket has already been removed.
   479  			return nil
   480  		}
   481  
   482  		// For the kindergarten output, delete its entry from the
   483  		// height and channel index, and create a new grad output in the
   484  		// channel index.
   485  		outpoint := kid.OutPoint()
   486  		chanPoint := kid.OriginChanPoint()
   487  
   488  		// Construct the key under which the output is
   489  		// currently stored height and channel indexes.
   490  		pfxOutputKey, err := prefixOutputKey(kndrPrefix,
   491  			outpoint)
   492  		if err != nil {
   493  			return err
   494  		}
   495  
   496  		// Remove the grad output's entry in the height
   497  		// index.
   498  		err = ns.removeOutputFromHeight(tx, height,
   499  			chanPoint, pfxOutputKey)
   500  		if err != nil {
   501  			return err
   502  		}
   503  
   504  		chanBucket := ns.getChannelBucketWrite(tx, chanPoint)
   505  		if chanBucket == nil {
   506  			return ErrContractNotFound
   507  		}
   508  
   509  		// Remove previous output with kindergarten
   510  		// prefix.
   511  		err = chanBucket.Delete(pfxOutputKey)
   512  		if err != nil {
   513  			return err
   514  		}
   515  
   516  		// Convert kindergarten key to graduate key.
   517  		copy(pfxOutputKey, gradPrefix)
   518  
   519  		var gradBuffer bytes.Buffer
   520  		if err := kid.Encode(&gradBuffer); err != nil {
   521  			return err
   522  		}
   523  
   524  		// Insert serialized output into channel bucket
   525  		// using graduate-prefixed key.
   526  		return chanBucket.Put(pfxOutputKey,
   527  			gradBuffer.Bytes())
   528  	}, func() {})
   529  }
   530  
   531  // FetchClass returns a list of babyOutputs in the crib bucket whose CLTV
   532  // delay expires at the provided block height.
   533  // FetchClass returns a list of the kindergarten and crib outputs whose timeouts
   534  // are expiring
   535  func (ns *NurseryStore) FetchClass(
   536  	height uint32) ([]kidOutput, []babyOutput, error) {
   537  
   538  	// Construct list of all crib and kindergarten outputs that need to be
   539  	// processed at the provided block height.
   540  	var kids []kidOutput
   541  	var babies []babyOutput
   542  	if err := kvdb.View(ns.db, func(tx kvdb.RTx) error {
   543  		// Append each crib output to our list of babyOutputs.
   544  		if err := ns.forEachHeightPrefix(tx, cribPrefix, height,
   545  			func(buf []byte) error {
   546  
   547  				// We will attempt to deserialize all outputs
   548  				// stored with the crib prefix into babyOutputs,
   549  				// since this is the expected type that would
   550  				// have been serialized previously.
   551  				var baby babyOutput
   552  				babyReader := bytes.NewReader(buf)
   553  				if err := baby.Decode(babyReader); err != nil {
   554  					return err
   555  				}
   556  
   557  				babies = append(babies, baby)
   558  
   559  				return nil
   560  
   561  			},
   562  		); err != nil {
   563  			return err
   564  		}
   565  
   566  		// Append each kindergarten output to our list of kidOutputs.
   567  		return ns.forEachHeightPrefix(tx, kndrPrefix, height,
   568  			func(buf []byte) error {
   569  				// We will attempt to deserialize all outputs
   570  				// stored with the kindergarten prefix into
   571  				// kidOutputs, since this is the expected type
   572  				// that would have been serialized previously.
   573  				var kid kidOutput
   574  				kidReader := bytes.NewReader(buf)
   575  				if err := kid.Decode(kidReader); err != nil {
   576  					return err
   577  				}
   578  
   579  				kids = append(kids, kid)
   580  
   581  				return nil
   582  
   583  			})
   584  
   585  	}, func() {
   586  		kids = nil
   587  		babies = nil
   588  	}); err != nil {
   589  		return nil, nil, err
   590  	}
   591  
   592  	return kids, babies, nil
   593  }
   594  
   595  // FetchPreschools returns a list of all outputs currently stored in the
   596  // preschool bucket.
   597  func (ns *NurseryStore) FetchPreschools() ([]kidOutput, error) {
   598  	var kids []kidOutput
   599  	if err := kvdb.View(ns.db, func(tx kvdb.RTx) error {
   600  
   601  		// Retrieve the existing chain bucket for this nursery store.
   602  		chainBucket := tx.ReadBucket(ns.pfxChainKey)
   603  		if chainBucket == nil {
   604  			return nil
   605  		}
   606  
   607  		// Load the existing channel index from the chain bucket.
   608  		chanIndex := chainBucket.NestedReadBucket(channelIndexKey)
   609  		if chanIndex == nil {
   610  			return nil
   611  		}
   612  
   613  		// Construct a list of all channels in the channel index that
   614  		// are currently being tracked by the nursery store.
   615  		var activeChannels [][]byte
   616  		if err := chanIndex.ForEach(func(chanBytes, _ []byte) error {
   617  			activeChannels = append(activeChannels, chanBytes)
   618  			return nil
   619  		}); err != nil {
   620  			return err
   621  		}
   622  
   623  		// Iterate over all of the accumulated channels, and do a prefix
   624  		// scan inside of each channel bucket. Each output found that
   625  		// has a preschool prefix will be deserialized into a kidOutput,
   626  		// and added to our list of preschool outputs to return to the
   627  		// caller.
   628  		for _, chanBytes := range activeChannels {
   629  			// Retrieve the channel bucket associated with this
   630  			// channel.
   631  			chanBucket := chanIndex.NestedReadBucket(chanBytes)
   632  			if chanBucket == nil {
   633  				continue
   634  			}
   635  
   636  			// All of the outputs of interest will start with the
   637  			// "pscl" prefix. So, we will perform a prefix scan of
   638  			// the channel bucket to efficiently enumerate all the
   639  			// desired outputs.
   640  			c := chanBucket.ReadCursor()
   641  			for k, v := c.Seek(psclPrefix); bytes.HasPrefix(
   642  				k, psclPrefix); k, v = c.Next() {
   643  
   644  				// Deserialize each output as a kidOutput, since
   645  				// this should have been the type that was
   646  				// serialized when it was written to disk.
   647  				var psclOutput kidOutput
   648  				psclReader := bytes.NewReader(v)
   649  				err := psclOutput.Decode(psclReader)
   650  				if err != nil {
   651  					return err
   652  				}
   653  
   654  				// Add the deserialized output to our list of
   655  				// preschool outputs.
   656  				kids = append(kids, psclOutput)
   657  			}
   658  		}
   659  
   660  		return nil
   661  	}, func() {
   662  		kids = nil
   663  	}); err != nil {
   664  		return nil, err
   665  	}
   666  
   667  	return kids, nil
   668  }
   669  
   670  // HeightsBelowOrEqual returns a slice of all non-empty heights in the height
   671  // index at or below the provided upper bound.
   672  func (ns *NurseryStore) HeightsBelowOrEqual(height uint32) ([]uint32, error) {
   673  	var activeHeights []uint32
   674  	err := kvdb.View(ns.db, func(tx kvdb.RTx) error {
   675  		// Ensure that the chain bucket for this nursery store exists.
   676  		chainBucket := tx.ReadBucket(ns.pfxChainKey)
   677  		if chainBucket == nil {
   678  			return nil
   679  		}
   680  
   681  		// Ensure that the height index has been properly initialized for this
   682  		// chain.
   683  		hghtIndex := chainBucket.NestedReadBucket(heightIndexKey)
   684  		if hghtIndex == nil {
   685  			return nil
   686  		}
   687  
   688  		// Serialize the provided height, as this will form the name of the
   689  		// bucket.
   690  		var lower, upper [4]byte
   691  		byteOrder.PutUint32(upper[:], height)
   692  
   693  		c := hghtIndex.ReadCursor()
   694  		for k, _ := c.Seek(lower[:]); bytes.Compare(k, upper[:]) <= 0 &&
   695  			len(k) == 4; k, _ = c.Next() {
   696  
   697  			activeHeights = append(activeHeights, byteOrder.Uint32(k))
   698  		}
   699  
   700  		return nil
   701  	}, func() {
   702  		activeHeights = nil
   703  	})
   704  	if err != nil {
   705  		return nil, err
   706  	}
   707  
   708  	return activeHeights, nil
   709  }
   710  
   711  // ForChanOutputs iterates over all outputs being incubated for a particular
   712  // channel point. This method accepts a callback that allows the caller to
   713  // process each key-value pair. The key will be a prefixed outpoint, and the
   714  // value will be the serialized bytes for an output, whose type should be
   715  // inferred from the key's prefix.
   716  // NOTE: The callback should not modify the provided byte slices and is
   717  // preferably non-blocking.
   718  func (ns *NurseryStore) ForChanOutputs(chanPoint *wire.OutPoint,
   719  	callback func([]byte, []byte) error, reset func()) error {
   720  
   721  	return kvdb.View(ns.db, func(tx kvdb.RTx) error {
   722  		return ns.forChanOutputs(tx, chanPoint, callback)
   723  	}, reset)
   724  }
   725  
   726  // ListChannels returns all channels the nursery is currently tracking.
   727  func (ns *NurseryStore) ListChannels() ([]wire.OutPoint, error) {
   728  	var activeChannels []wire.OutPoint
   729  	if err := kvdb.View(ns.db, func(tx kvdb.RTx) error {
   730  		// Retrieve the existing chain bucket for this nursery store.
   731  		chainBucket := tx.ReadBucket(ns.pfxChainKey)
   732  		if chainBucket == nil {
   733  			return nil
   734  		}
   735  
   736  		// Retrieve the existing channel index.
   737  		chanIndex := chainBucket.NestedReadBucket(channelIndexKey)
   738  		if chanIndex == nil {
   739  			return nil
   740  		}
   741  
   742  		return chanIndex.ForEach(func(chanBytes, _ []byte) error {
   743  			var chanPoint wire.OutPoint
   744  			err := readOutpoint(bytes.NewReader(chanBytes), &chanPoint)
   745  			if err != nil {
   746  				return err
   747  			}
   748  
   749  			activeChannels = append(activeChannels, chanPoint)
   750  
   751  			return nil
   752  		})
   753  	}, func() {
   754  		activeChannels = nil
   755  	}); err != nil {
   756  		return nil, err
   757  	}
   758  
   759  	return activeChannels, nil
   760  }
   761  
   762  // IsMatureChannel determines the whether or not all of the outputs in a
   763  // particular channel bucket have been marked as graduated.
   764  func (ns *NurseryStore) IsMatureChannel(chanPoint *wire.OutPoint) (bool, error) {
   765  	err := kvdb.View(ns.db, func(tx kvdb.RTx) error {
   766  		// Iterate over the contents of the channel bucket, computing
   767  		// both total number of outputs, and those that have the grad
   768  		// prefix.
   769  		return ns.forChanOutputs(tx, chanPoint,
   770  			func(pfxKey, _ []byte) error {
   771  				if !bytes.HasPrefix(pfxKey, gradPrefix) {
   772  					return ErrImmatureChannel
   773  				}
   774  				return nil
   775  			})
   776  
   777  	}, func() {})
   778  	if err != nil && err != ErrImmatureChannel {
   779  		return false, err
   780  	}
   781  
   782  	return err == nil, nil
   783  }
   784  
   785  // ErrImmatureChannel signals a channel cannot be removed because not all of its
   786  // outputs have graduated.
   787  var ErrImmatureChannel = errors.New("cannot remove immature channel, " +
   788  	"still has ungraduated outputs")
   789  
   790  // RemoveChannel channel erases all entries from the channel bucket for the
   791  // provided channel point.
   792  // NOTE: The channel's entries in the height index are assumed to be removed.
   793  func (ns *NurseryStore) RemoveChannel(chanPoint *wire.OutPoint) error {
   794  	return kvdb.Update(ns.db, func(tx kvdb.RwTx) error {
   795  		// Retrieve the existing chain bucket for this nursery store.
   796  		chainBucket := tx.ReadWriteBucket(ns.pfxChainKey)
   797  		if chainBucket == nil {
   798  			return nil
   799  		}
   800  
   801  		// Retrieve the channel index stored in the chain bucket.
   802  		chanIndex := chainBucket.NestedReadWriteBucket(channelIndexKey)
   803  		if chanIndex == nil {
   804  			return nil
   805  		}
   806  
   807  		// Serialize the provided channel point, such that we can delete
   808  		// the mature channel bucket.
   809  		var chanBuffer bytes.Buffer
   810  		if err := writeOutpoint(&chanBuffer, chanPoint); err != nil {
   811  			return err
   812  		}
   813  		chanBytes := chanBuffer.Bytes()
   814  
   815  		err := ns.forChanOutputs(tx, chanPoint, func(k, v []byte) error {
   816  			if !bytes.HasPrefix(k, gradPrefix) {
   817  				return ErrImmatureChannel
   818  			}
   819  
   820  			// Construct a kindergarten prefixed key, since this
   821  			// would have been the preceding state for a grad
   822  			// output.
   823  			kndrKey := make([]byte, len(k))
   824  			copy(kndrKey, k)
   825  			copy(kndrKey[:4], kndrPrefix)
   826  
   827  			// Decode each to retrieve the output's maturity height.
   828  			var kid kidOutput
   829  			if err := kid.Decode(bytes.NewReader(v)); err != nil {
   830  				return err
   831  			}
   832  
   833  			maturityHeight := kid.ConfHeight() + kid.BlocksToMaturity()
   834  
   835  			hghtBucket := ns.getHeightBucketWrite(tx, maturityHeight)
   836  			if hghtBucket == nil {
   837  				return nil
   838  			}
   839  
   840  			return removeBucketIfExists(hghtBucket, chanBytes)
   841  		})
   842  		if err != nil {
   843  			return err
   844  		}
   845  
   846  		return removeBucketIfExists(chanIndex, chanBytes)
   847  	}, func() {})
   848  }
   849  
   850  // Helper Methods
   851  
   852  // enterCrib accepts a new htlc output that the nursery will incubate through
   853  // its two-stage process of sweeping funds back to the user's wallet. These
   854  // outputs are persisted in the nursery store in the crib state, and will be
   855  // revisited after the first-stage output's CLTV has expired.
   856  func (ns *NurseryStore) enterCrib(tx kvdb.RwTx, baby *babyOutput) error {
   857  	// First, retrieve or create the channel bucket corresponding to the
   858  	// baby output's origin channel point.
   859  	chanPoint := baby.OriginChanPoint()
   860  	chanBucket, err := ns.createChannelBucket(tx, chanPoint)
   861  	if err != nil {
   862  		return err
   863  	}
   864  
   865  	// Since we are inserting this output into the crib bucket, we create a
   866  	// key that prefixes the baby output's outpoint with the crib prefix.
   867  	pfxOutputKey, err := prefixOutputKey(cribPrefix, baby.OutPoint())
   868  	if err != nil {
   869  		return err
   870  	}
   871  
   872  	// We'll first check that we don't already have an entry for this
   873  	// output. If we do, then we can exit early.
   874  	if rawBytes := chanBucket.Get(pfxOutputKey); rawBytes != nil {
   875  		return nil
   876  	}
   877  
   878  	// Next, retrieve or create the height-channel bucket located in the
   879  	// height bucket corresponding to the baby output's CLTV expiry height.
   880  
   881  	// TODO: Handle late registration.
   882  	hghtChanBucket, err := ns.createHeightChanBucket(tx,
   883  		baby.expiry, chanPoint)
   884  	if err != nil {
   885  		return err
   886  	}
   887  
   888  	// Serialize the baby output so that it can be written to the
   889  	// underlying key-value store.
   890  	var babyBuffer bytes.Buffer
   891  	if err := baby.Encode(&babyBuffer); err != nil {
   892  		return err
   893  	}
   894  	babyBytes := babyBuffer.Bytes()
   895  
   896  	// Now, insert the serialized output into its channel bucket under the
   897  	// prefixed key created above.
   898  	if err := chanBucket.Put(pfxOutputKey, babyBytes); err != nil {
   899  		return err
   900  	}
   901  
   902  	// Finally, create a corresponding bucket in the height-channel bucket
   903  	// for this crib output. The existence of this bucket indicates that
   904  	// the serialized output can be retrieved from the channel bucket using
   905  	// the same prefix key.
   906  	return hghtChanBucket.Put(pfxOutputKey, []byte{})
   907  }
   908  
   909  // enterPreschool accepts a new commitment output that the nursery will incubate
   910  // through a single stage before sweeping. Outputs are stored in the preschool
   911  // bucket until the commitment transaction has been confirmed, at which point
   912  // they will be moved to the kindergarten bucket.
   913  func (ns *NurseryStore) enterPreschool(tx kvdb.RwTx, kid *kidOutput) error {
   914  	// First, retrieve or create the channel bucket corresponding to the
   915  	// baby output's origin channel point.
   916  	chanPoint := kid.OriginChanPoint()
   917  	chanBucket, err := ns.createChannelBucket(tx, chanPoint)
   918  	if err != nil {
   919  		return err
   920  	}
   921  
   922  	// Since the kidOutput is being inserted into the preschool bucket, we
   923  	// create a key that prefixes its outpoint with the preschool prefix.
   924  	pfxOutputKey, err := prefixOutputKey(psclPrefix, kid.OutPoint())
   925  	if err != nil {
   926  		return err
   927  	}
   928  
   929  	// We'll first check if an entry for this key is already stored. If so,
   930  	// then we'll ignore this request, and return a nil error.
   931  	if rawBytes := chanBucket.Get(pfxOutputKey); rawBytes != nil {
   932  		return nil
   933  	}
   934  
   935  	// Serialize the kidOutput and insert it into the channel bucket.
   936  	var kidBuffer bytes.Buffer
   937  	if err := kid.Encode(&kidBuffer); err != nil {
   938  		return err
   939  	}
   940  
   941  	return chanBucket.Put(pfxOutputKey, kidBuffer.Bytes())
   942  }
   943  
   944  // createChannelBucket creates or retrieves a channel bucket for the provided
   945  // channel point.
   946  func (ns *NurseryStore) createChannelBucket(tx kvdb.RwTx,
   947  	chanPoint *wire.OutPoint) (kvdb.RwBucket, error) {
   948  
   949  	// Ensure that the chain bucket for this nursery store exists.
   950  	chainBucket, err := tx.CreateTopLevelBucket(ns.pfxChainKey)
   951  	if err != nil {
   952  		return nil, err
   953  	}
   954  
   955  	// Ensure that the channel index has been properly initialized for this
   956  	// chain.
   957  	chanIndex, err := chainBucket.CreateBucketIfNotExists(channelIndexKey)
   958  	if err != nil {
   959  		return nil, err
   960  	}
   961  
   962  	// Serialize the provided channel point, as this provides the name of
   963  	// the channel bucket of interest.
   964  	var chanBuffer bytes.Buffer
   965  	if err := writeOutpoint(&chanBuffer, chanPoint); err != nil {
   966  		return nil, err
   967  	}
   968  
   969  	// Finally, create or retrieve the channel bucket using the serialized
   970  	// key.
   971  	return chanIndex.CreateBucketIfNotExists(chanBuffer.Bytes())
   972  }
   973  
   974  // getChannelBucket retrieves an existing channel bucket from the nursery store,
   975  // using the given channel point.  If the bucket does not exist, or any bucket
   976  // along its path does not exist, a nil value is returned.
   977  func (ns *NurseryStore) getChannelBucket(tx kvdb.RTx,
   978  	chanPoint *wire.OutPoint) kvdb.RBucket {
   979  
   980  	// Retrieve the existing chain bucket for this nursery store.
   981  	chainBucket := tx.ReadBucket(ns.pfxChainKey)
   982  	if chainBucket == nil {
   983  		return nil
   984  	}
   985  
   986  	// Retrieve the existing channel index.
   987  	chanIndex := chainBucket.NestedReadBucket(channelIndexKey)
   988  	if chanIndex == nil {
   989  		return nil
   990  	}
   991  
   992  	// Serialize the provided channel point and return the bucket matching
   993  	// the serialized key.
   994  	var chanBuffer bytes.Buffer
   995  	if err := writeOutpoint(&chanBuffer, chanPoint); err != nil {
   996  		return nil
   997  	}
   998  
   999  	return chanIndex.NestedReadBucket(chanBuffer.Bytes())
  1000  }
  1001  
  1002  // getChannelBucketWrite retrieves an existing channel bucket from the nursery store,
  1003  // using the given channel point.  If the bucket does not exist, or any bucket
  1004  // along its path does not exist, a nil value is returned.
  1005  func (ns *NurseryStore) getChannelBucketWrite(tx kvdb.RwTx,
  1006  	chanPoint *wire.OutPoint) kvdb.RwBucket {
  1007  
  1008  	// Retrieve the existing chain bucket for this nursery store.
  1009  	chainBucket := tx.ReadWriteBucket(ns.pfxChainKey)
  1010  	if chainBucket == nil {
  1011  		return nil
  1012  	}
  1013  
  1014  	// Retrieve the existing channel index.
  1015  	chanIndex := chainBucket.NestedReadWriteBucket(channelIndexKey)
  1016  	if chanIndex == nil {
  1017  		return nil
  1018  	}
  1019  
  1020  	// Serialize the provided channel point and return the bucket matching
  1021  	// the serialized key.
  1022  	var chanBuffer bytes.Buffer
  1023  	if err := writeOutpoint(&chanBuffer, chanPoint); err != nil {
  1024  		return nil
  1025  	}
  1026  
  1027  	return chanIndex.NestedReadWriteBucket(chanBuffer.Bytes())
  1028  }
  1029  
  1030  // createHeightBucket creates or retrieves an existing bucket from the height
  1031  // index, corresponding to the provided height.
  1032  func (ns *NurseryStore) createHeightBucket(tx kvdb.RwTx,
  1033  	height uint32) (kvdb.RwBucket, error) {
  1034  
  1035  	// Ensure that the chain bucket for this nursery store exists.
  1036  	chainBucket, err := tx.CreateTopLevelBucket(ns.pfxChainKey)
  1037  	if err != nil {
  1038  		return nil, err
  1039  	}
  1040  
  1041  	// Ensure that the height index has been properly initialized for this
  1042  	// chain.
  1043  	hghtIndex, err := chainBucket.CreateBucketIfNotExists(heightIndexKey)
  1044  	if err != nil {
  1045  		return nil, err
  1046  	}
  1047  
  1048  	// Serialize the provided height, as this will form the name of the
  1049  	// bucket.
  1050  	var heightBytes [4]byte
  1051  	byteOrder.PutUint32(heightBytes[:], height)
  1052  
  1053  	// Finally, create or retrieve the bucket in question.
  1054  	return hghtIndex.CreateBucketIfNotExists(heightBytes[:])
  1055  }
  1056  
  1057  // getHeightBucketPath retrieves an existing height bucket from the nursery
  1058  // store, using the provided block height. If the bucket does not exist, or any
  1059  // bucket along its path does not exist, a nil value is returned.
  1060  func (ns *NurseryStore) getHeightBucketPath(tx kvdb.RTx,
  1061  	height uint32) (kvdb.RBucket, kvdb.RBucket, kvdb.RBucket) {
  1062  
  1063  	// Retrieve the existing chain bucket for this nursery store.
  1064  	chainBucket := tx.ReadBucket(ns.pfxChainKey)
  1065  	if chainBucket == nil {
  1066  		return nil, nil, nil
  1067  	}
  1068  
  1069  	// Retrieve the existing channel index.
  1070  	hghtIndex := chainBucket.NestedReadBucket(heightIndexKey)
  1071  	if hghtIndex == nil {
  1072  		return nil, nil, nil
  1073  	}
  1074  
  1075  	// Serialize the provided block height and return the bucket matching
  1076  	// the serialized key.
  1077  	var heightBytes [4]byte
  1078  	byteOrder.PutUint32(heightBytes[:], height)
  1079  
  1080  	return chainBucket, hghtIndex, hghtIndex.NestedReadBucket(heightBytes[:])
  1081  }
  1082  
  1083  // getHeightBucketPathWrite retrieves an existing height bucket from the nursery
  1084  // store, using the provided block height. If the bucket does not exist, or any
  1085  // bucket along its path does not exist, a nil value is returned.
  1086  func (ns *NurseryStore) getHeightBucketPathWrite(tx kvdb.RwTx,
  1087  	height uint32) (kvdb.RwBucket, kvdb.RwBucket, kvdb.RwBucket) {
  1088  
  1089  	// Retrieve the existing chain bucket for this nursery store.
  1090  	chainBucket := tx.ReadWriteBucket(ns.pfxChainKey)
  1091  	if chainBucket == nil {
  1092  		return nil, nil, nil
  1093  	}
  1094  
  1095  	// Retrieve the existing channel index.
  1096  	hghtIndex := chainBucket.NestedReadWriteBucket(heightIndexKey)
  1097  	if hghtIndex == nil {
  1098  		return nil, nil, nil
  1099  	}
  1100  
  1101  	// Serialize the provided block height and return the bucket matching
  1102  	// the serialized key.
  1103  	var heightBytes [4]byte
  1104  	byteOrder.PutUint32(heightBytes[:], height)
  1105  
  1106  	return chainBucket, hghtIndex, hghtIndex.NestedReadWriteBucket(
  1107  		heightBytes[:],
  1108  	)
  1109  }
  1110  
  1111  // getHeightBucket retrieves an existing height bucket from the nursery store,
  1112  // using the provided block height. If the bucket does not exist, or any bucket
  1113  // along its path does not exist, a nil value is returned.
  1114  func (ns *NurseryStore) getHeightBucket(tx kvdb.RTx,
  1115  	height uint32) kvdb.RBucket {
  1116  	_, _, hghtBucket := ns.getHeightBucketPath(tx, height)
  1117  
  1118  	return hghtBucket
  1119  }
  1120  
  1121  // getHeightBucketWrite retrieves an existing height bucket from the nursery store,
  1122  // using the provided block height. If the bucket does not exist, or any bucket
  1123  // along its path does not exist, a nil value is returned.
  1124  func (ns *NurseryStore) getHeightBucketWrite(tx kvdb.RwTx,
  1125  	height uint32) kvdb.RwBucket {
  1126  
  1127  	_, _, hghtBucket := ns.getHeightBucketPathWrite(tx, height)
  1128  
  1129  	return hghtBucket
  1130  }
  1131  
  1132  // createHeightChanBucket creates or retrieves an existing height-channel bucket
  1133  // for the provided block height and channel point. This method will attempt to
  1134  // instantiate all buckets along the path if required.
  1135  func (ns *NurseryStore) createHeightChanBucket(tx kvdb.RwTx,
  1136  	height uint32, chanPoint *wire.OutPoint) (kvdb.RwBucket, error) {
  1137  
  1138  	// Ensure that the height bucket for this nursery store exists.
  1139  	hghtBucket, err := ns.createHeightBucket(tx, height)
  1140  	if err != nil {
  1141  		return nil, err
  1142  	}
  1143  
  1144  	// Serialize the provided channel point, as this generates the name of
  1145  	// the subdirectory corresponding to the channel of interest.
  1146  	var chanBuffer bytes.Buffer
  1147  	if err := writeOutpoint(&chanBuffer, chanPoint); err != nil {
  1148  		return nil, err
  1149  	}
  1150  	chanBytes := chanBuffer.Bytes()
  1151  
  1152  	// Finally, create or retrieve an existing height-channel bucket for
  1153  	// this channel point.
  1154  	return hghtBucket.CreateBucketIfNotExists(chanBytes)
  1155  }
  1156  
  1157  // getHeightChanBucketWrite retrieves an existing height-channel bucket from the
  1158  // nursery store, using the provided block height and channel point. if the
  1159  // bucket does not exist, or any bucket along its path does not exist, a nil
  1160  // value is returned.
  1161  func (ns *NurseryStore) getHeightChanBucketWrite(tx kvdb.RwTx,
  1162  	height uint32, chanPoint *wire.OutPoint) kvdb.RwBucket {
  1163  
  1164  	// Retrieve the existing height bucket from this nursery store.
  1165  	hghtBucket := ns.getHeightBucketWrite(tx, height)
  1166  	if hghtBucket == nil {
  1167  		return nil
  1168  	}
  1169  
  1170  	// Serialize the provided channel point, which generates the key for
  1171  	// looking up the proper height-channel bucket inside the height bucket.
  1172  	var chanBuffer bytes.Buffer
  1173  	if err := writeOutpoint(&chanBuffer, chanPoint); err != nil {
  1174  		return nil
  1175  	}
  1176  	chanBytes := chanBuffer.Bytes()
  1177  
  1178  	// Finally, return the height bucket specified by the serialized channel
  1179  	// point.
  1180  	return hghtBucket.NestedReadWriteBucket(chanBytes)
  1181  }
  1182  
  1183  // forEachHeightPrefix enumerates all outputs at the given height whose state
  1184  // prefix matches that which is provided. This is used as a subroutine to help
  1185  // enumerate crib and kindergarten outputs at a particular height. The callback
  1186  // is invoked with serialized bytes retrieved for each output of interest,
  1187  // allowing the caller to deserialize them into the appropriate type.
  1188  func (ns *NurseryStore) forEachHeightPrefix(tx kvdb.RTx, prefix []byte,
  1189  	height uint32, callback func([]byte) error) error {
  1190  
  1191  	// Start by retrieving the height bucket corresponding to the provided
  1192  	// block height.
  1193  	chainBucket, _, hghtBucket := ns.getHeightBucketPath(tx, height)
  1194  	if hghtBucket == nil {
  1195  		return nil
  1196  	}
  1197  
  1198  	// Using the height bucket as a starting point, we will traverse its
  1199  	// entire two-tier directory structure, and filter for outputs that have
  1200  	// the provided prefix. The first layer of the height bucket contains
  1201  	// buckets identified by a channel point, thus we first create list of
  1202  	// channels contained in this height bucket.
  1203  	var channelsAtHeight [][]byte
  1204  	if err := hghtBucket.ForEach(func(chanBytes, v []byte) error {
  1205  		if v == nil {
  1206  			channelsAtHeight = append(channelsAtHeight, chanBytes)
  1207  		}
  1208  		return nil
  1209  	}); err != nil {
  1210  		return err
  1211  	}
  1212  
  1213  	// Additionally, grab the chain index, which we will facilitate queries
  1214  	// for each of the channel buckets of each of the channels in the list
  1215  	// we assembled above.
  1216  	chanIndex := chainBucket.NestedReadBucket(channelIndexKey)
  1217  	if chanIndex == nil {
  1218  		return errors.New("unable to retrieve channel index")
  1219  	}
  1220  
  1221  	// Now, we are ready to enumerate all outputs with the desired prefix at
  1222  	// this block height. We do so by iterating over our list of channels at
  1223  	// this height, filtering for outputs in each height-channel bucket that
  1224  	// begin with the given prefix, and then retrieving the serialized
  1225  	// outputs from the appropriate channel bucket.
  1226  	for _, chanBytes := range channelsAtHeight {
  1227  		// Retrieve the height-channel bucket for this channel, which
  1228  		// holds a sub-bucket for all outputs maturing at this height.
  1229  		hghtChanBucket := hghtBucket.NestedReadBucket(chanBytes)
  1230  		if hghtChanBucket == nil {
  1231  			return fmt.Errorf("unable to retrieve height-channel "+
  1232  				"bucket at height %d for %x", height, chanBytes)
  1233  		}
  1234  
  1235  		// Load the appropriate channel bucket from the channel index,
  1236  		// this will allow us to retrieve the individual serialized
  1237  		// outputs.
  1238  		chanBucket := chanIndex.NestedReadBucket(chanBytes)
  1239  		if chanBucket == nil {
  1240  			return fmt.Errorf("unable to retrieve channel "+
  1241  				"bucket: '%x'", chanBytes)
  1242  		}
  1243  
  1244  		// Since all of the outputs of interest will start with the same
  1245  		// prefix, we will perform a prefix scan of the buckets
  1246  		// contained in the height-channel bucket, efficiently
  1247  		// enumerating the desired outputs.
  1248  		c := hghtChanBucket.ReadCursor()
  1249  		for k, _ := c.Seek(prefix); bytes.HasPrefix(
  1250  			k, prefix); k, _ = c.Next() {
  1251  
  1252  			// Use the prefix output key emitted from our scan to
  1253  			// load the serialized babyOutput from the appropriate
  1254  			// channel bucket.
  1255  			outputBytes := chanBucket.Get(k)
  1256  			if outputBytes == nil {
  1257  				return errors.New("unable to retrieve output")
  1258  			}
  1259  
  1260  			// Present the serialized bytes to our call back
  1261  			// function, which is responsible for deserializing the
  1262  			// bytes into the appropriate type.
  1263  			if err := callback(outputBytes); err != nil {
  1264  				return err
  1265  			}
  1266  		}
  1267  	}
  1268  
  1269  	return nil
  1270  }
  1271  
  1272  // forChanOutputs enumerates the outputs contained in a channel bucket to the
  1273  // provided callback. The callback accepts a key-value pair of byte slices
  1274  // corresponding to the prefixed-output key and the serialized output,
  1275  // respectively.
  1276  func (ns *NurseryStore) forChanOutputs(tx kvdb.RTx, chanPoint *wire.OutPoint,
  1277  	callback func([]byte, []byte) error) error {
  1278  
  1279  	chanBucket := ns.getChannelBucket(tx, chanPoint)
  1280  	if chanBucket == nil {
  1281  		return ErrContractNotFound
  1282  	}
  1283  
  1284  	return chanBucket.ForEach(callback)
  1285  }
  1286  
  1287  // errBucketNotEmpty signals that an attempt to prune a particular
  1288  // bucket failed because it still has active outputs.
  1289  var errBucketNotEmpty = errors.New("bucket is not empty, cannot be pruned")
  1290  
  1291  // removeOutputFromHeight will delete the given output from the specified
  1292  // height-channel bucket, and attempt to prune the upstream directories if they
  1293  // are empty.
  1294  func (ns *NurseryStore) removeOutputFromHeight(tx kvdb.RwTx, height uint32,
  1295  	chanPoint *wire.OutPoint, pfxKey []byte) error {
  1296  
  1297  	// Retrieve the height-channel bucket and delete the prefixed output.
  1298  	hghtChanBucket := ns.getHeightChanBucketWrite(tx, height, chanPoint)
  1299  	if hghtChanBucket == nil {
  1300  		// Height-channel bucket already removed.
  1301  		return nil
  1302  	}
  1303  
  1304  	// Try to delete the prefixed output from the target height-channel
  1305  	// bucket.
  1306  	if err := hghtChanBucket.Delete(pfxKey); err != nil {
  1307  		return err
  1308  	}
  1309  
  1310  	// Retrieve the height bucket that contains the height-channel bucket.
  1311  	hghtBucket := ns.getHeightBucketWrite(tx, height)
  1312  	if hghtBucket == nil {
  1313  		return errors.New("height bucket not found")
  1314  	}
  1315  
  1316  	var chanBuffer bytes.Buffer
  1317  	if err := writeOutpoint(&chanBuffer, chanPoint); err != nil {
  1318  		return err
  1319  	}
  1320  
  1321  	// Try to remove the channel-height bucket if it this was the last
  1322  	// output in the bucket.
  1323  	err := removeBucketIfEmpty(hghtBucket, chanBuffer.Bytes())
  1324  	if err != nil && err != errBucketNotEmpty {
  1325  		return err
  1326  	} else if err == errBucketNotEmpty {
  1327  		return nil
  1328  	}
  1329  
  1330  	// Attempt to prune the height bucket matching the kid output's
  1331  	// confirmation height in case that was the last height-chan bucket.
  1332  	pruned, err := ns.pruneHeight(tx, height)
  1333  	if err != nil && err != errBucketNotEmpty {
  1334  		return err
  1335  	} else if err == nil && pruned {
  1336  		utxnLog.Infof("Height bucket %d pruned", height)
  1337  	}
  1338  
  1339  	return nil
  1340  }
  1341  
  1342  // pruneHeight removes the height bucket at the provided height if and only if
  1343  // all active outputs at this height have been removed from their respective
  1344  // height-channel buckets. The returned boolean value indicated whether or not
  1345  // this invocation successfully pruned the height bucket.
  1346  func (ns *NurseryStore) pruneHeight(tx kvdb.RwTx, height uint32) (bool, error) {
  1347  	// Fetch the existing height index and height bucket.
  1348  	_, hghtIndex, hghtBucket := ns.getHeightBucketPathWrite(tx, height)
  1349  	if hghtBucket == nil {
  1350  		return false, nil
  1351  	}
  1352  
  1353  	// Iterate over all channels stored at this block height. We will
  1354  	// attempt to remove each one if they are empty, keeping track of the
  1355  	// number of height-channel buckets that still have active outputs.
  1356  	if err := hghtBucket.ForEach(func(chanBytes, v []byte) error {
  1357  		// Skip the finalized txn key if it still exists from a previous
  1358  		// db version.
  1359  		if v != nil {
  1360  			return nil
  1361  		}
  1362  
  1363  		// Attempt to each height-channel bucket from the height bucket
  1364  		// located above.
  1365  		hghtChanBucket := hghtBucket.NestedReadWriteBucket(chanBytes)
  1366  		if hghtChanBucket == nil {
  1367  			return errors.New("unable to find height-channel bucket")
  1368  		}
  1369  
  1370  		return isBucketEmpty(hghtChanBucket)
  1371  
  1372  	}); err != nil {
  1373  		return false, err
  1374  	}
  1375  
  1376  	// Serialize the provided block height, such that it can be used as the
  1377  	// key to delete desired height bucket.
  1378  	var heightBytes [4]byte
  1379  	byteOrder.PutUint32(heightBytes[:], height)
  1380  
  1381  	// All of the height-channel buckets are empty or have been previously
  1382  	// removed, proceed by removing the height bucket
  1383  	// altogether.
  1384  	if err := removeBucketIfExists(hghtIndex, heightBytes[:]); err != nil {
  1385  		return false, err
  1386  	}
  1387  
  1388  	return true, nil
  1389  }
  1390  
  1391  // removeBucketIfEmpty attempts to delete a bucket specified by name from the
  1392  // provided parent bucket.
  1393  func removeBucketIfEmpty(parent kvdb.RwBucket, bktName []byte) error {
  1394  	// Attempt to fetch the named bucket from its parent.
  1395  	bkt := parent.NestedReadWriteBucket(bktName)
  1396  	if bkt == nil {
  1397  		// No bucket was found, already removed?
  1398  		return nil
  1399  	}
  1400  
  1401  	// The bucket exists, fail if it still has children.
  1402  	if err := isBucketEmpty(bkt); err != nil {
  1403  		return err
  1404  	}
  1405  
  1406  	return parent.DeleteNestedBucket(bktName)
  1407  }
  1408  
  1409  // removeBucketIfExists safely deletes the named bucket by first checking
  1410  // that it exists in the parent bucket.
  1411  func removeBucketIfExists(parent kvdb.RwBucket, bktName []byte) error {
  1412  	// Attempt to fetch the named bucket from its parent.
  1413  	bkt := parent.NestedReadWriteBucket(bktName)
  1414  	if bkt == nil {
  1415  		// No bucket was found, already removed?
  1416  		return nil
  1417  	}
  1418  
  1419  	return parent.DeleteNestedBucket(bktName)
  1420  }
  1421  
  1422  // isBucketEmpty returns errBucketNotEmpty if the bucket has a non-zero number
  1423  // of children.
  1424  func isBucketEmpty(parent kvdb.RBucket) error {
  1425  	return parent.ForEach(func(_, _ []byte) error {
  1426  		return errBucketNotEmpty
  1427  	})
  1428  }
  1429  
  1430  // Compile-time constraint to ensure NurseryStore implements NurseryStorer.
  1431  var _ NurseryStorer = (*NurseryStore)(nil)