arnaucube
arnaucube/arboPublic Self-hosted repository
Update VT goroutines errs & Update Pack&UnpackSibl

- Update VT goroutines errs to avoid race condition
- Update pack & unpack siblings to use 2-byte for full length & bitmap
bytes length
- Add check in UnpackSiblings to avoid panic
arnaucube root@arnaucube.com
Mon, 20 Sep 2021 18:09:32 +0200
commit

ed0cf70d571001290860218e38733b27e03e5861

parent

f09b0b03925584ba934a30d124c55c33293a9cba

4 files changed, 25 insertions(+), 17 deletions(-)

jump to
M .gitignore → .gitignore

@@ -1,1 +1,2 @@

err-dump +covprofile
M tree.go → tree.go

@@ -73,7 +73,7 @@ )

// Tree defines the struct that implements the MerkleTree functionalities type Tree struct { - sync.RWMutex + sync.Mutex db db.Database maxLevels int

@@ -659,11 +659,12 @@ return leafK, leafV, s, true, nil

} // PackSiblings packs the siblings into a byte array. -// [ 1 byte | L bytes | S * N bytes ] -// [ bitmap length (L) | bitmap | N non-zero siblings ] +// [ 2 byte | 2 byte | L bytes | S * N bytes ] +// [ full length | bitmap length (L) | bitmap | N non-zero siblings ] // Where the bitmap indicates if the sibling is 0 or a value from the siblings // array. And S is the size of the output of the hash function used for the -// Tree. +// Tree. The 2 2-byte that define the full length and bitmap length, are +// encoded in little-endian. func PackSiblings(hashFunc HashFunction, siblings [][]byte) []byte { var b []byte var bitmap []bool

@@ -680,19 +681,28 @@

bitmapBytes := bitmapToBytes(bitmap) l := len(bitmapBytes) - res := make([]byte, l+1+len(b)) - res[0] = byte(l) // set the bitmapBytes length - copy(res[1:1+l], bitmapBytes) - copy(res[1+l:], b) + fullLen := 4 + l + len(b) //nolint:gomnd + res := make([]byte, fullLen) + binary.LittleEndian.PutUint16(res[0:2], uint16(fullLen)) // set full length + binary.LittleEndian.PutUint16(res[2:4], uint16(l)) // set the bitmapBytes length + copy(res[4:4+l], bitmapBytes) + copy(res[4+l:], b) return res } // UnpackSiblings unpacks the siblings from a byte array. func UnpackSiblings(hashFunc HashFunction, b []byte) ([][]byte, error) { - l := b[0] - bitmapBytes := b[1 : 1+l] + fullLen := binary.LittleEndian.Uint16(b[0:2]) + l := binary.LittleEndian.Uint16(b[2:4]) // bitmap bytes length + if len(b) != int(fullLen) { + return nil, + fmt.Errorf("error unpacking siblings. Expected len: %d, current len: %d", + fullLen, len(b)) + } + + bitmapBytes := b[4 : 4+l] bitmap := bytesToBitmap(bitmapBytes) - siblingsBytes := b[1+l:] + siblingsBytes := b[4+l:] iSibl := 0 emptySibl := make([]byte, hashFunc.Len()) var siblings [][]byte

@@ -845,9 +855,6 @@ }

// Snapshot returns a read-only copy of the Tree from the given root func (t *Tree) Snapshot(fromRoot []byte) (*Tree, error) { - t.RLock() - defer t.RUnlock() - // allow to define which root to use if fromRoot == nil { var err error
M tree_test.go → tree_test.go

@@ -311,7 +311,7 @@ tree, err := NewTree(database, 100, HashFunctionPoseidon)

c.Assert(err, qt.IsNil) defer tree.db.Close() //nolint:errcheck - bLen := tree.HashFunction().Len() + bLen := tree.HashFunction().Len() - 1 for i := 0; i < 10; i++ { k := BigIntToBytes(bLen, big.NewInt(int64(i))) v := BigIntToBytes(bLen, big.NewInt(int64(i*2)))
M vt.go → vt.go

@@ -176,7 +176,7 @@ go func(cpu int) {

bucketVT := newVT(t.params.maxLevels, t.params.hashFunction) bucketVT.root = nodesAtL[cpu] for j := 0; j < len(buckets[cpu]); j++ { - if err = bucketVT.add(l, buckets[cpu][j].k, buckets[cpu][j].v); err != nil { + if err := bucketVT.add(l, buckets[cpu][j].k, buckets[cpu][j].v); err != nil { invalidsInBucket[cpu] = append(invalidsInBucket[cpu], buckets[cpu][j].pos) } }

@@ -321,7 +321,7 @@ go func(cpu int) {

bucketVT := newVT(t.params.maxLevels, t.params.hashFunction) bucketVT.params.dbg = newDbgStats() bucketVT.root = nodesAtL[cpu] - + var err error bucketPairs[cpu], err = bucketVT.root.computeHashes(l-1, t.params.maxLevels, bucketVT.params, bucketPairs[cpu]) if err != nil {