Skip to content

Commit

Permalink
Merge pull request #94 from kcalvinalvin/2023-12-21-utreexoviewpoint-…
Browse files Browse the repository at this point in the history
…partial-proof-suport

blockchain, wire: utreexoviewpoint partial proof support
  • Loading branch information
kcalvinalvin authored Dec 21, 2023
2 parents 0ccbeee + 32f3e68 commit acb4603
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 13 deletions.
81 changes: 81 additions & 0 deletions blockchain/utreexoviewpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,39 @@ func (b *BlockChain) VerifyUData(ud *wire.UData, txIns []*wire.TxIn, remember bo
return nil
}

// GenerateUDataPartial generates a utreexo data based on the current state of the utreexo viewpoint.
// It leaves out the full proof hashes and only fetches the requested positions.
//
// This function is safe for concurrent access.
func (b *BlockChain) GenerateUDataPartial(dels []wire.LeafData, positions []uint64) (*wire.UData, error) {
b.chainLock.RLock()
defer b.chainLock.RUnlock()

ud := new(wire.UData)
ud.LeafDatas = dels

// Get the positions of the targets of delHashes.
delHashes, err := wire.HashesFromLeafDatas(ud.LeafDatas)
if err != nil {
return nil, err
}
targets := b.getLeafHashPositions(delHashes)

// Fetch the requested hashes.
hashes := make([]utreexo.Hash, len(positions))
for i, pos := range positions {
hashes[i] = b.utreexoView.accumulator.GetHash(pos)
}

// Put the proof together and return.
ud.AccProof = utreexo.Proof{
Targets: targets,
Proof: hashes,
}

return ud, nil
}

// GenerateUData generates a utreexo data based on the current state of the utreexo viewpoint.
//
// This function is safe for concurrent access.
Expand Down Expand Up @@ -979,6 +1012,54 @@ func (b *BlockChain) PruneFromAccumulator(leaves []wire.LeafData) error {
return nil
}

// packedPositions fetches and returns the positions of the leafHashes as chainhash.Hash.
//
// This function is NOT safe for concurrent access.
func (b *BlockChain) packedPositions(leafHashes []utreexo.Hash) []chainhash.Hash {
positions := b.utreexoView.accumulator.GetLeafHashPositions(leafHashes)
return chainhash.Uint64sToPackedHashes(positions)
}

// PackedPositions fetches and returns the positions of the leafHashes as chainhash.Hash.
//
// This function is safe for concurrent access.
func (b *BlockChain) PackedPositions(leafHashes []utreexo.Hash) []chainhash.Hash {
b.chainLock.RLock()
defer b.chainLock.RUnlock()

return b.packedPositions(leafHashes)
}

// getLeafHashPositions returns the positions of the passed in leaf hashes.
//
// This function is NOT safe for concurrent access.
func (b *BlockChain) getLeafHashPositions(leafHashes []utreexo.Hash) []uint64 {
return b.utreexoView.accumulator.GetLeafHashPositions(leafHashes)
}

// GetLeafHashPositions returns the positions of the passed in leaf hashes.
//
// This function is safe for concurrent access.
func (b *BlockChain) GetLeafHashPositions(leafHashes []utreexo.Hash) []uint64 {
b.chainLock.RLock()
defer b.chainLock.RUnlock()

return b.getLeafHashPositions(leafHashes)
}

// GetNeededPositions returns the positions of the needed hashes in order to verify the
// positions passed in.
//
// This function is safe for concurrent access.
func (b *BlockChain) GetNeededPositions(packedPositions []chainhash.Hash) []chainhash.Hash {
b.chainLock.RLock()
defer b.chainLock.RUnlock()

positions := chainhash.PackedHashesToUint64(packedPositions)
missing := b.utreexoView.accumulator.GetMissingPositions(positions)
return chainhash.Uint64sToPackedHashes(missing)
}

// ChainTipProof represents all the information that is needed to prove that a
// utxo exists in the chain tip with utreexo accumulator proof.
type ChainTipProof struct {
Expand Down
37 changes: 24 additions & 13 deletions wire/udata.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,20 +428,13 @@ func DeserializeRemembers(r io.Reader) ([]uint32, error) {
return remembers, nil
}

// GenerateUData creates a block proof, calling forest.ProveBatch with the leaf indexes
// to get a batched inclusion proof from the accumulator. It then adds on the leaf data,
// to create a block proof which both proves inclusion and gives all utxo data
// needed for transaction verification.
func GenerateUData(txIns []LeafData, pollard utreexo.Utreexo) (
*UData, error) {

ud := new(UData)
ud.LeafDatas = txIns

// HashesFromLeafDatas hashes the passed in leaf datas. Returns an error if a
// leaf data is compact as you can't generate the correct hash.
func HashesFromLeafDatas(leafDatas []LeafData) ([]utreexo.Hash, error) {
// make slice of hashes from leafdata
var unconfirmedCount int
delHashes := make([]utreexo.Hash, 0, len(ud.LeafDatas))
for _, ld := range ud.LeafDatas {
delHashes := make([]utreexo.Hash, 0, len(leafDatas))
for _, ld := range leafDatas {
if ld.IsUnconfirmed() {
unconfirmedCount++
continue
Expand All @@ -457,8 +450,26 @@ func GenerateUData(txIns []LeafData, pollard utreexo.Utreexo) (
delHashes = append(delHashes, ld.LeafHash())
}

return delHashes, nil
}

// GenerateUData creates a block proof, calling forest.ProveBatch with the leaf indexes
// to get a batched inclusion proof from the accumulator. It then adds on the leaf data,
// to create a block proof which both proves inclusion and gives all utxo data
// needed for transaction verification.
func GenerateUData(txIns []LeafData, pollard utreexo.Utreexo) (
*UData, error) {

ud := new(UData)
ud.LeafDatas = txIns

// Make a slice of hashes from the leafdatas.
delHashes, err := HashesFromLeafDatas(ud.LeafDatas)
if err != nil {
return nil, err
}

// Generate the utreexo accumulator proof for all the inputs.
var err error
ud.AccProof, err = pollard.Prove(delHashes)
if err != nil {
// Find out which exact one is causing the error.
Expand Down

0 comments on commit acb4603

Please sign in to comment.