Skip to content

Commit

Permalink
Fix: Deserialization bug (#79)
Browse files Browse the repository at this point in the history
* only parse the hash if it’s there
* enhance: make sure to throw errors when the bytes are nonsensical
* also add tests for unusual transaction numbers.
* These paths should only have txid: true for their specific tx not the whole lot.

---------

Signed-off-by: Darren Kellenschwiler <d.kellenschwiler@bsvblockchain.org>
  • Loading branch information
sirdeggen authored Nov 20, 2023
1 parent a31145d commit 6f0ecba
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 3 deletions.
18 changes: 15 additions & 3 deletions bump.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ type leaf struct {

// NewBUMPFromBytes creates a new BUMP from a byte slice.
func NewBUMPFromBytes(bytes []byte) (*BUMP, error) {
if len(bytes) < 37 {
return nil, errors.New("BUMP bytes do not contain enough data to be valid")
}
bump := &BUMP{}

// first bytes are the block height.
Expand All @@ -50,6 +53,9 @@ func NewBUMPFromBytes(bytes []byte) (*BUMP, error) {
n, size := bt.NewVarIntFromBytes(bytes[skip:])
skip += size
nLeavesAtThisHeight := uint64(n)
if nLeavesAtThisHeight == 0 {
return nil, errors.New("There are no leaves at height: " + fmt.Sprint(lv) + " which makes this invalid")
}
bump.Path[lv] = make([]leaf, nLeavesAtThisHeight)
for lf := uint64(0); lf < nLeavesAtThisHeight; lf++ {
// For each leaf we parse the offset, hash, txid and duplicate.
Expand All @@ -65,6 +71,9 @@ func NewBUMPFromBytes(bytes []byte) (*BUMP, error) {
if dup {
l.Duplicate = &dup
} else {
if len(bytes) < skip+32 {
return nil, errors.New("BUMP bytes do not contain enough data to be valid")
}
h := StringFromBytesReverse(bytes[skip : skip+32])
l.Hash = &h
skip += 32
Expand Down Expand Up @@ -142,8 +151,11 @@ func (bump *BUMP) String() (string, error) {

// CalculateRootGivenTxid calculates the root of the Merkle tree given a txid.
func (bump *BUMP) CalculateRootGivenTxid(txid string) (string, error) {
if len(bump.Path) < 2 {
return txid, nil
if len(bump.Path) == 1 {
// if there is only one txid in the block then the root is the txid.
if len(bump.Path[0]) == 1 {
return txid, nil
}
}
// Find the index of the txid at the lowest level of the Merkle tree
var index uint64
Expand Down Expand Up @@ -233,7 +245,7 @@ func NewBUMPFromMerkleTreeAndIndex(blockHeight uint64, merkleTree []*chainhash.H
} else {
sh := hash.String()
thisLeaf.Hash = &sh
if height == 0 {
if height == 0 && txIndex == o {
thisLeaf.Txid = &t
}
}
Expand Down
36 changes: 36 additions & 0 deletions bump_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ const (
testnetHexExample = `0202ac5abbdc202bd6d50260825dd5465bd0798b052b2115c7abed277a41e403b21d0a61f6e257da3871657d324a31a449aa58a83b61967f1f2192eca71b3c21f68f`
testnetRootExample = `e4bbc8329d950749cb844ba2dac1e09bfc418d5c96d03fb688eff95bb90965b8`
testnetTxidExample = `8d15f64f8a35e94eb3cdbc07d9bc28952fdbdd13315fe3a94b393e635a9307aa`

twoTxExample = `fd0d020102000209d1fab394d14fc4d5819dffe7af320744b51469569fde7bd76c57c917d91ce10102b98551d22cd578c430374bde629322f72b72c9f64f5425ac307b679cfacd4525`
twoTxid = `2545cdfa9c677b30ac25544ff6c9722bf7229362de4b3730c478d52cd25185b9`

oneTxidHeightOne = `0101010102912f77eefdd311e24f96850ed8e701381fc4943327f9cf73f9c4dec0d93a056d`
)

var testnetBlockExample = []string{
Expand Down Expand Up @@ -116,3 +121,34 @@ func TestTestnetCalculateRootGivenTxid(t *testing.T) {
require.Equal(t, testnetRootExample, root)
}
}

func TestTwoTxsInBlock(t *testing.T) {
bump, err := NewBUMPFromStr(twoTxExample)
require.NoError(t, err)

_, err = bump.CalculateRootGivenTxid(twoTxid)
require.NoError(t, err)
}

func TestOneTxidHeightOne(t *testing.T) {
bump, err := NewBUMPFromStr(oneTxidHeightOne)
require.NoError(t, err)

_, err = bump.CalculateRootGivenTxid("6d053ad9c0dec4f973cff9273394c41f3801e7d80e85964fe211d3fdee772f91")
require.NoError(t, err)
}

func TestEmptyBytes(t *testing.T) {
_, err := NewBUMPFromStr("")
require.Error(t, err)
}

func TestTooFewBytes(t *testing.T) {
_, err := NewBUMPFromStr("01010101026d053ad9c0dec4f973cff9273394c41f3801e7d80e85964fe211d3fdee772f")
require.Error(t, err)
}

func TestNotEnoughLeavesInHeight(t *testing.T) {
_, err := NewBUMPFromStr("01020101026d053ad9c0dec4f973cff9273394c41f3801e7d80e85964fe211d3fdee772f9100")
require.Error(t, err)
}

0 comments on commit 6f0ecba

Please sign in to comment.