From fe1198e43aa41d049ca50012d3f712c75b3332a7 Mon Sep 17 00:00:00 2001 From: Calvin Kim Date: Wed, 20 Dec 2023 18:17:52 +0900 Subject: [PATCH 1/3] wire: refactor out HashesFromLeafDatas from GenerateUData The code that was hashing the leaf datas are refactored out into its own function. This is as we can avoid code duplicates when creating GenerateUDataPartial. --- wire/udata.go | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/wire/udata.go b/wire/udata.go index 01d9ed4d..cc42ffad 100644 --- a/wire/udata.go +++ b/wire/udata.go @@ -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 @@ -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. From 70a9fea2be5dc5d188224e3e15e2fe615568a5d1 Mon Sep 17 00:00:00 2001 From: Calvin Kim Date: Thu, 21 Dec 2023 14:49:20 +0900 Subject: [PATCH 2/3] blockchain: add util functions for mempool utreexo proof communication The added functions allow fetching for information that'll be used for communicating to other utreexo proofs what proof hashes I need to prove a given tx. --- blockchain/utreexoviewpoint.go | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/blockchain/utreexoviewpoint.go b/blockchain/utreexoviewpoint.go index 345772ee..6e7abc69 100644 --- a/blockchain/utreexoviewpoint.go +++ b/blockchain/utreexoviewpoint.go @@ -979,6 +979,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 { From 32f3e68ea4f098fc8b68d3609ef067883df8a84b Mon Sep 17 00:00:00 2001 From: Calvin Kim Date: Thu, 21 Dec 2023 14:50:15 +0900 Subject: [PATCH 3/3] blockchain: add GenerateUDataPartial GenerateUDataPartial allows for the generation of partial udata to serve to other utreexo nodes. --- blockchain/utreexoviewpoint.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/blockchain/utreexoviewpoint.go b/blockchain/utreexoviewpoint.go index 6e7abc69..e083bf40 100644 --- a/blockchain/utreexoviewpoint.go +++ b/blockchain/utreexoviewpoint.go @@ -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.