diff --git a/blockchain/utreexoviewpoint.go b/blockchain/utreexoviewpoint.go index 345772ee..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. @@ -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 { 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.