utxonursery: add new public NurseryReport method
This commit adds a new public facing method to the utxoNursery: NurseryReport. This method is intended to be used by callers to introspect into the current state of the utxo nursery. With this information, callers will be able to ascertain: the number of immature outputs, the total number of funds in limbo, and when funds can be fully swept.
This commit is contained in:
parent
79ceaca747
commit
17c5deb369
131
utxonursery.go
131
utxonursery.go
@ -421,6 +421,137 @@ out:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// contractMaturityReport is a report that details the maturity progress of a
|
||||||
|
// particular force closed contract.
|
||||||
|
type contractMaturityReport struct {
|
||||||
|
// chanPoint is the channel point of the original contract that is now
|
||||||
|
// awaiting maturity within the utxoNursery.
|
||||||
|
chanPoint wire.OutPoint
|
||||||
|
|
||||||
|
// limboBalance is the total number of frozen coins within this
|
||||||
|
// contract.
|
||||||
|
limboBalance btcutil.Amount
|
||||||
|
|
||||||
|
// confirmationHeight is the block height that this output originally
|
||||||
|
// confirmed at.
|
||||||
|
confirmationHeight uint32
|
||||||
|
|
||||||
|
// maturityHeight is the input age required for this output to reach
|
||||||
|
// maturity.
|
||||||
|
maturityRequirement uint32
|
||||||
|
|
||||||
|
// maturityHeight is the absolute block height that this output will mature
|
||||||
|
// at.
|
||||||
|
maturityHeight uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// NurseryReport attempts to return a nursery report stored for the target
|
||||||
|
// outpoint. A nursery report details the maturity/sweeping progress for a
|
||||||
|
// contract that was previously force closed. If a report entry for the target
|
||||||
|
// chanPoint is unable to be constructed, then an error will be returned.
|
||||||
|
func (u *utxoNursery) NurseryReport(chanPoint *wire.OutPoint) (*contractMaturityReport, error) {
|
||||||
|
var report *contractMaturityReport
|
||||||
|
if err := u.db.View(func(tx *bolt.Tx) error {
|
||||||
|
// First we'll examine the preschool bucket as the target
|
||||||
|
// contract may not yet have been confirmed.
|
||||||
|
psclBucket := tx.Bucket(preschoolBucket)
|
||||||
|
if psclBucket == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
psclIndex := tx.Bucket(preschoolIndex)
|
||||||
|
if psclIndex == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
if err := writeOutpoint(&b, chanPoint); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
chanPointBytes := b.Bytes()
|
||||||
|
|
||||||
|
var outputReader *bytes.Reader
|
||||||
|
|
||||||
|
// If the target contract hasn't been confirmed yet, then we
|
||||||
|
// can just construct the report from this information.
|
||||||
|
if outPoint := psclIndex.Get(chanPointBytes); outPoint != nil {
|
||||||
|
// The channel entry hasn't yet been fully confirmed
|
||||||
|
// yet, so we'll dig into the preschool bucket to fetch
|
||||||
|
// the channel information.
|
||||||
|
outputBytes := psclBucket.Get(outPoint)
|
||||||
|
if outputBytes == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
outputReader = bytes.NewReader(outputBytes)
|
||||||
|
} else {
|
||||||
|
// Otherwise, we'll have to consult out contract index,
|
||||||
|
// so fetch that bucket as well as the kindergarten
|
||||||
|
// bucket.
|
||||||
|
indexBucket := tx.Bucket(contractIndex)
|
||||||
|
if indexBucket == nil {
|
||||||
|
return fmt.Errorf("contract not found, " +
|
||||||
|
"contract index not populated")
|
||||||
|
}
|
||||||
|
kgtnBucket := tx.Bucket(kindergartenBucket)
|
||||||
|
if kgtnBucket == nil {
|
||||||
|
return fmt.Errorf("contract not found, " +
|
||||||
|
"kindergarten bucket not populated")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to query the index to see if we have an
|
||||||
|
// entry for this particular contract.
|
||||||
|
indexInfo := indexBucket.Get(chanPointBytes)
|
||||||
|
if indexInfo == nil {
|
||||||
|
return fmt.Errorf("contract not found in index")
|
||||||
|
}
|
||||||
|
|
||||||
|
// If an entry is found, then using the height store in
|
||||||
|
// the first 4 bytes, we'll fetch the height that this
|
||||||
|
// entry matures at.
|
||||||
|
height := indexInfo[:4]
|
||||||
|
heightRow := kgtnBucket.Get(height)
|
||||||
|
if heightRow == nil {
|
||||||
|
return fmt.Errorf("contract not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once we have the entry itself, we'll slice of the
|
||||||
|
// last for bytes so we can seek into this row to fetch
|
||||||
|
// the contract's information.
|
||||||
|
offset := byteOrder.Uint32(indexInfo[4:])
|
||||||
|
outputReader = bytes.NewReader(heightRow[offset:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// With the proper set of bytes received, we'll deserialize the
|
||||||
|
// information for this immature output.
|
||||||
|
immatureOutput, err := deserializeKidOutput(outputReader)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(roasbeef): should actually be list of outputs
|
||||||
|
report = &contractMaturityReport{
|
||||||
|
chanPoint: *chanPoint,
|
||||||
|
limboBalance: immatureOutput.amt,
|
||||||
|
maturityRequirement: immatureOutput.blocksToMaturity,
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the confirmation height is set, then this means the
|
||||||
|
// contract has been confirmed, and we know the final maturity
|
||||||
|
// height.
|
||||||
|
if immatureOutput.confHeight != 0 {
|
||||||
|
report.confirmationHeight = immatureOutput.confHeight
|
||||||
|
report.maturityHeight = (immatureOutput.blocksToMaturity +
|
||||||
|
immatureOutput.confHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return report, nil
|
||||||
|
}
|
||||||
|
|
||||||
// enterPreschool is the first stage in the process of transferring funds from
|
// enterPreschool is the first stage in the process of transferring funds from
|
||||||
// a force closed channel into the user's wallet. When an output is in the
|
// a force closed channel into the user's wallet. When an output is in the
|
||||||
// "preschool" stage, the daemon is waiting for the initial confirmation of the
|
// "preschool" stage, the daemon is waiting for the initial confirmation of the
|
||||||
|
Loading…
Reference in New Issue
Block a user