From 864ffb32e017c15cd8835391664957017d6cf9cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Lewandowski?= Date: Tue, 24 Oct 2023 16:35:58 +0200 Subject: [PATCH] chore(BUX-296): update calculate merkle proof method --- bump.go | 10 +++-- compound_merkle_path.go | 18 --------- p2p_beef_tx.go | 90 ++++++++++++++++++----------------------- 3 files changed, 47 insertions(+), 71 deletions(-) delete mode 100644 compound_merkle_path.go diff --git a/bump.go b/bump.go index 87f2a82..1ce50e4 100644 --- a/bump.go +++ b/bump.go @@ -1,15 +1,19 @@ package paymail +// BUMPTx is a struct that represents a single BUMP transaction type BUMPTx struct { hash string txId bool duplicate bool } -type BUMPMap []map[string]BUMPTx +// BUMPMap is a map of BUMPTx where offset is the key +type BUMPMap []map[uint64]BUMPTx +// BUMPSlice is a slice of BUMPMap which contain transactions required to calculate merkle roots type BUMPSlice []BUMPMap +// BUMP is a struct that represents a whole BUMP format type BUMP struct { blockHeight uint64 path BUMPSlice @@ -18,8 +22,8 @@ type BUMP struct { func (b BUMPMap) calculateMerkleRoots() ([]string, error) { merkleRoots := make([]string, 0) - for tx, offset := range cmp[len(cmp)-1] { - merkleRoot, err := calculateMerkleRoot(tx, offset, cmp) + for offset, bumpTx := range b[0] { + merkleRoot, err := calculateMerkleRoot(bumpTx, offset, b) if err != nil { return nil, err } diff --git a/compound_merkle_path.go b/compound_merkle_path.go deleted file mode 100644 index a0c83cd..0000000 --- a/compound_merkle_path.go +++ /dev/null @@ -1,18 +0,0 @@ -package paymail - -type CompoundMerklePath []map[string]uint64 - -type CMPSlice []CompoundMerklePath - -func (cmp CompoundMerklePath) calculateMerkleRoots() ([]string, error) { - merkleRoots := make([]string, 0) - - for tx, offset := range cmp[len(cmp)-1] { - merkleRoot, err := calculateMerkleRoot(tx, offset, cmp) - if err != nil { - return nil, err - } - merkleRoots = append(merkleRoots, merkleRoot) - } - return merkleRoots, nil -} diff --git a/p2p_beef_tx.go b/p2p_beef_tx.go index d1114e0..51d507a 100644 --- a/p2p_beef_tx.go +++ b/p2p_beef_tx.go @@ -4,8 +4,6 @@ import ( "encoding/hex" "errors" "fmt" - "strconv" - "github.com/libsv/go-bc" "github.com/libsv/go-bt/v2" ) @@ -39,8 +37,8 @@ type DecodedBEEF struct { func (dBeef *DecodedBEEF) GetMerkleRoots() ([]string, error) { var merkleRoots []string - for _, cmp := range dBeef.CMPSlice { - partialMerkleRoots, err := cmp.calculateMerkleRoots() + for _, bump := range dBeef.BUMP.path { + partialMerkleRoots, err := bump.calculateMerkleRoots() if err != nil { return nil, err } @@ -49,39 +47,56 @@ func (dBeef *DecodedBEEF) GetMerkleRoots() ([]string, error) { return merkleRoots, nil } -func calculateMerkleRoot(baseTx string, offset uint64, cmp []map[string]uint64) (string, error) { - for i := 0; i < len(cmp); i++ { - var leftNode, rightNode string +func calculateMerkleRoot(baseTx BUMPTx, offset uint64, bumpMap []map[uint64]BUMPTx) (string, error) { + calculatedHash := baseTx.hash + + for i := 0; i < len(bumpMap); i++ { newOffset := offset - 1 if offset%2 == 0 { newOffset = offset + 1 } - tx2 := keyByValue(cmp[i], newOffset) - if tx2 == nil { - fmt.Println("could not find pair") + tx2 := bumpMap[i][newOffset] + if &tx2 == nil { return "", errors.New("could not find pair") } - if newOffset > offset { - leftNode = baseTx - rightNode = *tx2 - } else { - leftNode = *tx2 - rightNode = baseTx - } + leftNode, rightNode := prepareNodes(baseTx, offset, tx2, newOffset) - // Calculate new merkle tree parent str, err := bc.MerkleTreeParentStr(leftNode, rightNode) if err != nil { return "", err } - baseTx = str + calculatedHash = str - // Reduce offset offset = offset / 2 + + if i+1 < len(bumpMap) { + baseTx = bumpMap[i+1][newOffset] + } } - return baseTx, nil + return calculatedHash, nil +} + +func prepareNodes(baseTx BUMPTx, offset uint64, tx2 BUMPTx, newOffset uint64) (string, string) { + var txHash, tx2Hash string + + if baseTx.duplicate { + txHash = tx2.hash + } else { + txHash = baseTx.hash + } + + if tx2.duplicate { + tx2Hash = baseTx.hash + } else { + tx2Hash = tx2.hash + } + + if newOffset > offset { + return txHash, tx2Hash + } + return tx2Hash, txHash } func keyByValue(m map[string]uint64, value uint64) *string { @@ -133,30 +148,6 @@ func DecodeBEEF(beefHex string) (*DecodedBEEF, error) { }, nil } -func DecodeBUMP(beefHex string) (*DecodedBEEF, error) { - beefBytes, err := hex.DecodeString(beefHex) - if err != nil { - return nil, err - } - - blockHeight, bytesUsed := bt.NewVarIntFromBytes(beefBytes) - beefBytes = beefBytes[bytesUsed:] - - bumpSlice, _, err := decodeBUMPSliceFromStream(beefBytes) - if err != nil { - return nil, err - } - - bump := BUMP{ - blockHeight: uint64(blockHeight), - path: bumpSlice, - } - - fmt.Println(bump) - - return nil, nil -} - func decodeBUMPSliceFromStream(hexBytes []byte) (BUMPSlice, []byte, error) { if len(hexBytes) == 0 { return nil, nil, errors.New("cannot decode cmp slice from stream - no bytes provided") @@ -179,7 +170,7 @@ func decodeBUMPSliceFromStream(hexBytes []byte) (BUMPSlice, []byte, error) { } func decodeBUMPLeaves(nLeaves bt.VarInt, hexBytes []byte) (BUMPMap, []byte) { - bumpMap := make(map[string]BUMPTx) + bumpMap := make(map[uint64]BUMPTx) for i := 0; i < int(nLeaves); i++ { if len(hexBytes) < 1 { panic(fmt.Errorf("insufficient bytes to extract offset for %d leaf of %d leaves", i, int(nLeaves))) @@ -196,8 +187,7 @@ func decodeBUMPLeaves(nLeaves bt.VarInt, hexBytes []byte) (BUMPMap, []byte) { hexBytes = hexBytes[bytesUsed:] if flag == 1 { - key := strconv.FormatUint(uint64(offset), 10) - bumpMap[key] = BUMPTx{ + bumpMap[uint64(offset)] = BUMPTx{ duplicate: true, } continue @@ -213,11 +203,11 @@ func decodeBUMPLeaves(nLeaves bt.VarInt, hexBytes []byte) (BUMPMap, []byte) { hash = reverse(hash) if flag == 0 { - bumpMap[strconv.FormatUint(uint64(offset), 10)] = BUMPTx{ + bumpMap[uint64(offset)] = BUMPTx{ hash: hash, } } else { - bumpMap[strconv.FormatUint(uint64(offset), 10)] = BUMPTx{ + bumpMap[uint64(offset)] = BUMPTx{ hash: hash, txId: true, }