├── CHANGELOG.md ├── docs └── .gitignore ├── config └── config.go ├── AUTHORS.md ├── .dockerignore ├── contrib ├── git │ ├── .gitconfig.tmp │ └── .gitmessage.tmp └── LICENSE-APPLY ├── test └── test_cov.sh ├── .gitattributes ├── scripts ├── unit_test_cov.sh ├── changelog.sh ├── check_spelling.sh ├── install_behave.sh ├── ensure_deps.sh └── check_license.sh ├── .codecov.yml ├── README.md ├── dependencies.txt ├── .gitignore ├── tools ├── merkle_tree_test.go ├── tools.go ├── tools_test.go └── merkle_tree.go ├── .circleci └── config.yml ├── version └── version.go ├── common ├── common.go └── common_test.go ├── CONTRIBUTING.md ├── Makefile ├── producer.go ├── producer_test.go └── LICENSE /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type ProducerConfig struct { 4 | EnableSignatureVerify bool 5 | ChainId uint64 6 | } 7 | -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | # Credits 2 | 3 | ## Development Lead 4 | 5 | - walterkangluo [DSiSc](https://github.com/DSiSc) 6 | 7 | ## Contributors 8 | 9 | None yet. Why not be the first? 10 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright(c) 2018 DSiSc Group. All Rights Reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | # 6 | .git 7 | .circleci 8 | .github 9 | .codecov.yml 10 | .mailmap 11 | .travis.yml 12 | -------------------------------------------------------------------------------- /contrib/git/.gitconfig.tmp: -------------------------------------------------------------------------------- 1 | [commit] 2 | template = ~/.gitmessage 3 | 4 | [alias] 5 | co = checkout 6 | ci = commit 7 | br = branch 8 | st = status 9 | last = log -1 10 | lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit 11 | -------------------------------------------------------------------------------- /test/test_cov.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -e 4 | 5 | echo "" > coverage.txt 6 | 7 | for pkg in $(go list ./... | grep -v vendor); do 8 | go test -timeout 5m -race -coverprofile=profile.cov -covermode=atomic "$pkg" 9 | if [ -f profile.cov ]; then 10 | cat profile.cov >> coverage.txt 11 | rm profile.cov 12 | fi 13 | done 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | *.sh text eol=lf 5 | *.go text eol=lf 6 | *.yaml text eol=lf 7 | *.yml text eol=lf 8 | *.md text eol=lf 9 | *.json text eol=lf 10 | *.proto text eol=lf 11 | *.py text eol=lf 12 | *.js text eol=lf 13 | *.txt text eol=lf 14 | *.sol linguist-language=Solidity 15 | LICENSE text eol=lf 16 | -------------------------------------------------------------------------------- /scripts/unit_test_cov.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -e 4 | 5 | # Change directory to project root folder 6 | PROJ_FOLDER=$(cd "$(dirname "$0")/..";pwd) 7 | cd $PROJ_FOLDER 8 | 9 | echo "" > coverage.txt 10 | 11 | for pkg in $(go list ./... | grep -v vendor); do 12 | go test -timeout 5m -race -coverprofile=profile.cov -covermode=atomic "$pkg" 13 | if [ -f profile.cov ]; then 14 | cat profile.cov >> coverage.txt 15 | rm profile.cov 16 | fi 17 | done 18 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | notify: 3 | require_ci_to_pass: yes 4 | 5 | coverage: 6 | precision: 2 7 | round: down 8 | range: "50...80" 9 | 10 | status: 11 | project: yes 12 | patch: yes 13 | changes: no 14 | 15 | parsers: 16 | gcov: 17 | branch_detection: 18 | conditional: yes 19 | loop: yes 20 | method: no 21 | macro: no 22 | 23 | comment: 24 | layout: "header, diff" 25 | behavior: default 26 | require_changes: no 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # producer 2 | 3 | Implementation of producer which is responsible for producing block. 4 | 5 | [![Build Status](https://circleci.com/gh/DSiSc/producer/tree/master.svg?style=shield)](https://circleci.com/gh/DSiSc/producer/tree/master) 6 | [![codecov](https://codecov.io/gh/DSiSc/producer/branch/master/graph/badge.svg)](https://codecov.io/gh/DSiSc/producer) 7 | 8 | ## Getting started 9 | 10 | Running it then should be as simple as: 11 | 12 | ``` 13 | $ make all 14 | ``` 15 | 16 | ### Testing 17 | 18 | ``` 19 | $ make test 20 | ``` 21 | 22 | -------------------------------------------------------------------------------- /dependencies.txt: -------------------------------------------------------------------------------- 1 | # Imported packages that does not exsit under "vendor" folder. 2 | # The following lines listed by git repositories(each line for one git repo) 3 | # alone with compatible version(branch/tag/commit-id). 4 | 5 | github.com/DSiSc/craft:master 6 | github.com/DSiSc/txpool:master 7 | github.com/DSiSc/ledger:master 8 | github.com/DSiSc/repository:master 9 | github.com/DSiSc/blockstore:master 10 | github.com/DSiSc/statedb-NG:master 11 | github.com/DSiSc/validator:master 12 | github.com/DSiSc/monkey:master 13 | github.com/DSiSc/crypto-suite:master 14 | -------------------------------------------------------------------------------- /contrib/git/.gitmessage.tmp: -------------------------------------------------------------------------------- 1 | # head: (): 2 | # - type: feat, fix, docs, style, refactor, test, chore 3 | # - scope: can be empty (eg. if the change is a global or difficult to assign to a single component) 4 | # - subject: start with verb (such as 'change'), 50-character line 5 | # 6 | # body: 72-character wrapped. This should answer: 7 | # * Why was this change necessary? 8 | # * How does it address the problem? 9 | # * Are there any side effects? 10 | # 11 | # footer: 12 | # - Include a link to the ticket, if any. 13 | # - BREAKING CHANGE 14 | # 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile ~/.gitignore_global 6 | 7 | # govendor 8 | #vendor/ 9 | 10 | # IDEs 11 | .project 12 | .settings 13 | .idea 14 | .vscode 15 | 16 | # May be used by the Makefile 17 | build/_workspace/ 18 | build/_vendor/pkg 19 | build/bin/ 20 | 21 | # travis, codecov 22 | profile.tmp 23 | profile.cov 24 | coverage.txt 25 | 26 | # tmp 27 | *.sw? 28 | -------------------------------------------------------------------------------- /scripts/changelog.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright(c) 2018 DSiSc Group. All Rights Reserved. 4 | # 5 | # SPDX-License-Identifier: Apache-2.0 6 | # 7 | 8 | set -x 9 | 10 | SCRIPT_DIR=$(readlink -f "$(dirname $0)") 11 | CHANGELOG_TEMP="CHANGELOG.new" 12 | 13 | echo "## $2\n$(date)" >> ${CHANGELOG_TEMP} 14 | echo "" >> ${CHANGELOG_TEMP} 15 | git log $1..HEAD --oneline | grep -v Merge | sed -e "s/\([0-9|a-z]*\)/* \[\1\](https:\/\/github.com\/DSiSc\/producer\/commit\/\1)/" >> ${CHANGELOG_TEMP} 16 | echo "" >> ${CHANGELOG_TEMP} 17 | cat ${SCRIPT_DIR}/../CHANGELOG.md >> ${CHANGELOG_TEMP} 18 | mv -f ${CHANGELOG_TEMP} CHANGELOG.md 19 | -------------------------------------------------------------------------------- /contrib/LICENSE-APPLY: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2018 DSiSc Group. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | -------------------------------------------------------------------------------- /tools/merkle_tree_test.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "crypto/sha256" 5 | "github.com/DSiSc/craft/types" 6 | "github.com/stretchr/testify/assert" 7 | "testing" 8 | ) 9 | 10 | func Test_ComputeMerkleRoot(t *testing.T) { 11 | var data []types.Hash 12 | a1 := types.Hash(sha256.Sum256([]byte("a"))) 13 | a2 := types.Hash(sha256.Sum256([]byte("b"))) 14 | a3 := types.Hash(sha256.Sum256([]byte("c"))) 15 | a4 := types.Hash(sha256.Sum256([]byte("d"))) 16 | a5 := types.Hash(sha256.Sum256([]byte("e"))) 17 | data = append(data, a1) 18 | data = append(data, a2) 19 | data = append(data, a3) 20 | data = append(data, a4) 21 | data = append(data, a5) 22 | hash := ComputeMerkleRoot(data) 23 | assert.NotEqual(t, hash, types.Hash{}) 24 | } 25 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Golang CircleCI 2.0 configuration file 2 | 3 | version: 2 4 | 5 | jobs: 6 | build: 7 | 8 | docker: 9 | - image: circleci/golang:1.10.3 10 | working_directory: /go/src/github.com/DSiSc/producer 11 | 12 | steps: 13 | - checkout 14 | 15 | - run: 16 | name: Get dependencies 17 | command: make fetch-deps 18 | 19 | - run: 20 | name: Static checks 21 | command: make static-check 22 | 23 | - run: 24 | name: Correctness check 25 | command: make build && make vet 26 | 27 | - run: 28 | name: Test with coverage 29 | command: | 30 | make coverage 31 | bash <(curl -s https://codecov.io/bash) 32 | -------------------------------------------------------------------------------- /scripts/check_spelling.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright(c) 2018 DSiSc Group. All Rights Reserved. 4 | # 5 | # SPDX-License-Identifier: Apache-2.0 6 | # 7 | 8 | CHECK=$(git diff --name-only HEAD * | grep -v .png$ | grep -v .git | grep -v ^CHANGELOG \ 9 | | grep -v ^vendor/ | grep -v ^build/ | sort -u) 10 | 11 | if [[ -z "$CHECK" ]]; then 12 | CHECK=$(git diff-tree --no-commit-id --name-only -r $(git log -2 \ 13 | --pretty=format:"%h") | grep -v .png$ | grep -v .git | grep -v ^CHANGELOG \ 14 | | grep -v ^vendor/ | grep -v ^build/ | sort -u) 15 | fi 16 | 17 | echo "Checking changed go files for spelling errors ..." 18 | errs=`echo $CHECK | xargs misspell -source=text` 19 | if [ -z "$errs" ]; then 20 | echo "spell checker passed" 21 | exit 0 22 | fi 23 | echo "The following files are have spelling errors:" 24 | echo "$errs" 25 | exit 0 26 | -------------------------------------------------------------------------------- /tools/tools.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "encoding/hex" 5 | "github.com/DSiSc/craft/types" 6 | ) 7 | 8 | func HexToAddress(s string) types.Address { 9 | return BytesToAddress(FromHex(s)) 10 | } 11 | 12 | // FromHex returns the bytes represented by the hexadecimal string s. 13 | // s may be prefixed with "0x". 14 | func FromHex(s string) []byte { 15 | if len(s) > 1 { 16 | if s[0:2] == "0x" || s[0:2] == "0X" { 17 | s = s[2:] 18 | } 19 | } 20 | if len(s)%2 == 1 { 21 | s = "0" + s 22 | } 23 | return Hex2Bytes(s) 24 | } 25 | 26 | // Hex2Bytes returns the bytes represented by the hexadecimal string str. 27 | func Hex2Bytes(str string) []byte { 28 | h, _ := hex.DecodeString(str) 29 | return h 30 | } 31 | 32 | func BytesToAddress(b []byte) types.Address { 33 | var a types.Address 34 | SetBytes(b, &a) 35 | return a 36 | } 37 | 38 | func SetBytes(b []byte, a *types.Address) { 39 | if len(b) > len(a) { 40 | b = b[len(b)-types.AddressLength:] 41 | } 42 | copy(a[types.AddressLength-len(b):], b) 43 | } 44 | -------------------------------------------------------------------------------- /version/version.go: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2018 DSiSc Group. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package version 16 | 17 | // The git commit that was compiled. This will be filled in by the compiler. 18 | var GitCommit string 19 | 20 | // The main version number that is being run at the moment. 21 | const Version = "0.0.1" 22 | 23 | // A pre-release marker for the version. If this is "" (empty string) 24 | // then it means that it is a final release. Otherwise, this is a pre-release 25 | // such as "dev" (in development) 26 | var VersionPrerelease = "dev" 27 | 28 | var BuildDate = "" 29 | -------------------------------------------------------------------------------- /scripts/install_behave.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright(c) 2018 DSiSc Group. All Rights Reserved. 4 | # 5 | # SPDX-License-Identifier: Apache-2.0 6 | # 7 | 8 | 9 | # 10 | # This script is used on Debian based linux distros. 11 | # (i.e., linux that supports the apt packaging manager.) 12 | # 13 | 14 | # Update system 15 | apt-get update -qq 16 | 17 | # Install Python, pip, behave 18 | # 19 | # install python-dev and libyaml-dev to get compiled speedups 20 | apt-get install --yes python-dev 21 | apt-get install --yes libyaml-dev 22 | 23 | apt-get install --yes python-setuptools 24 | apt-get install --yes python-pip 25 | apt-get install --yes build-essential 26 | # required dependencies for cryptography, which is required by pyOpenSSL 27 | # https://cryptography.io/en/stable/installation/#building-cryptography-on-linux 28 | apt-get install --yes libssl-dev libffi-dev 29 | pip install --upgrade pip 30 | 31 | # Pip packages required for behave tests 32 | pip install -r ../devenv/bddtests-requirements.txt 33 | 34 | # install ruby and apiaryio 35 | #apt-get install --yes ruby ruby-dev gcc 36 | #gem install apiaryio 37 | 38 | # Install Tcl prerequisites for busywork 39 | apt-get install --yes tcl tclx tcllib 40 | 41 | # Install NPM for the SDK 42 | apt-get install --yes npm 43 | -------------------------------------------------------------------------------- /tools/tools_test.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "github.com/DSiSc/craft/types" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | ) 8 | 9 | var addr = types.Address{ 10 | 0x33, 0x3c, 0x33, 0x10, 0x82, 0x4b, 0x7c, 0x68, 0x51, 0x33, 11 | 0xf2, 0xbe, 0xdb, 0x2c, 0xa4, 0xb8, 0xb4, 0xdf, 0x63, 0x3d} 12 | 13 | func TestHexToAddress(t *testing.T) { 14 | assert := assert.New(t) 15 | address := HexToAddress("333c3310824b7c685133f2bedb2ca4b8b4df633d") 16 | assert.NotNil(address) 17 | assert.Equal(addr, address) 18 | } 19 | 20 | func TestBytesToAddress(t *testing.T) { 21 | assert := assert.New(t) 22 | var addr1 = []byte{ 23 | 0x33, 0x3c, 0x33, 0x10, 0x82, 0x4b, 0x7c, 0x68, 0x51, 0x33, 24 | 0xf2, 0xbe, 0xdb, 0x2c, 0xa4, 0xb8, 0xb4, 0xdf, 0x63, 0x3d} 25 | address := BytesToAddress(addr1) 26 | assert.Equal(addr, address) 27 | } 28 | 29 | func TestFromHex(t *testing.T) { 30 | assert := assert.New(t) 31 | oddStr := "0x12345" 32 | var oddExcept = []byte{ 33 | 0x1, 0x23, 0x45, 34 | } 35 | bytes := FromHex(oddStr) 36 | assert.Equal(oddExcept, bytes) 37 | evenStr := "0x123456" 38 | var evenExcept = []byte{ 39 | 0x12, 0x34, 0x56, 40 | } 41 | bytes = FromHex(evenStr) 42 | assert.Equal(evenExcept, bytes) 43 | } 44 | 45 | func TestHex2Bytes(t *testing.T) { 46 | assert := assert.New(t) 47 | oddStr := "12" 48 | var oddExcept = []byte{0x12} 49 | bytes := Hex2Bytes(oddStr) 50 | assert.Equal(oddExcept, bytes) 51 | } 52 | -------------------------------------------------------------------------------- /scripts/ensure_deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Change directory to project root folder 4 | PROJ_FOLDER=$(cd "$(dirname "$0")/..";pwd) 5 | cd $PROJ_FOLDER 6 | 7 | # Read "dependencies.txt" under project root 8 | DEPS=$(grep -v "^#" dependencies.txt | grep -v "^$") 9 | 10 | # Go get all the imported packages (except the ones under "vendor" folder) to $GOPATH 11 | for dep in $DEPS; do 12 | dep_repo=$(echo ${dep} | awk -F ':' '{print $1}') 13 | if [ -d "${GOPATH}/src/${dep_repo}" ]; then 14 | cd ${GOPATH}/src/${dep_repo} 15 | git checkout master &> /dev/null 16 | fi 17 | go get -v -u ${dep_repo} 18 | done 19 | 20 | # Check out to desired version 21 | for dep in $DEPS; do 22 | dep_repo=$(echo ${dep} | awk -F ':' '{print $1}') 23 | dep_ver=$(echo ${dep} | awk -F ':' '{print $2}') 24 | if [ -d "${GOPATH}/src/${dep_repo}" ]; then 25 | 26 | echo "[INFO] Ensuring ${dep_repo} on ${dep_ver} ..." 27 | 28 | cd ${GOPATH}/src/${dep_repo} 29 | 30 | git fetch origin > /dev/null 31 | 32 | # Try checkout to ${dep_ver} 33 | git checkout ${dep_ver} > /dev/null && (git pull &> /dev/null | true) 34 | 35 | if [ $? != 0 ]; then 36 | # If failed, checkout to origin/${dep_ver} 37 | git checkout origin/${dep_ver} > /dev/null 38 | if [ $? != 0 ]; then 39 | echo "[ERROR] Got error when checking out ${dep_ver} under ${dep_repo}, please check." 40 | exit 1 41 | else 42 | echo "[INFO] ${dep_repo} is now on ${dep_ver}" 43 | fi 44 | else 45 | echo "[INFO] ${dep_repo} is now on ${dep_ver}" 46 | fi 47 | else 48 | echo "[WARN] ${GOPATH}/src/${dep_repo} not exist, do nothing, please check dependencies.txt." 49 | fi 50 | done 51 | 52 | -------------------------------------------------------------------------------- /scripts/check_license.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright(c) 2018 DSiSc Corp, SecureKey Technologies Inc. All Rights Reserved. 4 | # 5 | # SPDX-License-Identifier: Apache-2.0 6 | # 7 | 8 | 9 | function filterGeneratedFiles { 10 | for f in $@; do 11 | head -n2 $f | grep -qE '// Code generated by' || echo $f 12 | done 13 | } 14 | 15 | function filterExcludedFiles { 16 | CHECK=`echo "$CHECK" | grep -v .png$ | grep -v .rst$ | grep -v ^.git/ \ 17 | | grep -v .pem$ | grep -v .block$ | grep -v .tx$ | grep -v ^LICENSE$ | grep -v _sk$ \ 18 | | grep -v .key$ | grep -v \\.gen.go$ | grep -v ^Gopkg.lock$ \ 19 | | grep -v .md$ | grep -v ^vendor/ | grep -v ^build/ | grep -v .pb.go$ | sort -u` 20 | 21 | CHECK=$(filterGeneratedFiles "$CHECK") 22 | } 23 | 24 | CHECK=$(git diff --name-only --diff-filter=ACMRTUXB HEAD) 25 | filterExcludedFiles 26 | if [[ -z "$CHECK" ]]; then 27 | LAST_COMMITS=($(git log -2 --pretty=format:"%h")) 28 | CHECK=$(git diff-tree --no-commit-id --name-only --diff-filter=ACMRTUXB -r ${LAST_COMMITS[1]} ${LAST_COMMITS[0]}) 29 | filterExcludedFiles 30 | fi 31 | 32 | if [[ -z "$CHECK" ]]; then 33 | echo "All files are excluded from having license headers" 34 | exit 0 35 | fi 36 | 37 | missing=`echo "$CHECK" | xargs ls -d 2>/dev/null | xargs grep -L "SPDX-License-Identifier"` 38 | if [[ -z "$missing" ]]; then 39 | echo "All files have SPDX-License-Identifier headers" 40 | exit 0 41 | fi 42 | echo "The following files are missing SPDX-License-Identifier headers:" 43 | echo "$missing" 44 | echo 45 | echo "Please replace the Apache license header comment text with:" 46 | echo "SPDX-License-Identifier: Apache-2.0" 47 | 48 | echo 49 | echo "Checking committed files for traditional Apache License headers ..." 50 | missing=`echo "$missing" | xargs ls -d 2>/dev/null | xargs grep -L "http://www.apache.org/licenses/LICENSE-2.0"` 51 | if [[ -z "$missing" ]]; then 52 | echo "All remaining files have Apache 2.0 headers" 53 | exit 0 54 | fi 55 | echo "The following files are missing traditional Apache 2.0 headers:" 56 | echo "$missing" 57 | echo "Fatal Error - All files must have a license header" 58 | exit 1 59 | -------------------------------------------------------------------------------- /tools/merkle_tree.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "bytes" 5 | "crypto/sha256" 6 | "errors" 7 | "github.com/DSiSc/craft/types" 8 | "io" 9 | ) 10 | 11 | type merkleTreeNode struct { 12 | Hash types.Hash 13 | Left *merkleTreeNode 14 | Right *merkleTreeNode 15 | } 16 | 17 | type merkleTree struct { 18 | Depth uint 19 | Root *merkleTreeNode 20 | } 21 | 22 | func SerializeHash(w io.Writer, u *types.Hash) error { 23 | _, err := w.Write(u[:]) 24 | return err 25 | } 26 | 27 | //Generate the leaves nodes 28 | func generateLeaves(hashes []types.Hash) []*merkleTreeNode { 29 | var leaves []*merkleTreeNode 30 | for _, d := range hashes { 31 | node := &merkleTreeNode{ 32 | Hash: d, 33 | } 34 | leaves = append(leaves, node) 35 | } 36 | return leaves 37 | } 38 | 39 | //calc the next level's hash use double sha256 40 | func levelUp(nodes []*merkleTreeNode) []*merkleTreeNode { 41 | var nextLevel []*merkleTreeNode 42 | for i := 0; i < len(nodes)/2; i++ { 43 | var data []types.Hash 44 | data = append(data, nodes[i*2].Hash) 45 | data = append(data, nodes[i*2+1].Hash) 46 | hash := doubleSha256(data) 47 | node := &merkleTreeNode{ 48 | Hash: hash, 49 | Left: nodes[i*2], 50 | Right: nodes[i*2+1], 51 | } 52 | nextLevel = append(nextLevel, node) 53 | } 54 | if len(nodes)%2 == 1 { 55 | var data []types.Hash 56 | data = append(data, nodes[len(nodes)-1].Hash) 57 | data = append(data, nodes[len(nodes)-1].Hash) 58 | hash := doubleSha256(data) 59 | node := &merkleTreeNode{ 60 | Hash: hash, 61 | Left: nodes[len(nodes)-1], 62 | Right: nodes[len(nodes)-1], 63 | } 64 | nextLevel = append(nextLevel, node) 65 | } 66 | return nextLevel 67 | } 68 | 69 | func doubleSha256(s []types.Hash) types.Hash { 70 | b := new(bytes.Buffer) 71 | for _, d := range s { 72 | SerializeHash(b, &d) 73 | } 74 | temp := sha256.Sum256(b.Bytes()) 75 | f := sha256.Sum256(temp[:]) 76 | return types.Hash(f) 77 | } 78 | 79 | func newMerkleTree(hashes []types.Hash) (*merkleTree, error) { 80 | if len(hashes) == 0 { 81 | return nil, errors.New("new MerkleTree input no item error") 82 | } 83 | var height uint 84 | 85 | height = 1 86 | nodes := generateLeaves(hashes) 87 | for len(nodes) > 1 { 88 | nodes = levelUp(nodes) 89 | height += 1 90 | } 91 | mt := &merkleTree{ 92 | Root: nodes[0], 93 | Depth: height, 94 | } 95 | return mt, nil 96 | } 97 | 98 | func ComputeMerkleRoot(hashes []types.Hash) types.Hash { 99 | if len(hashes) == 0 { 100 | return types.Hash{} 101 | } 102 | if len(hashes) == 1 { 103 | return hashes[0] 104 | } 105 | tree, _ := newMerkleTree(hashes) 106 | return tree.Root.Hash 107 | } 108 | -------------------------------------------------------------------------------- /common/common.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | gconf "github.com/DSiSc/craft/config" 7 | "github.com/DSiSc/craft/log" 8 | "github.com/DSiSc/craft/types" 9 | "github.com/DSiSc/crypto-suite/crypto/sha3" 10 | ) 11 | 12 | // Sum returns the first 32 bytes of hash of the bz. 13 | func Sum(bz []byte) []byte { 14 | var alg string 15 | if value, ok := gconf.GlobalConfig.Load(gconf.HashAlgName); ok { 16 | alg = value.(string) 17 | } else { 18 | alg = "SHA256" 19 | } 20 | hasher := sha3.NewHashByAlgName(alg) 21 | hasher.Write(bz) 22 | hash := hasher.Sum(nil) 23 | return hash[:types.HashLength] 24 | } 25 | 26 | func TxHash(tx *types.Transaction) types.Hash { 27 | if hash := tx.Hash.Load(); hash != nil { 28 | return hash.(types.Hash) 29 | } 30 | hashData := types.TxData{ 31 | AccountNonce: tx.Data.AccountNonce, 32 | Price: tx.Data.Price, 33 | GasLimit: tx.Data.GasLimit, 34 | Recipient: tx.Data.Recipient, 35 | Amount: tx.Data.Amount, 36 | Payload: tx.Data.Payload, 37 | V: tx.Data.V, 38 | R: tx.Data.R, 39 | S: tx.Data.S, 40 | } 41 | jsonByte, _ := json.Marshal(hashData) 42 | sumByte := Sum(jsonByte) 43 | var temp types.Hash 44 | copy(temp[:], sumByte) 45 | tx.Hash.Store(temp) 46 | return temp 47 | } 48 | 49 | func HeaderHash(block *types.Block) (hash types.Hash) { 50 | var defaultHash types.Hash 51 | if !bytes.Equal(block.HeaderHash[:], defaultHash[:]) { 52 | log.Info("block hash %v has exits.", block.HeaderHash) 53 | copy(hash[:], block.HeaderHash[:]) 54 | return 55 | } 56 | jsonByte, _ := json.Marshal(block.Header) 57 | sumByte := Sum(jsonByte) 58 | copy(hash[:], sumByte) 59 | return 60 | } 61 | 62 | func HeaderDigest(header *types.Header) (hash types.Hash) { 63 | var defaultHash types.Hash 64 | if !bytes.Equal(header.MixDigest[:], defaultHash[:]) { 65 | log.Info("header hash %x has exits.", header.MixDigest) 66 | copy(hash[:], header.MixDigest[:]) 67 | return 68 | } 69 | newHeader := digestHeader(header) 70 | jsonByte, _ := json.Marshal(newHeader) 71 | sumByte := Sum(jsonByte) 72 | copy(hash[:], sumByte) 73 | return 74 | } 75 | 76 | func digestHeader(header *types.Header) *types.Header { 77 | return &types.Header{ 78 | ChainID: header.ChainID, 79 | PrevBlockHash: header.PrevBlockHash, 80 | StateRoot: header.StateRoot, 81 | TxRoot: header.TxRoot, 82 | ReceiptsRoot: header.ReceiptsRoot, 83 | Height: header.Height, 84 | Timestamp: header.Timestamp, 85 | CoinBase: header.CoinBase, 86 | } 87 | } 88 | 89 | func CopyBytes(b []byte) (copiedBytes []byte) { 90 | if len(b) == 0 { 91 | return 92 | } 93 | copiedBytes = make([]byte, len(b)) 94 | copy(copiedBytes, b) 95 | 96 | return 97 | } 98 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given. 4 | 5 | You can contribute in many ways: 6 | 7 | ## Types of Contributions 8 | 9 | ### Report Bugs 10 | 11 | Report bugs at https://github.com/DSiSc/producer/issues. 12 | 13 | If you are reporting a bug, please include: 14 | 15 | * Your operating system name and version. 16 | * Any details about your local setup that might be helpful in troubleshooting. 17 | * Detailed steps to reproduce the bug. 18 | 19 | ### Fix Bugs 20 | 21 | Look through the GitHub issues for bugs. Anything tagged with "bug" 22 | is open to whoever wants to implement it. 23 | 24 | ### Implement Features 25 | 26 | Look through the GitHub issues for features. Anything tagged with "feature" 27 | is open to whoever wants to implement it. 28 | 29 | ### Write Documentation 30 | 31 | producer could always use more documentation, whether as part of the 32 | official producer docs, in docstrings, or even on the web in blog posts, 33 | articles, and such. 34 | 35 | ### Submit Feedback 36 | 37 | The best way to send feedback is to file an issue at https://github.com/DSiSc/producer/issues. 38 | 39 | If you are proposing a feature: 40 | 41 | * Explain in detail how it would work. 42 | * Keep the scope as narrow as possible, to make it easier to implement. 43 | * Remember that this is a volunteer-driven project, and that contributions 44 | are welcome :) 45 | 46 | ## Get Started! 47 | 48 | Ready to contribute? Here's how to set up `producer` for local development. 49 | 50 | 1. Fork the `producer` repo on GitHub. 51 | 2. Clone your fork locally:: 52 | 53 | $ git clone git@github.com:your_name_here/producer.git 54 | 55 | 3. Create a branch for local development:: 56 | 57 | $ git checkout -b name-of-your-bugfix-or-feature 58 | 59 | Now you can make your changes locally. 60 | 61 | 4. When you're done making changes, check that your changes pass the tests:: 62 | 63 | $ make test 64 | 65 | 6. Commit your changes and push your branch to GitHub, We use [Angular Commit Guidelines](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#-git-commit-guidelines), Thanks for Angular good job.:: 66 | 67 | $ git add . 68 | $ git commit -m "Your detailed description of your changes." 69 | $ git push origin name-of-your-bugfix-or-feature 70 | 71 | 7. Submit a pull request through the GitHub website. 72 | 73 | Pull Request Guidelines 74 | ----------------------- 75 | 76 | Before you submit a pull request, check that it meets these guidelines: 77 | 78 | 1. The pull request should include tests. 79 | 2. If the pull request adds functionality, the docs should be updated. Put 80 | your new functionality into a function with a docstring, and add the 81 | feature to the list in README.md. 82 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright(c) 2018 DSiSc Group. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | VERSION=$(shell grep "const Version" version/version.go | sed -E 's/.*"(.+)"$$/\1/') 16 | GIT_COMMIT=$(shell git rev-parse HEAD) 17 | GIT_DIRTY=$(shell test -n "`git status --porcelain`" && echo "+CHANGES" || true) 18 | BUILD_DATE=$(shell date '+%Y-%m-%d-%H:%M:%S') 19 | 20 | .PHONY: default help all build test unit-test devenv gotools clean coverage 21 | 22 | default: all 23 | 24 | help: 25 | @echo 'Management commands for DSiSc/producer:' 26 | @echo 27 | @echo 'Usage:' 28 | @echo ' make lint Check code style.' 29 | @echo ' make spelling Check code spelling.' 30 | @echo ' make fmt Check code formatting.' 31 | @echo ' make static-check Static code check: style & spelling & formatting.' 32 | @echo ' make build Compile the project.' 33 | @echo ' make vet Examine source code and reports suspicious constructs.' 34 | @echo ' make unit-test Run unit tests with coverage report.' 35 | @echo ' make test Run unit tests with coverage report.' 36 | @echo ' make devenv Prepare devenv for test or build.' 37 | @echo ' make fetch-deps Run govendor fetch for deps.' 38 | @echo ' make gotools Prepare go tools depended.' 39 | @echo ' make clean Clean the directory tree.' 40 | @echo 41 | 42 | all: static-check build test 43 | 44 | fmt: 45 | gofmt -d -l . 46 | 47 | spelling: 48 | bash scripts/check_spelling.sh 49 | 50 | lint: 51 | @echo "Check code style..." 52 | golint `go list ./...` 53 | 54 | static-check: fmt spelling lint 55 | 56 | build: 57 | @echo "building producer ${VERSION}" 58 | @echo "GOPATH=${GOPATH}" 59 | go build -v -ldflags "-X github.com/DSiSc/producer/version.GitCommit=${GIT_COMMIT}${GIT_DIRTY} -X github.com/DSiSc/producer/version.BuildDate=${BUILD_DATE}" ./... 60 | 61 | vet: 62 | @echo "Examine source code and reports suspicious constructs..." 63 | go vet `go list ./...` 64 | 65 | unit-test: 66 | @echo "Run unit tests without coverage report..." 67 | go test -v -count=1 -race ./... 68 | 69 | coverage: 70 | @echo "Run unit tests with coverage report..." 71 | bash scripts/unit_test_cov.sh 72 | 73 | test: vet unit-test 74 | 75 | get-tools: 76 | # official tools 77 | go get -u golang.org/x/lint/golint 78 | @# go get -u golang.org/x/tools/cmd/gotype 79 | @# go get -u golang.org/x/tools/cmd/goimports 80 | @# go get -u golang.org/x/tools/cmd/godoc 81 | @# go get -u golang.org/x/tools/cmd/gorename 82 | @# go get -u golang.org/x/tools/cmd/gomvpkg 83 | 84 | # thirdparty tools 85 | go get -u github.com/stretchr/testify 86 | @# go get -u github.com/kardianos/govendor 87 | @# go get -u github.com/axw/gocov/... 88 | @# go get -u github.com/client9/misspell/cmd/misspell 89 | 90 | fetch-deps: get-tools 91 | @echo "Run go get to fetch dependencies as described in dependencies.txt ..." 92 | @bash scripts/ensure_deps.sh 93 | 94 | ## tools & deps 95 | devenv: get-tools fetch-deps 96 | -------------------------------------------------------------------------------- /producer.go: -------------------------------------------------------------------------------- 1 | package producer 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "github.com/DSiSc/craft/log" 7 | "github.com/DSiSc/craft/types" 8 | "github.com/DSiSc/producer/common" 9 | "github.com/DSiSc/producer/config" 10 | "github.com/DSiSc/producer/tools" 11 | "github.com/DSiSc/repository" 12 | "github.com/DSiSc/txpool" 13 | "github.com/DSiSc/validator/tools/account" 14 | "github.com/DSiSc/validator/tools/signature" 15 | "github.com/DSiSc/validator/worker" 16 | "time" 17 | ) 18 | 19 | type Producer struct { 20 | txpool txpool.TxsPool 21 | time uint64 22 | // TODO: we support many workers to promote verification speed in the future 23 | workers *worker.Worker 24 | account account.Account 25 | enableSignVerify bool 26 | chainId uint64 27 | } 28 | 29 | func NewProducer(pool txpool.TxsPool, account account.Account, producerConfig config.ProducerConfig) *Producer { 30 | return &Producer{ 31 | txpool: pool, 32 | account: account, 33 | enableSignVerify: producerConfig.EnableSignatureVerify, 34 | chainId: producerConfig.ChainId, 35 | } 36 | } 37 | 38 | func (self *Producer) MakeBlock() (*types.Block, error) { 39 | // Get latest block store and state store 40 | blockStore, ok := repository.NewLatestStateRepository() 41 | if nil != ok { 42 | log.Error("Get NewLatestStateRepository failed.") 43 | return nil, fmt.Errorf("get NewLatestStateRepository failed") 44 | } 45 | // make block 46 | block, err := self.assembleBlock(blockStore) 47 | if nil != err { 48 | log.Error("Assemble block failed.") 49 | return nil, fmt.Errorf("assemble block failed") 50 | } 51 | // verify block 52 | err = self.verifyBlock(block, blockStore) 53 | if nil != err { 54 | log.Error("The block verified failed.") 55 | return nil, err 56 | } 57 | block.Header.MixDigest = common.HeaderDigest(block.Header) 58 | // set state root 59 | block.Header.StateRoot = blockStore.IntermediateRoot(false) 60 | // sign 61 | err = self.signBlock(block) 62 | if nil != err { 63 | log.Error("Sign block failed.") 64 | return nil, fmt.Errorf("signature error: %v", err) 65 | } 66 | log.Info("Block %d make success", block.Header.Height) 67 | return block, nil 68 | } 69 | 70 | func (self *Producer) assembleBlock(blockStore *repository.Repository) (*types.Block, error) { 71 | txs := self.txpool.GetTxs() 72 | txHash := make([]types.Hash, 0, len(txs)) 73 | for _, t := range txs { 74 | txHash = append(txHash, common.TxHash(t)) 75 | } 76 | txRoot := tools.ComputeMerkleRoot(txHash) 77 | currentBlock := blockStore.GetCurrentBlock() 78 | block := &types.Block{ 79 | Header: &types.Header{ 80 | ChainID: self.chainId, 81 | TxRoot: txRoot, 82 | CoinBase: self.account.Address, 83 | PrevBlockHash: currentBlock.HeaderHash, 84 | Timestamp: uint64(time.Now().Unix()), 85 | Height: currentBlock.Header.Height + 1, 86 | }, 87 | Transactions: txs, 88 | } 89 | log.Info("Block %d assemble success with %d txs.", block.Header.Height, len(txs)) 90 | return block, nil 91 | } 92 | 93 | func (self *Producer) verifyBlock(block *types.Block, blockStore *repository.Repository) error { 94 | // we support num of works to verify the block 95 | work := worker.NewWorker(blockStore, block, self.enableSignVerify) 96 | // verify the block 97 | err := work.VerifyBlock() 98 | if err != nil { 99 | log.Error("The block %d verified failed with err %v.", block.Header.Height, err) 100 | return err 101 | } 102 | log.Info("The block %d verified success.", block.Header.Height) 103 | return nil 104 | } 105 | 106 | func (self *Producer) signBlock(block *types.Block) error { 107 | sign, err := signature.Sign(&self.account, block.Header.MixDigest[:]) 108 | if nil != err { 109 | log.Error("signature error.") 110 | return err 111 | } 112 | 113 | notSigned := true 114 | for _, value := range block.Header.SigData { 115 | if bytes.Equal(value, sign) { 116 | notSigned = false 117 | log.Warn("Duplicate sign") 118 | } 119 | } 120 | if notSigned { 121 | block.Header.SigData = append(block.Header.SigData, sign) 122 | } 123 | return nil 124 | } 125 | -------------------------------------------------------------------------------- /common/common_test.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "bytes" 5 | "github.com/DSiSc/craft/types" 6 | "github.com/stretchr/testify/assert" 7 | "math/big" 8 | "testing" 9 | "time" 10 | ) 11 | 12 | var to = &types.Address{ 13 | 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, 14 | 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, 15 | } 16 | var from = &types.Address{ 17 | 0x12, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, 18 | 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, 19 | } 20 | 21 | var data = []byte{ 22 | 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, 23 | } 24 | 25 | var emptyTx = &types.Transaction{ 26 | 27 | Data: types.TxData{ 28 | AccountNonce: 0, 29 | Price: new(big.Int).SetUint64(10), 30 | GasLimit: 100, 31 | Recipient: to, 32 | From: from, 33 | Amount: new(big.Int).SetUint64(50), 34 | Payload: data, 35 | }, 36 | } 37 | 38 | func TestTxHash(t *testing.T) { 39 | assert := assert.New(t) 40 | expect := types.Hash{ 41 | 0x4c, 0xb3, 0x5d, 0x9e, 0xfb, 0x35, 0xc3, 0x5d, 0xc0, 0x12, 0x90, 0x23, 0xb2, 0xe3, 0xb0, 0xc5, 0x61, 0x30, 0xf1, 0xd0, 0x58, 0xcb, 0xf5, 0x2e, 0x65, 0x4e, 0x75, 0x47, 0x21, 0x29, 0x33, 0x54, 42 | } 43 | hash := TxHash(emptyTx) 44 | assert.Equal(expect, hash) 45 | hash = TxHash(emptyTx) 46 | assert.Equal(expect, hash) 47 | } 48 | 49 | func TestSumSha256(t *testing.T) { 50 | b := []byte{ 51 | 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, 52 | 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, 53 | } 54 | c := Sum(b) 55 | except := []byte{ 56 | 0x8d, 0xb5, 0xc6, 0x54, 0xc7, 0xa1, 0x24, 0xd4, 0xf8, 0x6a, 0x6c, 0x19, 0xb6, 0x69, 0x51, 0x41, 0xbb, 0xc6, 0xa7, 0xaf, 0x7c, 0x7b, 0x89, 0x8a, 0x85, 0xaf, 0x71, 0xe, 0xf, 0x3, 0xbb, 0xc2, 57 | } 58 | assert.Equal(t, except, c) 59 | } 60 | 61 | func TestCopyBytes(t *testing.T) { 62 | b := []byte{ 63 | 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, 64 | 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, 65 | } 66 | c := CopyBytes(b) 67 | assert.Equal(t, b, c) 68 | } 69 | 70 | var MockHash = types.Hash{ 71 | 0x1d, 0xcf, 0x7, 0xba, 0xfc, 0x42, 0xb0, 0x8d, 0xfd, 0x23, 0x9c, 0x45, 0xa4, 0xb9, 0x38, 0xd, 72 | 0x8d, 0xfe, 0x5d, 0x6f, 0xa7, 0xdb, 0xd5, 0x50, 0xc9, 0x25, 0xb1, 0xb3, 0x4, 0xdc, 0xc5, 0x1c, 73 | } 74 | 75 | var MockBlockHash = types.Hash{ 76 | 0xaf, 0x4e, 0x5b, 0xa3, 0x16, 0x97, 0x74, 0x6a, 0x26, 0x9d, 0x9b, 0x9e, 0xf1, 0x9d, 0xa8, 0xb3, 77 | 0xf9, 0x32, 0x68, 0x16, 0xf4, 0x73, 0xd4, 0xb3, 0x6a, 0xaf, 0x2d, 0x6d, 0xfa, 0x82, 0xd9, 0x89, 78 | } 79 | 80 | var MockHeaderHash = types.Hash{ 81 | 0xcc, 0x88, 0x1c, 0x28, 0x30, 0x38, 0x50, 0x46, 0x2c, 0xcb, 0xae, 0xe5, 0xa4, 0x88, 0x85, 0x75, 82 | 0xdf, 0xae, 0xd7, 0xd3, 0x39, 0x17, 0x9a, 0xfc, 0x9c, 0x4, 0x5e, 0xcd, 0x98, 0x8a, 0x39, 0xdd, 83 | } 84 | 85 | func MockBlock() *types.Block { 86 | return &types.Block{ 87 | Header: &types.Header{ 88 | ChainID: 1, 89 | PrevBlockHash: MockHash, 90 | StateRoot: MockHash, 91 | TxRoot: MockHash, 92 | ReceiptsRoot: MockHash, 93 | Height: 1, 94 | Timestamp: uint64(time.Date(2018, time.August, 28, 0, 0, 0, 0, time.UTC).Unix()), 95 | }, 96 | Transactions: make([]*types.Transaction, 0), 97 | } 98 | } 99 | 100 | func TestBlockHash(t *testing.T) { 101 | assert := assert.New(t) 102 | block := MockBlock() 103 | header := block.Header 104 | 105 | var tmp types.Hash 106 | assert.True(bytes.Equal(tmp[:], header.MixDigest[:])) 107 | assert.True(bytes.Equal(tmp[:], block.HeaderHash[:])) 108 | 109 | digest := HeaderDigest(header) 110 | exceptDigest := types.Hash{0xd8, 0xf9, 0xbb, 0xf4, 0x80, 0xc3, 0x7a, 0xf6, 0x7a, 0x80, 0x8c, 0x3c, 0x60, 0x5f, 0x1a, 0x1c, 0x45, 0x47, 0xf6, 0x4a, 0x33, 0xb6, 0xd2, 0xfd, 0x5c, 0xf1, 0x76, 0x51, 0xc3, 0xa8, 0xa, 0x19} 111 | 112 | assert.Equal(digest, exceptDigest) 113 | block.Header.MixDigest = HeaderDigest(header) 114 | assert.Equal(digest, exceptDigest) 115 | } 116 | 117 | func TestHeaderHash(t *testing.T) { 118 | assert := assert.New(t) 119 | block := MockBlock() 120 | 121 | var tmp types.Hash 122 | assert.True(bytes.Equal(tmp[:], block.HeaderHash[:])) 123 | headerHash := HeaderHash(block) 124 | exceptHeaderHash := types.Hash{0xd8, 0xf9, 0xbb, 0xf4, 0x80, 0xc3, 0x7a, 0xf6, 0x7a, 0x80, 0x8c, 0x3c, 0x60, 0x5f, 0x1a, 0x1c, 0x45, 0x47, 0xf6, 0x4a, 0x33, 0xb6, 0xd2, 0xfd, 0x5c, 0xf1, 0x76, 0x51, 0xc3, 0xa8, 0xa, 0x19} 125 | 126 | assert.Equal(exceptHeaderHash, headerHash) 127 | 128 | block.HeaderHash = HeaderHash(block) 129 | headerHash = HeaderHash(block) 130 | assert.Equal(exceptHeaderHash, headerHash) 131 | } 132 | -------------------------------------------------------------------------------- /producer_test.go: -------------------------------------------------------------------------------- 1 | package producer 2 | 3 | import ( 4 | "fmt" 5 | "github.com/DSiSc/craft/types" 6 | "github.com/DSiSc/monkey" 7 | producerConfig "github.com/DSiSc/producer/config" 8 | "github.com/DSiSc/repository" 9 | "github.com/DSiSc/repository/config" 10 | "github.com/DSiSc/txpool" 11 | "github.com/DSiSc/validator/tools" 12 | account2 "github.com/DSiSc/validator/tools/account" 13 | "github.com/DSiSc/validator/tools/signature" 14 | "github.com/DSiSc/validator/worker" 15 | "github.com/stretchr/testify/assert" 16 | "reflect" 17 | "testing" 18 | ) 19 | 20 | var mockAddress = types.Address{ 21 | 0x33, 0x3c, 0x33, 0x10, 0x82, 0x4b, 0x7c, 0x68, 0x51, 0x33, 22 | 0xf2, 0xbe, 0xdb, 0x2c, 0xa4, 0xb8, 0xb4, 0xdf, 0x63, 0x3d, 23 | } 24 | 25 | type eventCenter struct { 26 | } 27 | 28 | // subscriber subscribe specified eventType with eventFunc 29 | func (*eventCenter) Subscribe(eventType types.EventType, eventFunc types.EventFunc) types.Subscriber { 30 | return nil 31 | } 32 | 33 | // subscriber unsubscribe specified eventType 34 | func (*eventCenter) UnSubscribe(eventType types.EventType, subscriber types.Subscriber) (err error) { 35 | return nil 36 | } 37 | 38 | // notify subscriber of eventType 39 | func (*eventCenter) Notify(eventType types.EventType, value interface{}) (err error) { 40 | return nil 41 | } 42 | 43 | // notify specified eventFunc 44 | func (*eventCenter) NotifySubscriber(eventFunc types.EventFunc, value interface{}) { 45 | 46 | } 47 | 48 | // notify subscriber traversing all events 49 | func (*eventCenter) NotifyAll() (errs []error) { 50 | return nil 51 | } 52 | 53 | // unsubscrible all event 54 | func (*eventCenter) UnSubscribeAll() { 55 | } 56 | 57 | var configFile = producerConfig.ProducerConfig{ 58 | EnableSignatureVerify: false, 59 | } 60 | 61 | func TestNewProducer(t *testing.T) { 62 | assert := assert.New(t) 63 | txpool := txpool.NewTxPool(txpool.DefaultTxPoolConfig, &eventCenter{}) 64 | account := account2.Account{ 65 | Address: tools.HexToAddress("333c3310824b7c685133f2bedb2ca4b8b4df633d"), 66 | } 67 | MockProducer := NewProducer(txpool, account, configFile) 68 | assert.NotNil(MockProducer) 69 | assert.Equal(mockAddress, account.Address) 70 | } 71 | 72 | func TestProducer_assembleBlock(t *testing.T) { 73 | assert := assert.New(t) 74 | txpool := txpool.NewTxPool(txpool.DefaultTxPoolConfig, &eventCenter{}) 75 | account := account2.Account{ 76 | Address: tools.HexToAddress("333c3310824b7c685133f2bedb2ca4b8b4df633d"), 77 | } 78 | MockProducer := NewProducer(txpool, account, configFile) 79 | conf := config.RepositoryConfig{ 80 | PluginName: repository.PLUGIN_MEMDB, 81 | StateDataPath: "./state", 82 | BlockDataPath: "./state", 83 | } 84 | err := repository.InitRepository(conf, &eventCenter{}) 85 | assert.Nil(err) 86 | blockChain, err := repository.NewLatestStateRepository() 87 | assert.NotNil(blockChain) 88 | assert.Nil(err) 89 | genesisBlock := &types.Block{ 90 | Header: &types.Header{ 91 | Height: 1, 92 | }, 93 | HeaderHash: types.Hash{0xbf, 0x35, 0x40, 0x34, 0x12, 0x0d, 0xca, 0x57, 0x0a, 0x4d, 0xc6, 0x65, 0xcb, 0x71, 0x72, 0xa7, 0x0e, 0x71, 0xac, 0x21, 0x3e, 0xc1, 0x34, 0xe0, 0x61, 0x8a, 0x1f, 0x50, 0xc3, 0xe8, 0x27, 0x54}, 94 | } 95 | blockChain.WriteBlock(genesisBlock) 96 | block, err1 := MockProducer.assembleBlock(blockChain) 97 | assert.Nil(err1) 98 | assert.NotNil(block) 99 | assert.Equal(uint64(2), block.Header.Height) 100 | } 101 | 102 | func TestProducer_MakeBlock(t *testing.T) { 103 | assert := assert.New(t) 104 | pool := txpool.NewTxPool(txpool.DefaultTxPoolConfig, &eventCenter{}) 105 | account := account2.Account{ 106 | Address: tools.HexToAddress("333c3310824b7c685133f2bedb2ca4b8b4df633d"), 107 | } 108 | MockProducer := NewProducer(pool, account, configFile) 109 | 110 | monkey.Patch(repository.NewLatestStateRepository, func() (*repository.Repository, error) { 111 | return nil, fmt.Errorf("get block chain failed") 112 | }) 113 | block, err := MockProducer.MakeBlock() 114 | assert.Nil(block) 115 | assert.Equal(err, fmt.Errorf("get NewLatestStateRepository failed")) 116 | 117 | monkey.Patch(repository.NewLatestStateRepository, func() (*repository.Repository, error) { 118 | return nil, nil 119 | }) 120 | var b *repository.Repository 121 | monkey.PatchInstanceMethod(reflect.TypeOf(b), "GetCurrentBlock", func(*repository.Repository) *types.Block { 122 | return &types.Block{ 123 | Header: &types.Header{ 124 | Height: 0, 125 | }, 126 | HeaderHash: types.Hash{ 127 | 0xbd, 0x79, 0x1d, 0x4a, 0xf9, 0x64, 0x8f, 0xc3, 0x7f, 0x94, 0xeb, 0x36, 0x53, 0x19, 0xf6, 0xd0, 128 | 0xa9, 0x78, 0x9f, 0x9c, 0x22, 0x47, 0x2c, 0xa7, 0xa6, 0x12, 0xa9, 0xca, 0x4, 0x13, 0xc1, 0x4, 129 | }, 130 | } 131 | }) 132 | monkey.PatchInstanceMethod(reflect.TypeOf(b), "GetCurrentBlockHeight", func(*repository.Repository) uint64 { 133 | return uint64(0) 134 | }) 135 | monkey.PatchInstanceMethod(reflect.TypeOf(b), "IntermediateRoot", func(*repository.Repository, bool) types.Hash { 136 | return types.Hash{ 137 | 0xbd, 0x79, 0x1d, 0x4a, 0xf9, 0x64, 0x8f, 0xc3, 0x7f, 0x94, 0xeb, 0x36, 0x53, 0x19, 0xf6, 0xd0, 138 | 0xa9, 0x78, 0x9f, 0x9c, 0x22, 0x47, 0x2c, 0xa7, 0xa6, 0x12, 0xa9, 0xca, 0x4, 0x13, 0xc1, 0x4, 139 | } 140 | }) 141 | 142 | var c *worker.Worker 143 | monkey.PatchInstanceMethod(reflect.TypeOf(c), "VerifyBlock", func(*worker.Worker) error { 144 | return fmt.Errorf("verify failed") 145 | }) 146 | 147 | block, err = MockProducer.MakeBlock() 148 | assert.Nil(block) 149 | assert.Equal(err, fmt.Errorf("verify failed")) 150 | 151 | monkey.PatchInstanceMethod(reflect.TypeOf(c), "VerifyBlock", func(*worker.Worker) error { 152 | return nil 153 | }) 154 | 155 | monkey.Patch(signature.Sign, func(signer signature.Signer, data []byte) ([]byte, error) { 156 | except := []byte{0x1, 0x2, 0x4} 157 | return except, fmt.Errorf("mock sign error") 158 | }) 159 | block, err = MockProducer.MakeBlock() 160 | assert.Nil(block) 161 | assert.Equal(fmt.Errorf("signature error: mock sign error"), err) 162 | 163 | monkey.Patch(signature.Sign, func(signer signature.Signer, data []byte) ([]byte, error) { 164 | except := []byte{0x1, 0x2, 0x4} 165 | return except, nil 166 | }) 167 | block, err = MockProducer.MakeBlock() 168 | assert.NotNil(block) 169 | assert.Nil(err) 170 | assert.Equal(uint64(1), block.Header.Height) 171 | } 172 | 173 | func Test_verifyBlock(t *testing.T) { 174 | assert := assert.New(t) 175 | MockProducer := NewProducer(nil, account2.Account{}, configFile) 176 | var d *worker.Worker 177 | block := &types.Block{ 178 | Header: &types.Header{ 179 | Height: 0, 180 | }, 181 | } 182 | monkey.PatchInstanceMethod(reflect.TypeOf(d), "VerifyBlock", func(*worker.Worker) error { 183 | return fmt.Errorf("mock verify failed") 184 | }) 185 | err := MockProducer.verifyBlock(block, nil) 186 | assert.NotNil(err) 187 | 188 | monkey.PatchInstanceMethod(reflect.TypeOf(d), "VerifyBlock", func(*worker.Worker) error { 189 | return nil 190 | }) 191 | err = MockProducer.verifyBlock(block, nil) 192 | assert.Nil(err) 193 | monkey.UnpatchInstanceMethod(reflect.TypeOf(d), "VerifyBlock") 194 | } 195 | 196 | func Test_signBlock(t *testing.T) { 197 | assert := assert.New(t) 198 | MockProducer := NewProducer(nil, account2.Account{}, configFile) 199 | block := &types.Block{ 200 | Header: &types.Header{ 201 | SigData: [][]byte{{0x1, 0x2, 0x3}}, 202 | }, 203 | } 204 | // test sign error 205 | monkey.Patch(signature.Sign, func(signer signature.Signer, data []byte) ([]byte, error) { 206 | except := []byte{0x1, 0x2, 0x4} 207 | return except, fmt.Errorf("mock sign error") 208 | }) 209 | err := MockProducer.signBlock(block) 210 | assert.Equal(err, fmt.Errorf("mock sign error")) 211 | 212 | // test new sign 213 | monkey.Patch(signature.Sign, func(signer signature.Signer, data []byte) ([]byte, error) { 214 | except := []byte{0x1, 0x2, 0x4} 215 | return except, nil 216 | }) 217 | err = MockProducer.signBlock(block) 218 | assert.Nil(err) 219 | assert.Equal(2, len(block.Header.SigData)) 220 | // test duplicate sign 221 | monkey.Patch(signature.Sign, func(signer signature.Signer, data []byte) ([]byte, error) { 222 | except := []byte{0x1, 0x2, 0x3} 223 | return except, nil 224 | }) 225 | err = MockProducer.signBlock(block) 226 | assert.Nil(err) 227 | assert.Equal(2, len(block.Header.SigData)) 228 | monkey.Unpatch(signature.Sign) 229 | } 230 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | --------------------------------------------------------------------------------