forked from txaty/go-merkletree
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor: 1. Removed goroutine pool (gool). Using goroutine pool causes overhead and increases the complexity of the code base. 2. Changed the proof generation method. Now proofGen parallelized algorithm doesn't require two buffers. 3. Added fuzzing test. 4. More unit tests were added to achieve 100% coverage. 5. Refactored many methods and functions. 6. Extracted methods and functions to separate files to increase readability. Signed-off-by: txaty <[email protected]>
- Loading branch information
Showing
21 changed files
with
2,460 additions
and
1,742 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,114 @@ | ||
name: Go Build | ||
name: Go Build, Test, and Analyze Pipeline | ||
|
||
on: | ||
push: | ||
branches: [ "main" ] | ||
pull_request: | ||
branches: [ "main" ] | ||
|
||
env: | ||
GO_VERSION: 1.21 | ||
|
||
jobs: | ||
|
||
build: | ||
name: Build | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Set up Go | ||
uses: actions/setup-go@v4 | ||
with: | ||
go-version-file: './go.mod' | ||
go-version: ${{ env.GO_VERSION }} | ||
|
||
- name: Cache Go modules | ||
uses: actions/cache@v3 | ||
with: | ||
path: ~/go/pkg/mod | ||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} | ||
restore-keys: | | ||
${{ runner.os }}-go- | ||
- name: Build | ||
run: make build | ||
|
||
- name: Test | ||
run: make test_race | ||
test: | ||
name: Unit Test | ||
needs: build | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Set up Go | ||
uses: actions/setup-go@v4 | ||
with: | ||
go-version: ${{ env.GO_VERSION }} | ||
|
||
- name: Unit Test with Mocking | ||
run: make test_with_mock | ||
|
||
lint: | ||
name: Linting with golangci-lint | ||
needs: test | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Set up Go | ||
uses: actions/setup-go@v4 | ||
with: | ||
go-version: ${{ env.GO_VERSION }} | ||
|
||
- name: Run golangci-lint | ||
uses: golangci/golangci-lint-action@v3 | ||
|
||
coverage: | ||
name: Coverage and Codecov Upload | ||
needs: lint | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Set up Go | ||
uses: actions/setup-go@v4 | ||
with: | ||
go-version: ${{ env.GO_VERSION }} | ||
|
||
- name: Run coverage | ||
run: make test_ci_coverage | ||
|
||
- name: Upload coverage to Codecov | ||
uses: codecov/codecov-action@v3 | ||
if: success() | ||
|
||
analysis: | ||
name: Codacy Analysis | ||
needs: coverage | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Set up Go | ||
uses: actions/setup-go@v4 | ||
with: | ||
go-version: ${{ env.GO_VERSION }} | ||
|
||
- name: Codacy Analysis CLI | ||
uses: codacy/codacy-analysis-cli-action@master | ||
if: success() | ||
|
||
fuzz: | ||
name: Fuzzing Test | ||
needs: build | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Set up Go | ||
uses: actions/setup-go@v4 | ||
with: | ||
go-version: ${{ env.GO_VERSION }} | ||
|
||
- name: Run Fuzzing Tests | ||
run: make test_fuzz |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// MIT License | ||
// | ||
// Copyright (c) 2023 Tommy TIAN | ||
// | ||
// Permission is hereby granted, free of charge, to any person obtaining a copy | ||
// of this software and associated documentation files (the "Software"), to deal | ||
// in the Software without restriction, including without limitation the rights | ||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
// copies of the Software, and to permit persons to whom the Software is | ||
// furnished to do so, subject to the following conditions: | ||
// | ||
// The above copyright notice and this permission notice shall be included in all | ||
// copies or substantial portions of the Software. | ||
// | ||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
// SOFTWARE. | ||
|
||
// Package merkletree implements a high-performance Merkle Tree in Go. | ||
// It supports parallel execution for enhanced performance and | ||
// offers compatibility with OpenZeppelin through sorted sibling pairs. | ||
package merkletree | ||
|
||
// DataBlock is the interface for input data blocks used to generate the Merkle Tree. | ||
// Implementations of DataBlock should provide a serialization method | ||
// that converts the data block into a byte slice for hashing purposes. | ||
type DataBlock interface { | ||
// Serialize converts the data block into a byte slice. | ||
// It returns the serialized byte slice and an error, if any occurs during the serialization process. | ||
Serialize() ([]byte, error) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// MIT License | ||
// | ||
// Copyright (c) 2023 Tommy TIAN | ||
// | ||
// Permission is hereby granted, free of charge, to any person obtaining a copy | ||
// of this software and associated documentation files (the "Software"), to deal | ||
// in the Software without restriction, including without limitation the rights | ||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
// copies of the Software, and to permit persons to whom the Software is | ||
// furnished to do so, subject to the following conditions: | ||
// | ||
// The above copyright notice and this permission notice shall be included in all | ||
// copies or substantial portions of the Software. | ||
// | ||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
// SOFTWARE. | ||
|
||
// Package merkletree implements a high-performance Merkle Tree in Go. | ||
// It supports parallel execution for enhanced performance and | ||
// offers compatibility with OpenZeppelin through sorted sibling pairs. | ||
package merkletree | ||
|
||
import "errors" | ||
|
||
var ( | ||
// ErrInvalidNumOfDataBlocks is the error for an invalid number of data blocks. | ||
ErrInvalidNumOfDataBlocks = errors.New("the number of data blocks must be greater than 1") | ||
// ErrInvalidConfigMode is the error for an invalid configuration mode. | ||
ErrInvalidConfigMode = errors.New("invalid configuration mode") | ||
// ErrProofIsNil is the error for a nil proof. | ||
ErrProofIsNil = errors.New("proof is nil") | ||
// ErrDataBlockIsNil is the error for a nil data block. | ||
ErrDataBlockIsNil = errors.New("data block is nil") | ||
// ErrProofInvalidModeTreeNotBuilt is the error for an invalid mode in Proof() function. | ||
// Proof() function requires a built tree to generate the proof. | ||
ErrProofInvalidModeTreeNotBuilt = errors.New("merkle tree is not in built, could not generate proof by this method") | ||
// ErrProofInvalidDataBlock is the error for an invalid data block in Proof() function. | ||
ErrProofInvalidDataBlock = errors.New("data block is not a member of the merkle tree") | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
// MIT License | ||
// | ||
// Copyright (c) 2023 Tommy TIAN | ||
// | ||
// Permission is hereby granted, free of charge, to any person obtaining a copy | ||
// of this software and associated documentation files (the "Software"), to deal | ||
// in the Software without restriction, including without limitation the rights | ||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
// copies of the Software, and to permit persons to whom the Software is | ||
// furnished to do so, subject to the following conditions: | ||
// | ||
// The above copyright notice and this permission notice shall be included in all | ||
// copies or substantial portions of the Software. | ||
// | ||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
// SOFTWARE. | ||
|
||
// Package merkletree implements a high-performance Merkle Tree in Go. | ||
// It supports parallel execution for enhanced performance and | ||
// offers compatibility with OpenZeppelin through sorted sibling pairs. | ||
package merkletree | ||
|
||
import "golang.org/x/sync/errgroup" | ||
|
||
// computeLeafNodes compute the leaf nodes from the data blocks. | ||
func (m *MerkleTree) computeLeafNodes(blocks []DataBlock) ([][]byte, error) { | ||
var ( | ||
leaves = make([][]byte, m.NumLeaves) | ||
hashFunc = m.HashFunc | ||
disableLeafHashing = m.DisableLeafHashing | ||
err error | ||
) | ||
for i := 0; i < m.NumLeaves; i++ { | ||
if leaves[i], err = dataBlockToLeaf(blocks[i], hashFunc, disableLeafHashing); err != nil { | ||
return nil, err | ||
} | ||
} | ||
return leaves, nil | ||
} | ||
|
||
// computeLeafNodesParallel compute the leaf nodes from the data blocks in parallel. | ||
func (m *MerkleTree) computeLeafNodesParallel(blocks []DataBlock) ([][]byte, error) { | ||
var ( | ||
lenLeaves = len(blocks) | ||
leaves = make([][]byte, lenLeaves) | ||
numRoutines = m.NumRoutines | ||
hashFunc = m.HashFunc | ||
disableLeafHashing = m.DisableLeafHashing | ||
eg = new(errgroup.Group) | ||
) | ||
numRoutines = min(numRoutines, lenLeaves) | ||
for startIdx := 0; startIdx < numRoutines; startIdx++ { | ||
startIdx := startIdx | ||
eg.Go(func() error { | ||
var err error | ||
for i := startIdx; i < lenLeaves; i += numRoutines { | ||
if leaves[i], err = dataBlockToLeaf(blocks[i], hashFunc, disableLeafHashing); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
}) | ||
} | ||
if err := eg.Wait(); err != nil { | ||
return nil, err | ||
} | ||
return leaves, nil | ||
} | ||
|
||
// dataBlockToLeaf generates the leaf from the data block. | ||
// If the leaf hashing is disabled, the data block is returned as the leaf. | ||
func dataBlockToLeaf(block DataBlock, hashFunc TypeHashFunc, disableLeafHashing bool) ([]byte, error) { | ||
blockBytes, err := block.Serialize() | ||
if err != nil { | ||
return nil, err | ||
} | ||
if disableLeafHashing { | ||
// copy the value so that the original byte slice is not modified | ||
leaf := make([]byte, len(blockBytes)) | ||
copy(leaf, blockBytes) | ||
return leaf, nil | ||
} | ||
return hashFunc(blockBytes) | ||
} |
Oops, something went wrong.