nursery_store: detect Late Registrations when promoting to kindergarten
In this commit, we aim to address a lingering bug caused by a Late Registration of a kid output from preschool to kindergarten. In this scenario, an output is promoted, but *after* it’s target maturity period, meaning that we won’t graduate the output until we restart. To avoid this, we’ll now detect this case, and bump the graduation height by one to ensure that when the new block arrives, we properly handle the output.
This commit is contained in:
parent
d0f8b5f194
commit
fc8a6568c9
@ -400,6 +400,10 @@ func (ns *nurseryStore) CribToKinder(bby *babyOutput) error {
|
||||
return err
|
||||
}
|
||||
|
||||
utxnLog.Tracef("Placing (crib -> baby) output for "+
|
||||
"chan_point=%v at height_index=%v", chanPoint,
|
||||
maturityHeight)
|
||||
|
||||
// Register the kindergarten output's prefixed output key in the
|
||||
// height-channel bucket corresponding to its maturity height.
|
||||
// This informs the utxo nursery that it should attempt to spend
|
||||
@ -413,7 +417,6 @@ func (ns *nurseryStore) CribToKinder(bby *babyOutput) error {
|
||||
// confirmation of the preschool output's commitment transaction.
|
||||
func (ns *nurseryStore) PreschoolToKinder(kid *kidOutput) error {
|
||||
return ns.db.Update(func(tx *bolt.Tx) error {
|
||||
|
||||
// Create or retrieve the channel bucket corresponding to the
|
||||
// kid output's origin channel point.
|
||||
chanPoint := kid.OriginChanPoint()
|
||||
@ -459,13 +462,41 @@ func (ns *nurseryStore) PreschoolToKinder(kid *kidOutput) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Since the CSV delay on the kid output has now begun ticking,
|
||||
// we must insert a record of in the height index to remind us
|
||||
// to revisit this output once it has fully matured.
|
||||
// If this output has an absolute time lock, then we'll set the
|
||||
// maturity height directly.
|
||||
var maturityHeight uint32
|
||||
if kid.BlocksToMaturity() == 0 {
|
||||
maturityHeight = kid.absoluteMaturity
|
||||
} else {
|
||||
// Otherwise, since the CSV delay on the kid output has
|
||||
// now begun ticking, we must insert a record of in the
|
||||
// height index to remind us to revisit this output
|
||||
// once it has fully matured.
|
||||
//
|
||||
// Compute the maturity height, by adding the output's
|
||||
// CSV delay to its confirmation height.
|
||||
maturityHeight = kid.ConfHeight() + kid.BlocksToMaturity()
|
||||
}
|
||||
|
||||
// Compute the maturity height, by adding the output's CSV delay
|
||||
// to its confirmation height.
|
||||
maturityHeight := kid.ConfHeight() + kid.BlocksToMaturity()
|
||||
// In the case of a Late Registration, we've already graduated
|
||||
// the class that this kid is destined for. So we'll bump it's
|
||||
// height by one to ensure we don't forget to graduate it.
|
||||
lastGradHeight, err := ns.getLastGraduatedHeight(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maturityHeight <= lastGradHeight {
|
||||
utxnLog.Debugf("Late Registration for kid output=%v "+
|
||||
"detected: class_height=%v, "+
|
||||
"last_graduated_height=%v", kid.OutPoint(),
|
||||
maturityHeight, lastGradHeight)
|
||||
|
||||
maturityHeight = lastGradHeight + 1
|
||||
}
|
||||
|
||||
utxnLog.Tracef("Placing (crib -> kid) output for "+
|
||||
"chan_point=%v at height_index=%v", chanPoint,
|
||||
maturityHeight)
|
||||
|
||||
// Create or retrieve the height-channel bucket for this
|
||||
// channel. This method will first create a height bucket for
|
||||
|
@ -127,7 +127,11 @@ func TestNurseryStoreIncubate(t *testing.T) {
|
||||
|
||||
// Begin incubating all of the outputs provided in this test
|
||||
// vector.
|
||||
err = ns.Incubate(test.commOutput, test.htlcOutputs)
|
||||
var kids []kidOutput
|
||||
if test.commOutput != nil {
|
||||
kids = append(kids, *test.commOutput)
|
||||
}
|
||||
err = ns.Incubate(kids, test.htlcOutputs)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to incubate outputs"+
|
||||
"on test #%d: %v", i, err)
|
||||
@ -362,7 +366,7 @@ func TestNurseryStoreFinalize(t *testing.T) {
|
||||
|
||||
// Begin incubating the commitment output, which will be placed in the
|
||||
// preschool bucket.
|
||||
err = ns.Incubate(kid, nil)
|
||||
err = ns.Incubate([]kidOutput{*kid}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to incubate commitment output: %v", err)
|
||||
}
|
||||
@ -449,7 +453,7 @@ func TestNurseryStoreGraduate(t *testing.T) {
|
||||
|
||||
// First, add a commitment output to the nursery store, which is
|
||||
// initially inserted in the preschool bucket.
|
||||
err = ns.Incubate(kid, nil)
|
||||
err = ns.Incubate([]kidOutput{*kid}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to incubate commitment output: %v", err)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user