├── .circleci └── config.yml ├── .codecov.yml ├── .dockerignore ├── .gitattributes ├── .gitignore ├── AUTHORS.md ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── common ├── bloom.go ├── common.go └── common_test.go ├── contrib ├── LICENSE-APPLY └── git │ ├── .gitconfig.tmp │ └── .gitmessage.tmp ├── dependencies.txt ├── docs └── .gitignore ├── scripts ├── changelog.sh ├── check_license.sh ├── check_spelling.sh ├── ensure_deps.sh ├── install_behave.sh └── unit_test_cov.sh ├── tools ├── account │ ├── account.go │ └── account_test.go ├── merkle_tree │ ├── merkle_tree.go │ └── merkle_tree_test.go ├── signature │ ├── keypair │ │ └── key.go │ ├── signature.go │ ├── signature_test.go │ ├── signer.go │ ├── transaction_signing.go │ └── transaction_signing_test.go ├── tools.go └── tools_test.go ├── validator.go ├── validator_test.go ├── version └── version.go └── worker ├── common ├── errors.go ├── gaspool.go ├── gaspool_test.go ├── log.go ├── receipt.go └── receipt_test.go ├── state.go ├── state_test.go ├── worker.go └── worker_test.go /.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/validator 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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | 3 | * text=auto 4 | 5 | *.sh text eol=lf 6 | *.go text eol=lf 7 | *.yaml text eol=lf 8 | *.yml text eol=lf 9 | *.md text eol=lf 10 | *.json text eol=lf 11 | *.proto text eol=lf 12 | *.py text eol=lf 13 | *.js text eol=lf 14 | *.txt text eol=lf 15 | *.sol linguist-language=Solidity 16 | LICENSE text eol=lf 17 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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? -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DSiSc/validator/634f624b2b2a5c914aaa5ad9d497ff30b680a330/CHANGELOG.md -------------------------------------------------------------------------------- /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/validator/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 | validator could always use more documentation, whether as part of the 32 | official validator 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/validator/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 `validator` for local development. 49 | 50 | 1. Fork the `validator` repo on GitHub. 51 | 2. Clone your fork locally:: 52 | 53 | $ git clone git@github.com:your_name_here/validator.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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/validator:' 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 validator ${VERSION}" 58 | @echo "GOPATH=${GOPATH}" 59 | go build -v -ldflags "-X github.com/DSiSc/validator/version.GitCommit=${GIT_COMMIT}${GIT_DIRTY} -X github.com/DSiSc/validator/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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # validator 2 | 3 | A high-speed validator verify transaction and block. 4 | 5 | [![Build Status](https://circleci.com/gh/DSiSc/validator/tree/master.svg?style=shield)](https://circleci.com/gh/DSiSc/validator/tree/master) 6 | [![codecov](https://codecov.io/gh/DSiSc/validator/branch/master/graph/badge.svg)](https://codecov.io/gh/DSiSc/validator) 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 | -------------------------------------------------------------------------------- /common/bloom.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "fmt" 5 | "github.com/DSiSc/craft/types" 6 | "github.com/DSiSc/crypto-suite/crypto" 7 | "math/big" 8 | ) 9 | 10 | // BytesToBloom converts a byte slice to a bloom filter. 11 | // It panics if b is not of suitable size. 12 | func BytesToBloom(b []byte) types.Bloom { 13 | var bloom types.Bloom 14 | SetBytes(b, &bloom) 15 | return bloom 16 | } 17 | 18 | // SetBytes sets the content of b to the given bytes. 19 | // It panics if d is not of suitable size. 20 | func SetBytes(d []byte, b *types.Bloom) { 21 | if len(b) < len(d) { 22 | panic(fmt.Sprintf("bloom bytes too big %d %d", len(b), len(d))) 23 | } 24 | copy(b[types.BloomByteLength-len(d):], d) 25 | } 26 | 27 | func bloom9(b []byte) *big.Int { 28 | b = crypto.Keccak256(b) 29 | 30 | r := new(big.Int) 31 | 32 | for i := 0; i < 6; i += 2 { 33 | t := big.NewInt(1) 34 | b := (uint(b[i+1]) + (uint(b[i]) << 8)) & 2047 35 | r.Or(r, t.Lsh(t, b)) 36 | } 37 | 38 | return r 39 | } 40 | 41 | func LogsBloom(logs []*types.Log) *big.Int { 42 | bin := new(big.Int) 43 | for _, log := range logs { 44 | bin.Or(bin, bloom9(log.Address[:])) 45 | for _, b := range log.Topics { 46 | bin.Or(bin, bloom9(b[:])) 47 | } 48 | } 49 | 50 | return bin 51 | } 52 | 53 | func CreateBloom(receipts types.Receipts) types.Bloom { 54 | bin := new(big.Int) 55 | for _, receipt := range receipts { 56 | bin.Or(bin, LogsBloom(receipt.Logs)) 57 | } 58 | 59 | return BytesToBloom(bin.Bytes()) 60 | } 61 | -------------------------------------------------------------------------------- /common/common.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "encoding/json" 5 | gconf "github.com/DSiSc/craft/config" 6 | "github.com/DSiSc/craft/rlp" 7 | "github.com/DSiSc/craft/types" 8 | "github.com/DSiSc/crypto-suite/crypto/sha3" 9 | "hash" 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 HashAlg() hash.Hash { 27 | var alg string 28 | if value, ok := gconf.GlobalConfig.Load(gconf.HashAlgName); ok { 29 | alg = value.(string) 30 | } else { 31 | alg = "SHA256" 32 | } 33 | return sha3.NewHashByAlgName(alg) 34 | } 35 | 36 | func rlpHash(x interface{}) (h types.Hash) { 37 | hw := HashAlg() 38 | rlp.Encode(hw, x) 39 | hw.Sum(h[:0]) 40 | return h 41 | } 42 | 43 | // Hash hashes the RLP encoding of tx. 44 | // It uniquely identifies the transaction. 45 | func TxHash(tx *types.Transaction) types.Hash { 46 | if hash := tx.Hash.Load(); hash != nil { 47 | return hash.(types.Hash) 48 | } 49 | v := rlpHash(tx) 50 | tx.Hash.Store(v) 51 | return v 52 | } 53 | 54 | func HeaderHash(block *types.Block) types.Hash { 55 | //var defaultHash types.Hash 56 | if !(block.HeaderHash == types.Hash{}) { 57 | var hash types.Hash 58 | copy(hash[:], block.HeaderHash[:]) 59 | return hash 60 | } 61 | return rlpHash(block.Header) 62 | } 63 | 64 | type RefAddress struct { 65 | Addr types.Address 66 | } 67 | 68 | func NewRefAddress(addr types.Address) *RefAddress { 69 | return &RefAddress{Addr: addr} 70 | } 71 | 72 | func (self *RefAddress) Address() types.Address { 73 | return self.Addr 74 | } 75 | 76 | func HashToByte(hash types.Hash) []byte { 77 | var value = make([]byte, len(hash)) 78 | copy(value, hash[:]) 79 | return value 80 | } 81 | 82 | func ByteToHash(data []byte) (hash types.Hash) { 83 | copy(hash[:], data[:]) 84 | return 85 | } 86 | 87 | func HeaderDigest(header *types.Header) (hash types.Hash) { 88 | if !(header.MixDigest == types.Hash{}) { 89 | copy(hash[:], header.MixDigest[:]) 90 | return 91 | } 92 | newHeader := digestHeader(header) 93 | jsonByte, _ := json.Marshal(newHeader) 94 | sumByte := Sum(jsonByte) 95 | copy(hash[:], sumByte) 96 | return 97 | } 98 | 99 | func digestHeader(header *types.Header) *types.Header { 100 | return &types.Header{ 101 | ChainID: header.ChainID, 102 | PrevBlockHash: header.PrevBlockHash, 103 | StateRoot: header.StateRoot, 104 | TxRoot: header.TxRoot, 105 | ReceiptsRoot: header.ReceiptsRoot, 106 | Height: header.Height, 107 | Timestamp: header.Timestamp, 108 | CoinBase: header.CoinBase, 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /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 | func MockTransaction() *types.Transaction { 13 | to := &types.Address{ 14 | 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, 15 | 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, 16 | } 17 | from := &types.Address{ 18 | 0x12, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, 19 | 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, 20 | } 21 | 22 | data := []byte{ 23 | 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, 24 | } 25 | 26 | tx := &types.Transaction{ 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 | return tx 38 | } 39 | 40 | var MockHash = types.Hash{0xee, 0x60, 0x3b, 0x70, 0xb7, 0xd0, 0xf2, 0xd2, 0xc2, 0x2b, 0xcf, 0xf9, 0xa3, 0xe1, 0x63, 0xe5, 0x5b, 0xfd, 0xa, 0x24, 0xb3, 0x3d, 0x6b, 0xb2, 0xa, 0x70, 0x7a, 0x3e, 0x23, 0xb6, 0x75, 0x6} 41 | 42 | var MockBlockHash = types.Hash{ 43 | 0xaf, 0x4e, 0x5b, 0xa3, 0x16, 0x97, 0x74, 0x6a, 0x26, 0x9d, 0x9b, 0x9e, 0xf1, 0x9d, 0xa8, 0xb3, 44 | 0xf9, 0x32, 0x68, 0x16, 0xf4, 0x73, 0xd4, 0xb3, 0x6a, 0xaf, 0x2d, 0x6d, 0xfa, 0x82, 0xd9, 0x89, 45 | } 46 | 47 | var MockHeaderHash = types.Hash{ 48 | 0xcc, 0x88, 0x1c, 0x28, 0x30, 0x38, 0x50, 0x46, 0x2c, 0xcb, 0xae, 0xe5, 0xa4, 0x88, 0x85, 0x75, 49 | 0xdf, 0xae, 0xd7, 0xd3, 0x39, 0x17, 0x9a, 0xfc, 0x9c, 0x4, 0x5e, 0xcd, 0x98, 0x8a, 0x39, 0xdd, 50 | } 51 | 52 | func TestTxHash(t *testing.T) { 53 | hash := TxHash(MockTransaction()) 54 | assert.Equal(t, MockHash, hash) 55 | hash = TxHash(MockTransaction()) 56 | assert.Equal(t, MockHash, hash) 57 | } 58 | 59 | func MockBlock() *types.Block { 60 | return &types.Block{ 61 | Header: &types.Header{ 62 | ChainID: 1, 63 | PrevBlockHash: MockHash, 64 | StateRoot: MockHash, 65 | TxRoot: MockHash, 66 | ReceiptsRoot: MockHash, 67 | Height: 1, 68 | Timestamp: uint64(time.Date(2018, time.August, 28, 0, 0, 0, 0, time.UTC).Unix()), 69 | }, 70 | Transactions: make([]*types.Transaction, 0), 71 | } 72 | } 73 | 74 | func TestBlockHash(t *testing.T) { 75 | assert := assert.New(t) 76 | block := MockBlock() 77 | var tmp types.Hash 78 | 79 | header := block.Header 80 | assert.True(bytes.Equal(tmp[:], header.MixDigest[:])) 81 | assert.True(bytes.Equal(tmp[:], block.HeaderHash[:])) 82 | 83 | digest := HeaderDigest(header) 84 | exceptDigest := types.Hash{0x7c, 0xa6, 0xb8, 0xc0, 0x86, 0x20, 0xf0, 0x18, 0x3e, 0x70, 0x70, 0xde, 0xf7, 0xf5, 0xc, 0xab, 0x20, 0x25, 0xeb, 0x4d, 0xcb, 0x3c, 0x57, 0x90, 0xe, 0xdd, 0x2, 0xe6, 0x20, 0x22, 0x74, 0xa3} 85 | 86 | assert.Equal(exceptDigest, digest) 87 | 88 | assert.True(bytes.Equal(tmp[:], block.HeaderHash[:])) 89 | headerHash := HeaderHash(block) 90 | exceptHeaderHash := types.Hash{0x1c, 0xe8, 0x7c, 0xb7, 0xe8, 0x5c, 0x32, 0x4d, 0x25, 0x33, 0x9a, 0xcf, 0x20, 0xec, 0xc6, 0x79, 0x4d, 0x56, 0x1c, 0x11, 0x57, 0x15, 0x62, 0xd8, 0x74, 0x79, 0xb9, 0xc1, 0x5d, 0xd7, 0xf7, 0x30} 91 | 92 | assert.Equal(exceptHeaderHash, headerHash) 93 | block.HeaderHash = HeaderHash(block) 94 | headerHash = HeaderHash(block) 95 | assert.Equal(exceptHeaderHash, headerHash) 96 | } 97 | 98 | func TestNewRefAddress(t *testing.T) { 99 | mock := types.Address{ 100 | 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, 101 | 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, 102 | } 103 | refAddr := NewRefAddress(mock) 104 | assert.NotNil(t, refAddr) 105 | addr := refAddr.Address() 106 | assert.Equal(t, mock, addr) 107 | } 108 | 109 | func TestHashToByte(t *testing.T) { 110 | bytes := HashToByte(MockBlockHash) 111 | var exceptByte = []byte{ 112 | 0xaf, 0x4e, 0x5b, 0xa3, 0x16, 0x97, 0x74, 0x6a, 0x26, 0x9d, 0x9b, 0x9e, 0xf1, 0x9d, 0xa8, 0xb3, 113 | 0xf9, 0x32, 0x68, 0x16, 0xf4, 0x73, 0xd4, 0xb3, 0x6a, 0xaf, 0x2d, 0x6d, 0xfa, 0x82, 0xd9, 0x89, 114 | } 115 | assert.Equal(t, exceptByte, bytes) 116 | } 117 | 118 | func TestByteToHash(t *testing.T) { 119 | var byteSrc = []byte{ 120 | 0xaf, 0x4e, 0x5b, 0xa3, 0x16, 0x97, 0x74, 0x6a, 0x26, 0x9d, 0x9b, 0x9e, 0xf1, 0x9d, 0xa8, 0xb3, 121 | 0xf9, 0x32, 0x68, 0x16, 0xf4, 0x73, 0xd4, 0xb3, 0x6a, 0xaf, 0x2d, 0x6d, 0xfa, 0x82, 0xd9, 0x89, 122 | } 123 | hash := ByteToHash(byteSrc) 124 | assert.Equal(t, MockBlockHash, hash) 125 | } 126 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/statedb-NG:master 6 | github.com/DSiSc/repository:master 7 | github.com/DSiSc/blockstore:master 8 | github.com/DSiSc/craft:master 9 | github.com/DSiSc/evm-NG:master 10 | github.com/DSiSc/txpool:master 11 | github.com/DSiSc/wallet:master 12 | github.com/DSiSc/monkey:master 13 | github.com/DSiSc/crypto-suite:master 14 | github.com/DSiSc/wasm:master 15 | 16 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | -------------------------------------------------------------------------------- /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\/validator\/commit\/\1)/" >> ${CHANGELOG_TEMP} 16 | echo "" >> ${CHANGELOG_TEMP} 17 | cat ${SCRIPT_DIR}/../CHANGELOG.md >> ${CHANGELOG_TEMP} 18 | mv -f ${CHANGELOG_TEMP} CHANGELOG.md 19 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /tools/account/account.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "github.com/DSiSc/craft/types" 5 | "github.com/DSiSc/validator/tools/signature/keypair" 6 | ) 7 | 8 | type Account struct { 9 | PrivateKey keypair.PrivateKey 10 | PublicKey keypair.PublicKey 11 | Address types.Address 12 | SigScheme keypair.SignatureScheme 13 | Extension AccountExtension 14 | } 15 | 16 | func (*Account) PrivKey() keypair.PrivateKey { 17 | return nil 18 | } 19 | 20 | //get signer's public key 21 | func (*Account) PubKey() keypair.PublicKey { 22 | return nil 23 | } 24 | 25 | func (*Account) Scheme() keypair.SignatureScheme { 26 | //var temp keypair.SignatureScheme 27 | var byt byte = 'a' 28 | return keypair.SignatureScheme(byt) 29 | } 30 | 31 | type AccountExtension struct { 32 | Id uint64 33 | Url string 34 | } 35 | -------------------------------------------------------------------------------- /tools/account/account_test.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "github.com/DSiSc/craft/types" 5 | "github.com/DSiSc/validator/tools" 6 | "github.com/DSiSc/validator/tools/signature/keypair" 7 | "github.com/stretchr/testify/assert" 8 | "testing" 9 | ) 10 | 11 | func Test_Account(t *testing.T) { 12 | assert := assert.New(t) 13 | 14 | var address = types.Address{ 15 | 0x33, 0x3c, 0x33, 0x10, 0x82, 0x4b, 0x7c, 0x68, 0x51, 0x33, 16 | 0xf2, 0xbe, 0xdb, 0x2c, 0xa4, 0xb8, 0xb4, 0xdf, 0x63, 0x3d, 17 | } 18 | 19 | var account = &Account{ 20 | PrivateKey: nil, 21 | PublicKey: nil, 22 | Address: tools.HexToAddress("333c3310824b7c685133f2bedb2ca4b8b4df633d"), 23 | SigScheme: keypair.SignatureScheme('a'), 24 | } 25 | 26 | priKey := account.PrivKey() 27 | assert.Nil(priKey) 28 | 29 | pubKey := account.PubKey() 30 | assert.Nil(pubKey) 31 | 32 | scheme := account.Scheme() 33 | assert.Equal(keypair.SignatureScheme('a'), scheme) 34 | 35 | addr := account.Address 36 | assert.Equal(address, addr) 37 | 38 | exceptStr := "3<3\x10\x82K|hQ3\xf2\xbe\xdb,\xa4\xb8\xb4\xdfc=" 39 | str := string(address[:]) 40 | assert.Equal(exceptStr, str) 41 | 42 | data := []byte(str) 43 | assert.Equal(address, tools.BytesToAddress(data)) 44 | } 45 | -------------------------------------------------------------------------------- /tools/merkle_tree/merkle_tree.go: -------------------------------------------------------------------------------- 1 | package merkle_tree 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("hashes is empty") 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 | -------------------------------------------------------------------------------- /tools/merkle_tree/merkle_tree_test.go: -------------------------------------------------------------------------------- 1 | package merkle_tree 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 | -------------------------------------------------------------------------------- /tools/signature/keypair/key.go: -------------------------------------------------------------------------------- 1 | package keypair 2 | 3 | import ( 4 | "crypto" 5 | ) 6 | 7 | type SignatureScheme byte 8 | 9 | type PublicKey crypto.PublicKey 10 | 11 | type PrivateKey interface { 12 | crypto.PrivateKey 13 | Public() crypto.PublicKey 14 | } 15 | -------------------------------------------------------------------------------- /tools/signature/signature.go: -------------------------------------------------------------------------------- 1 | package signature 2 | 3 | import ( 4 | "fmt" 5 | "github.com/DSiSc/craft/types" 6 | "github.com/DSiSc/validator/common" 7 | "github.com/DSiSc/validator/tools" 8 | "github.com/DSiSc/validator/tools/account" 9 | "github.com/DSiSc/validator/tools/signature/keypair" 10 | ) 11 | 12 | type Signature struct { 13 | Scheme keypair.SignatureScheme 14 | Value interface{} 15 | } 16 | 17 | // Sing the data by singer 18 | func Sign(signer Signer, data []byte) ([]byte, error) { 19 | // TODO: adding key 20 | signatures := make([]byte, len(data)) 21 | address := signer.(*account.Account).Address 22 | for i := 0; i < len(address); i++ { 23 | signatures[i] = address[i] ^ data[i] 24 | } 25 | return signatures, nil 26 | } 27 | 28 | func verifySpecifiedAddress(pubKey []byte, signData []byte, validatorAddress types.Address) bool { 29 | var decode = make([]byte, len(signData)) 30 | for i := 0; i < len(validatorAddress); i++ { 31 | decode[i] = pubKey[i] ^ signData[i] 32 | if validatorAddress[i] != decode[i] { 33 | return false 34 | } 35 | } 36 | return true 37 | } 38 | 39 | // Verify check the signature of data using pubKey 40 | func Verify(pubKey keypair.PublicKey, signature []byte) (types.Address, error) { 41 | var validators = []types.Address{ 42 | tools.HexToAddress("333c3310824b7c685133f2bedb2ca4b8b4df633d"), 43 | tools.HexToAddress("343c3310824b7c685133f2bedb2ca4b8b4df633d"), 44 | tools.HexToAddress("353c3310824b7c685133f2bedb2ca4b8b4df633d"), 45 | tools.HexToAddress("363c3310824b7c685133f2bedb2ca4b8b4df633d"), 46 | } 47 | pkey := common.HashToByte(pubKey.(types.Hash)) 48 | for i := 0; i < len(validators); i++ { 49 | if verifySpecifiedAddress(pkey, signature, validators[i]) { 50 | return validators[i], nil 51 | } 52 | } 53 | return *new(types.Address), fmt.Errorf("invalid signData") 54 | } 55 | 56 | // VerifyMultiSignature check whether more than m sigs are signed by the keys 57 | func VerifyMultiSignature(data []byte, keys []keypair.PublicKey, m int, sigs [][]byte) error { 58 | return nil 59 | } 60 | -------------------------------------------------------------------------------- /tools/signature/signature_test.go: -------------------------------------------------------------------------------- 1 | package signature 2 | 3 | import ( 4 | "fmt" 5 | "github.com/DSiSc/craft/log" 6 | "github.com/DSiSc/craft/types" 7 | "github.com/DSiSc/validator/common" 8 | "github.com/DSiSc/validator/tools" 9 | "github.com/DSiSc/validator/tools/account" 10 | "github.com/stretchr/testify/assert" 11 | "testing" 12 | ) 13 | 14 | var MockAccount = &account.Account{ 15 | Address: types.Address{0x33, 0x3c, 0x33, 0x10, 0x82, 0x4b, 0x7c, 0x68, 0x51, 0x33, 0xf2, 0xbe, 0xdb, 0x2c, 0xa4, 0xb8, 0xb4, 0xdf, 0x63, 0x3d}, 16 | } 17 | 18 | var MockAccount1 = &account.Account{ 19 | Address: types.Address{0x34, 0x3c, 0x33, 0x10, 0x82, 0x4b, 0x7c, 0x68, 0x51, 0x33, 0xf2, 0xbe, 0xdb, 0x2c, 0xa4, 0xb8, 0xb4, 0xdf, 0x63, 0x3d}, 20 | } 21 | 22 | var MockSignData = []byte{ 23 | 0x8a, 0x73, 0x60, 0x64, 0x7e, 0xae, 0x91, 0xd4, 0xdf, 0x19, 24 | 0x74, 0x29, 0x1a, 0x7f, 0x95, 0xdf, 0xca, 0xb1, 0xdc, 0x36, 25 | } 26 | 27 | var Digest = tools.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b") 28 | 29 | func Test_Sign(t *testing.T) { 30 | assert := assert.New(t) 31 | exc, err := Sign(MockAccount, Digest[:]) 32 | assert.Nil(err) 33 | assert.Equal(MockSignData, exc) 34 | } 35 | 36 | func TestVerifyMultiSignature(t *testing.T) { 37 | assert := assert.New(t) 38 | signature, err := Sign(MockAccount, Digest[:]) 39 | assert.Nil(err) 40 | signer, err := Verify(common.ByteToHash(Digest[:]), signature) 41 | assert.Nil(err) 42 | assert.Equal(MockAccount.Address, signer) 43 | } 44 | 45 | func Test_Verify(t *testing.T) { 46 | assert := assert.New(t) 47 | signer, err := Verify(common.ByteToHash(MockSignData), Digest[:]) 48 | assert.Nil(err) 49 | assert.Equal(signer, tools.HexToAddress("333c3310824b7c685133f2bedb2ca4b8b4df633d")) 50 | NoSignDigest := tools.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf00") 51 | _, err = Verify(common.ByteToHash(MockSignData), NoSignDigest[:]) 52 | expect := fmt.Errorf("invalid signData") 53 | assert.Equal(expect, err) 54 | 55 | digest := tools.FromHex("f3b6a8c32257a09ce1b510234fed018212e2910fbad95ba42b1e9e333932bf3f") 56 | var MockAccount1 = &account.Account{ 57 | Address: types.Address{0x33, 0x3c, 0x33, 0x10, 0x82, 0x4b, 0x7c, 0x68, 0x51, 0x33, 0xf2, 0xbe, 0xdb, 0x2c, 0xa4, 0xb8, 0xb4, 0xdf, 0x63, 0x3d}, 58 | } 59 | signature, err := Sign(MockAccount1, digest) 60 | var b types.Hash 61 | setBytes(digest, &b) 62 | address, err := Verify(b, signature) 63 | assert.Nil(err) 64 | assert.NotNil(address) 65 | assert.Equal(MockAccount1.Address, address) 66 | } 67 | 68 | func Test_VerifyMultiSignature(t *testing.T) { 69 | assert := assert.New(t) 70 | err := VerifyMultiSignature(nil, nil, 0, nil) 71 | assert.Nil(err) 72 | } 73 | 74 | func signDataVerify(account account.Account, sign []byte, digest types.Hash) bool { 75 | address, err := Verify(digest, sign) 76 | if nil != err { 77 | log.Error("verify sign %v failed with err %s", sign, err) 78 | } 79 | return account.Address == address 80 | } 81 | 82 | func setBytes(b []byte, a *types.Hash) { 83 | copy(a[:], b[:types.HashLength]) 84 | } 85 | -------------------------------------------------------------------------------- /tools/signature/signer.go: -------------------------------------------------------------------------------- 1 | package signature 2 | 3 | import ( 4 | "github.com/DSiSc/validator/tools/signature/keypair" 5 | ) 6 | 7 | // Signer is the abstract interface of user's information(Keys) for signing data. 8 | type Signer interface { 9 | //get signer's private key 10 | PrivKey() keypair.PrivateKey 11 | 12 | //get signer's public key 13 | PubKey() keypair.PublicKey 14 | 15 | Scheme() keypair.SignatureScheme 16 | } 17 | -------------------------------------------------------------------------------- /tools/signature/transaction_signing.go: -------------------------------------------------------------------------------- 1 | package signature 2 | 3 | import ( 4 | "github.com/DSiSc/craft/types" 5 | "math/big" 6 | ) 7 | 8 | type TxSigner interface { 9 | // Sender returns the sender address of the transaction. 10 | Sender(tx *types.Transaction) (types.Address, error) 11 | 12 | // SignatureValues returns the raw R, S, V values corresponding to the 13 | // given signature. 14 | SignatureValues(tx *types.Transaction, sig []byte) (r, s, v *big.Int, err error) 15 | 16 | // Hash returns the hash to be signed. 17 | Hash(tx *types.Transaction) types.Hash 18 | 19 | // Equal returns true if the given signer is the same as the receiver. 20 | Equal(TxSigner) bool 21 | } 22 | 23 | type sigCache struct { 24 | signer TxSigner 25 | from types.Address 26 | } 27 | 28 | func Sender(signer TxSigner, tx *types.Transaction) (types.Address, error) { 29 | if sc := tx.From.Load(); sc != nil { 30 | sigCache := sc.(sigCache) 31 | if sigCache.signer.Equal(signer) { 32 | return sigCache.from, nil 33 | } 34 | } 35 | 36 | addr, err := signer.Sender(tx) 37 | if err != nil { 38 | return types.Address{}, err 39 | } 40 | tx.From.Store(sigCache{signer: signer, from: addr}) 41 | return addr, nil 42 | } 43 | -------------------------------------------------------------------------------- /tools/signature/transaction_signing_test.go: -------------------------------------------------------------------------------- 1 | package signature 2 | 3 | import ( 4 | "github.com/DSiSc/craft/types" 5 | "github.com/DSiSc/validator/common" 6 | "github.com/stretchr/testify/assert" 7 | "math/big" 8 | "testing" 9 | ) 10 | 11 | type MockSigner struct { 12 | r big.Int 13 | s big.Int 14 | v big.Int 15 | equal bool 16 | } 17 | 18 | func NewMockSigner(r big.Int, s big.Int, v big.Int, equal bool) *MockSigner { 19 | return &MockSigner{ 20 | r: r, 21 | s: s, 22 | v: v, 23 | equal: equal, 24 | } 25 | } 26 | 27 | var from = types.Address{ 28 | 0x12, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, 29 | 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, 30 | } 31 | 32 | func (*MockSigner) Sender(tx *types.Transaction) (types.Address, error) { 33 | return from, nil 34 | } 35 | 36 | func (self *MockSigner) SignatureValues(tx *types.Transaction, sig []byte) (r, s, v *big.Int, err error) { 37 | r, s, v = &self.r, &self.s, &self.v 38 | err = nil 39 | return 40 | } 41 | 42 | func (*MockSigner) Hash(tx *types.Transaction) types.Hash { 43 | return common.TxHash(tx) 44 | } 45 | 46 | func (self *MockSigner) Equal(TxSigner) bool { 47 | return self.equal 48 | } 49 | 50 | func TestSender(t *testing.T) { 51 | to := &types.Address{ 52 | 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, 53 | 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, 54 | } 55 | data := []byte{ 56 | 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, 57 | } 58 | tx := &types.Transaction{ 59 | Data: types.TxData{ 60 | AccountNonce: 0, 61 | Price: new(big.Int).SetUint64(10), 62 | GasLimit: 100, 63 | Recipient: to, 64 | From: nil, 65 | Amount: new(big.Int).SetUint64(50), 66 | Payload: data, 67 | }, 68 | } 69 | signer := NewMockSigner(*new(big.Int).SetUint64(1), *new(big.Int).SetUint64(2), *new(big.Int).SetUint64(3), true) 70 | addr, err := Sender(signer, tx) 71 | assert.Nil(t, err) 72 | assert.Equal(t, addr, from) 73 | 74 | tx.Data.From = &from 75 | signer = NewMockSigner(*new(big.Int).SetUint64(1), *new(big.Int).SetUint64(2), *new(big.Int).SetUint64(3), true) 76 | addr, err = Sender(signer, tx) 77 | assert.Nil(t, err) 78 | assert.Equal(t, addr, from) 79 | } 80 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /validator.go: -------------------------------------------------------------------------------- 1 | package validator 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "github.com/DSiSc/craft/log" 7 | "github.com/DSiSc/craft/types" 8 | "github.com/DSiSc/repository" 9 | "github.com/DSiSc/validator/tools/account" 10 | "github.com/DSiSc/validator/tools/signature" 11 | "github.com/DSiSc/validator/worker" 12 | ) 13 | 14 | type Validator struct { 15 | Account *account.Account 16 | Receipts types.Receipts 17 | } 18 | 19 | func NewValidator(account *account.Account) *Validator { 20 | return &Validator{ 21 | Account: account, 22 | } 23 | } 24 | 25 | func (self *Validator) ValidateBlock(block *types.Block, signVerify bool) (*types.Header, error) { 26 | chain, err := repository.NewLatestStateRepository() 27 | if err != nil { 28 | return nil, fmt.Errorf("get NewLatestStateRepository error:%s ", err) 29 | } 30 | // new worker to verify the block 31 | work := worker.NewWorker(chain, block, signVerify) 32 | err = work.VerifyBlock() 33 | if nil != err { 34 | return nil, err 35 | } 36 | self.Receipts = work.GetReceipts() 37 | // sign the block 38 | sign, ok := signature.Sign(self.Account, block.Header.MixDigest[:]) 39 | if ok != nil { 40 | return nil, fmt.Errorf("sign block failed with error: %s", ok) 41 | } 42 | 43 | notSigned := true 44 | for _, value := range block.Header.SigData { 45 | if bytes.Equal(value, sign) { 46 | notSigned = false 47 | log.Warn("Duplicate sign.") 48 | break 49 | } 50 | } 51 | if notSigned { 52 | block.Header.SigData = append(block.Header.SigData, sign) 53 | log.Debug("Validator add sign %x to block %d.", sign, block.Header.Height) 54 | } 55 | 56 | return block.Header, nil 57 | } 58 | -------------------------------------------------------------------------------- /validator_test.go: -------------------------------------------------------------------------------- 1 | package validator 2 | 3 | import ( 4 | "fmt" 5 | "github.com/DSiSc/craft/types" 6 | "github.com/DSiSc/monkey" 7 | "github.com/DSiSc/repository" 8 | account2 "github.com/DSiSc/validator/tools/account" 9 | "github.com/DSiSc/validator/tools/signature" 10 | "github.com/DSiSc/validator/worker" 11 | "github.com/stretchr/testify/assert" 12 | "reflect" 13 | "testing" 14 | "time" 15 | ) 16 | 17 | var validator *Validator 18 | 19 | var MockHash = types.Hash{ 20 | 0x1d, 0xcf, 0x7, 0xba, 0xfc, 0x42, 0xb0, 0x8d, 0xfd, 0x23, 0x9c, 0x45, 0xa4, 0xb9, 0x38, 0xd, 21 | 0x8d, 0xfe, 0x5d, 0x6f, 0xa7, 0xdb, 0xd5, 0x50, 0xc9, 0x25, 0xb1, 0xb3, 0x4, 0xdc, 0xc5, 0x1c, 22 | } 23 | 24 | var mockBlock = &types.Block{ 25 | Header: &types.Header{ 26 | ChainID: 1, 27 | PrevBlockHash: MockHash, 28 | StateRoot: MockHash, 29 | TxRoot: MockHash, 30 | ReceiptsRoot: MockHash, 31 | Height: 1, 32 | Timestamp: uint64(time.Date(2018, time.August, 28, 0, 0, 0, 0, time.UTC).Unix()), 33 | MixDigest: MockHash, 34 | }, 35 | Transactions: make([]*types.Transaction, 0), 36 | } 37 | 38 | func TestNewValidator(t *testing.T) { 39 | var account account2.Account 40 | validator = NewValidator(&account) 41 | assert.NotNil(t, validator) 42 | } 43 | 44 | func TestValidateBlock(t *testing.T) { 45 | assert := assert.New(t) 46 | monkey.Patch(repository.NewLatestStateRepository, func() (*repository.Repository, error) { 47 | return nil, fmt.Errorf("mock error") 48 | }) 49 | header, err := validator.ValidateBlock(mockBlock, false) 50 | assert.Nil(header) 51 | assert.NotNil(err) 52 | assert.Equal(err, fmt.Errorf("get NewLatestStateRepository error:mock error ")) 53 | 54 | monkey.Patch(repository.NewLatestStateRepository, func() (*repository.Repository, error) { 55 | return nil, nil 56 | }) 57 | var woker *worker.Worker 58 | monkey.PatchInstanceMethod(reflect.TypeOf(woker), "VerifyBlock", func(*worker.Worker) error { 59 | return fmt.Errorf("verify block failed") 60 | }) 61 | header, err = validator.ValidateBlock(mockBlock, false) 62 | assert.Nil(header) 63 | assert.NotNil(err) 64 | assert.Equal(err, fmt.Errorf("verify block failed")) 65 | 66 | monkey.PatchInstanceMethod(reflect.TypeOf(woker), "VerifyBlock", func(*worker.Worker) error { 67 | return nil 68 | }) 69 | 70 | monkey.Patch(signature.Sign, func(signature.Signer, []byte) ([]byte, error) { 71 | return MockHash[:], fmt.Errorf("sign block failed") 72 | }) 73 | header, err = validator.ValidateBlock(mockBlock, false) 74 | assert.Equal(err, fmt.Errorf("sign block failed with error: sign block failed")) 75 | assert.Nil(header) 76 | 77 | monkey.Patch(signature.Sign, func(signature.Signer, []byte) ([]byte, error) { 78 | return MockHash[:], nil 79 | }) 80 | var mockSignData [][]byte 81 | mockBlock.Header.SigData = mockSignData 82 | header, err = validator.ValidateBlock(mockBlock, false) 83 | assert.Nil(err) 84 | assert.NotNil(header) 85 | assert.Equal(MockHash[:], mockBlock.Header.SigData[0][:]) 86 | 87 | mockBlock.Header.SigData = append(mockBlock.Header.SigData, MockHash[:]) 88 | header, err = validator.ValidateBlock(mockBlock, false) 89 | assert.Nil(err) 90 | assert.NotNil(header) 91 | assert.Equal(MockHash[:], mockBlock.Header.SigData[0][:]) 92 | monkey.UnpatchAll() 93 | } 94 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /worker/common/errors.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | var ( 8 | // ErrGasLimitReached is returned by the gas pool if the amount of gas required 9 | // by a transaction is higher than what's left in the block. 10 | ErrGasLimitReached = errors.New("gas reached limit") 11 | ErrInsufficientBalanceForGas = errors.New("insufficient balance to pay for gas") 12 | ) 13 | -------------------------------------------------------------------------------- /worker/common/gaspool.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | ) 7 | 8 | type GasPool uint64 9 | 10 | // AddGas makes gas available for execution. 11 | func (gp *GasPool) AddGas(amount uint64) *GasPool { 12 | if uint64(*gp) > math.MaxUint64-amount { 13 | panic("gas pool pushed above uint64") 14 | } 15 | *(*uint64)(gp) += amount 16 | return gp 17 | } 18 | 19 | // SubGas deducts the given amount from the pool if enough gas is 20 | // available and returns an error otherwise. 21 | func (gp *GasPool) SubGas(amount uint64) error { 22 | if uint64(*gp) < amount { 23 | return ErrGasLimitReached 24 | } 25 | *(*uint64)(gp) -= amount 26 | return nil 27 | } 28 | 29 | // Gas returns the amount of gas remaining in the pool. 30 | func (gp *GasPool) Gas() uint64 { 31 | return uint64(*gp) 32 | } 33 | 34 | func (gp *GasPool) String() string { 35 | return fmt.Sprintf("%d", *gp) 36 | } 37 | -------------------------------------------------------------------------------- /worker/common/gaspool_test.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "testing" 6 | ) 7 | 8 | func Test_NewGasPool(t *testing.T) { 9 | assert := assert.New(t) 10 | gasInit := GasPool(100) 11 | gasInitPoint := &gasInit 12 | assert.NotNil(gasInitPoint) 13 | 14 | assert.Equal(uint64(100), gasInitPoint.Gas()) 15 | 16 | addGas := gasInitPoint.AddGas(uint64(20)) 17 | assert.Equal(GasPool(120), *addGas) 18 | assert.Equal(GasPool(120), *gasInitPoint) 19 | 20 | err := gasInitPoint.SubGas(uint64(20)) 21 | assert.Nil(err) 22 | assert.Equal(GasPool(100), *gasInitPoint) 23 | 24 | assert.Equal("100", gasInitPoint.String()) 25 | } 26 | -------------------------------------------------------------------------------- /worker/common/log.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "github.com/DSiSc/craft/types" 5 | ) 6 | 7 | type Log struct { 8 | // Consensus fields: 9 | // address of the contract that generated the event 10 | Address types.Address `json:"address" gencodec:"required"` 11 | // list of topics provided by the contract. 12 | Topics []types.Hash `json:"topics" gencodec:"required"` 13 | // supplied by the contract, usually ABI-encoded 14 | Data []byte `json:"data" gencodec:"required"` 15 | 16 | // Derived fields. These fields are filled in by the node 17 | // but not secured by consensus. 18 | // block in which the transaction was included 19 | BlockNumber uint64 `json:"blockNumber"` 20 | // hash of the transaction 21 | TxHash types.Hash `json:"transactionHash" gencodec:"required"` 22 | // index of the transaction in the block 23 | TxIndex uint `json:"transactionIndex" gencodec:"required"` 24 | // hash of the block in which the transaction was included 25 | BlockHash types.Hash `json:"blockHash"` 26 | // index of the log in the receipt 27 | Index uint `json:"logIndex" gencodec:"required"` 28 | 29 | // The Removed field is true if this log was reverted due to a chain reorganisation. 30 | // You must pay attention to this field if you receive logs through a filter query. 31 | Removed bool `json:"removed"` 32 | } 33 | -------------------------------------------------------------------------------- /worker/common/receipt.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/DSiSc/craft/types" 6 | "github.com/DSiSc/validator/common" 7 | ) 8 | 9 | const ( 10 | // ReceiptStatusFailed is the status code of a transaction if execution failed. 11 | ReceiptStatusFailed = uint64(0) 12 | 13 | // ReceiptStatusSuccessful is the status code of a transaction if execution succeeded. 14 | ReceiptStatusSuccessful = uint64(1) 15 | ) 16 | 17 | func CopyBytes(b []byte) (copiedBytes []byte) { 18 | if b == nil { 19 | return nil 20 | } 21 | copiedBytes = make([]byte, len(b)) 22 | copy(copiedBytes, b) 23 | 24 | return 25 | } 26 | 27 | // NewReceipt creates a barebone transaction receipt, copying the init fields. 28 | func NewReceipt(root []byte, failed bool, cumulativeGasUsed uint64) *types.Receipt { 29 | r := &types.Receipt{PostState: CopyBytes(root), CumulativeGasUsed: cumulativeGasUsed} 30 | if failed { 31 | r.Status = ReceiptStatusFailed 32 | } else { 33 | r.Status = ReceiptStatusSuccessful 34 | } 35 | return r 36 | } 37 | 38 | // compute hash of receipt 39 | func ReceiptHash(receipt *types.Receipt) (hash types.Hash) { 40 | jsonByte, _ := json.Marshal(receipt) 41 | sumByte := common.Sum(jsonByte) 42 | copy(hash[:], sumByte) 43 | return 44 | } 45 | -------------------------------------------------------------------------------- /worker/common/receipt_test.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "github.com/DSiSc/craft/types" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | ) 8 | 9 | func Test_NewReceipt(t *testing.T) { 10 | assert := assert.New(t) 11 | recept := NewReceipt(nil, true, uint64(0)) 12 | assert.NotNil(recept) 13 | assert.Equal(recept.Status, ReceiptStatusFailed) 14 | recept = NewReceipt(nil, false, uint64(0)) 15 | assert.Equal(recept.Status, ReceiptStatusSuccessful) 16 | } 17 | 18 | func TestReceipt_ReceiptHash(t *testing.T) { 19 | assert := assert.New(t) 20 | receipt := NewReceipt(nil, false, uint64(0)) 21 | assert.Equal(receipt.Status, ReceiptStatusSuccessful) 22 | receiptHash := ReceiptHash(receipt) 23 | var except = types.Hash{0x1, 0x8, 0x22, 0xb1, 0x12, 0x1, 0xd3, 0x70, 0x7d, 0x48, 0xc5, 0x4b, 0x2, 0xf4, 0x82, 0x7d, 0x95, 0x4e, 0xfd, 0x25, 0x6a, 0xc, 0xaa, 0xf5, 0x60, 0x62, 0x39, 0x6, 0x52, 0x3a, 0x2a, 0xa5} 24 | 25 | assert.Equal(except, receiptHash) 26 | } 27 | -------------------------------------------------------------------------------- /worker/state.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "errors" 5 | "github.com/DSiSc/craft/log" 6 | "github.com/DSiSc/craft/types" 7 | evmNg "github.com/DSiSc/evm-NG" 8 | "github.com/DSiSc/repository" 9 | evmCommon "github.com/DSiSc/validator/common" 10 | "github.com/DSiSc/validator/worker/common" 11 | wasmExec "github.com/DSiSc/wasm/exec" 12 | wasmModule "github.com/DSiSc/wasm/wasm" 13 | "math" 14 | "math/big" 15 | ) 16 | 17 | type StateTransition struct { 18 | gp *common.GasPool 19 | tx *types.Transaction 20 | gas uint64 21 | gasPrice *big.Int 22 | initialGas uint64 23 | value *big.Int 24 | data []byte 25 | state *repository.Repository 26 | from types.Address 27 | to types.Address 28 | nonce uint64 29 | header *types.Header 30 | author types.Address 31 | } 32 | 33 | // NewStateTransition initialises and returns a new state transition object. 34 | func NewStateTransition(author types.Address, header *types.Header, chain *repository.Repository, trx *types.Transaction, gp *common.GasPool) *StateTransition { 35 | var receive types.Address 36 | if trx.Data.Recipient == nil /* contract creation */ { 37 | receive = types.Address{} 38 | } else { 39 | receive = *trx.Data.Recipient 40 | } 41 | return &StateTransition{ 42 | author: author, 43 | gp: gp, 44 | tx: trx, 45 | from: *trx.Data.From, 46 | to: receive, 47 | gasPrice: trx.Data.Price, 48 | value: trx.Data.Amount, 49 | data: trx.Data.Payload, 50 | state: chain, 51 | gas: trx.Data.GasLimit, 52 | initialGas: math.MaxUint64, 53 | nonce: trx.Data.AccountNonce, 54 | header: header, 55 | } 56 | } 57 | 58 | // ApplyMessage computes the new state by applying the given message 59 | // against the old state within the environment. 60 | // ApplyMessage returns the bytes returned by any EVM execution (if it took place), 61 | // the gas used (which includes gas refunds) and an error if it failed. An error always 62 | // indicates a core error meaning that the message would always fail for that particular 63 | // state and would never be accepted within a block. 64 | func ApplyTransaction(author types.Address, header *types.Header, chain *repository.Repository, tx *types.Transaction, gp *common.GasPool) ([]byte, uint64, bool, error, types.Address) { 65 | return NewStateTransition(author, header, chain, tx, gp).TransitionDb() 66 | } 67 | 68 | // TransitionDb will transition the state by applying the current message and 69 | // returning the result including the used gas. It returns an error if failed. 70 | // An error indicates a consensus issue. 71 | func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bool, err error, address types.Address) { 72 | if err = st.preCheck(); err != nil { 73 | return 74 | } 75 | if st.isWasmContract(st.tx) { 76 | ret, address, st.gas, err = st.execWasmContract() 77 | } else { 78 | var vmerr error 79 | ret, address, st.gas, vmerr = st.execSolidityContract() 80 | if vmerr != nil { 81 | log.Debug("VM returned with error", "err", vmerr) 82 | // The only possible consensus-error would be if there wasn't 83 | // sufficient balance to make the transfer happen. The first 84 | // balance transfer may never fail. 85 | if vmerr == evmNg.ErrInsufficientBalance { 86 | return ret, 0, false, vmerr, address 87 | } 88 | } 89 | } 90 | return ret, st.gasUsed(), err != nil, err, address 91 | } 92 | 93 | func (st *StateTransition) refundGas() { 94 | // Apply refund counter, capped to half of the used gas. 95 | refund := st.gasUsed() / 2 96 | if refund > st.state.GetRefund() { 97 | refund = st.state.GetRefund() 98 | } 99 | st.gas += refund 100 | 101 | // Return ETH for remaining gas, exchanged at the original rate. 102 | remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice) 103 | st.state.AddBalance(*st.tx.Data.From, remaining) 104 | 105 | // Also return remaining gas to the block gas counter so it is 106 | // available for the next transaction. 107 | st.gp.AddGas(st.gas) 108 | } 109 | 110 | // gasUsed returns the amount of gas used up by the state transition. 111 | func (st *StateTransition) gasUsed() uint64 { 112 | return st.initialGas - st.gas 113 | } 114 | 115 | // check tx's nonce 116 | func (st *StateTransition) preCheck() error { 117 | // Make sure this transaction's nonce is correct. 118 | nonce := st.state.GetNonce(st.from) 119 | if nonce < st.nonce { 120 | return errors.New("blacklisted hash") 121 | } else if nonce > st.nonce { 122 | return errors.New("nonce too high") 123 | } 124 | return nil 125 | } 126 | 127 | // check whether the tx Recipient is wasm contract 128 | func (st *StateTransition) isWasmContract(tx *types.Transaction) bool { 129 | var code []byte 130 | if (nil == tx.Data.Recipient || types.Address{} == *tx.Data.Recipient) { 131 | code = tx.Data.Payload 132 | } else { 133 | code = st.state.GetCode(*tx.Data.Recipient) 134 | } 135 | return wasmModule.IsValidWasmCode(code) 136 | } 137 | 138 | func (st *StateTransition) execSolidityContract() (ret []byte, contractAddr types.Address, leftOverGas uint64, err error) { 139 | from := *st.tx.Data.From 140 | sender := evmCommon.NewRefAddress(from) 141 | //homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber) 142 | contractCreation := st.tx.Data.Recipient == nil 143 | /* 144 | // Pay intrinsic gas 145 | gas, err := IntrinsicGas(st.data, contractCreation, homestead) 146 | if err != nil { 147 | return nil, 0, false, err 148 | } 149 | if err = st.useGas(gas); err != nil { 150 | return nil, 0, false, err 151 | } 152 | */ 153 | context := evmNg.NewEVMContext(*st.tx, st.header, st.state, st.author) 154 | evm := evmNg.NewEVM(context, st.state) 155 | 156 | if contractCreation { 157 | // ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value) 158 | ret, contractAddr, leftOverGas, err = evm.Create(sender, st.data, math.MaxUint64, st.value) 159 | } else { 160 | // Increment the nonce for the next transaction 161 | st.state.SetNonce(from, st.state.GetNonce(sender.Address())+1) 162 | ret, leftOverGas, err = evm.Call(sender, st.to, st.data, math.MaxUint64, st.value) 163 | } 164 | return ret, contractAddr, leftOverGas, err 165 | } 166 | 167 | func (st *StateTransition) execWasmContract() (ret []byte, contractAddr types.Address, leftOverGas uint64, err error) { 168 | context := wasmExec.NewWasmChainContext(st.tx, st.header, st.state, st.author) 169 | wvm := wasmExec.NewVM(context, st.state) 170 | contractCreation := st.tx.Data.Recipient == nil 171 | if contractCreation { 172 | ret, contractAddr, leftOverGas, err = wvm.Create(*st.tx.Data.From, st.data, math.MaxUint64, st.value) 173 | } else { 174 | st.state.SetNonce(*st.tx.Data.From, st.state.GetNonce(*st.tx.Data.From)+1) 175 | ret, leftOverGas, err = wvm.Call(*st.tx.Data.From, *st.tx.Data.Recipient, st.data, math.MaxUint64, st.value) 176 | } 177 | return ret, contractAddr, leftOverGas, err 178 | } 179 | -------------------------------------------------------------------------------- /worker/state_test.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "encoding/hex" 5 | "encoding/json" 6 | "github.com/DSiSc/craft/types" 7 | "github.com/DSiSc/evm-NG" 8 | "github.com/DSiSc/evm-NG/common/math" 9 | "github.com/DSiSc/monkey" 10 | "github.com/DSiSc/repository" 11 | "github.com/DSiSc/validator/worker/common" 12 | "github.com/stretchr/testify/assert" 13 | "math/big" 14 | "reflect" 15 | "testing" 16 | "time" 17 | "fmt" 18 | ) 19 | 20 | var MockHash = types.Hash{ 21 | 0x1d, 0xcf, 0x7, 0xba, 0xfc, 0x42, 0xb0, 0x8d, 0xfd, 0x23, 0x9c, 0x45, 0xa4, 0xb9, 0x38, 0xd, 22 | 0x8d, 0xfe, 0x5d, 0x6f, 0xa7, 0xdb, 0xd5, 0x50, 0xc9, 0x25, 0xb1, 0xb3, 0x4, 0xdc, 0xc5, 0x1c, 23 | } 24 | 25 | var MockBlock = &types.Block{ 26 | Header: &types.Header{ 27 | ChainID: 1, 28 | PrevBlockHash: MockHash, 29 | StateRoot: MockHash, 30 | TxRoot: MockHash, 31 | ReceiptsRoot: MockHash, 32 | Height: 1, 33 | Timestamp: uint64(time.Date(2018, time.August, 28, 0, 0, 0, 0, time.UTC).Unix()), 34 | MixDigest: MockHash, 35 | }, 36 | Transactions: make([]*types.Transaction, 0), 37 | } 38 | 39 | var author = types.Address{ 40 | 0xb1, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, 41 | 0xc2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, 42 | } 43 | 44 | var from = &types.Address{ 45 | 0xb1, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, 46 | 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, 47 | } 48 | 49 | var to = &types.Address{ 50 | 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, 51 | 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, 52 | } 53 | 54 | var contractAddress = types.Address{ 55 | 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, 56 | 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x16, 57 | } 58 | 59 | var wasmContractAddress = types.Address{ 60 | 0x79, 0x46, 0x28, 0x8, 0xf6, 0xd1, 0xa6, 0x42, 0x81, 0xd, 0x96, 0xa1, 0xfb, 0x67, 0x5c, 0x33, 0xcf, 0x60, 0xc8, 0x65, 61 | } 62 | 63 | func mockTrx() *types.Transaction { 64 | return &types.Transaction{ 65 | Data: types.TxData{ 66 | AccountNonce: 0, 67 | Price: new(big.Int).SetUint64(10), 68 | GasLimit: 100, 69 | Recipient: to, 70 | From: from, 71 | Amount: new(big.Int).SetUint64(50), 72 | Payload: to[:10], 73 | }, 74 | } 75 | } 76 | 77 | var state *StateTransition 78 | 79 | func TestNewStateTransition(t *testing.T) { 80 | bc := &repository.Repository{} 81 | var gp = common.GasPool(6) 82 | state = NewStateTransition(author, MockBlock.Header, bc, mockTrx(), &gp) 83 | assert.NotNil(t, state) 84 | assert.NotNil(t, state.tx) 85 | } 86 | 87 | func TestStateTransition_TransitionDb(t *testing.T) { 88 | // test carets contract 89 | bc := &repository.Repository{} 90 | var gp = common.GasPool(10000) 91 | state = NewStateTransition(author, MockBlock.Header, bc, mockTrx(), &gp) 92 | state.tx.Data.Recipient = nil 93 | var evmd *evm.EVM 94 | monkey.PatchInstanceMethod(reflect.TypeOf(evmd), "Create", func(*evm.EVM, evm.ContractRef, []byte, uint64, *big.Int) ([]byte, types.Address, uint64, error) { 95 | return to[:10], contractAddress, 0, evm.ErrInsufficientBalance 96 | }) 97 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "GetBalance", func(*repository.Repository, types.Address) *big.Int { 98 | return new(big.Int).SetUint64(1000) 99 | }) 100 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "SubBalance", func(*repository.Repository, types.Address, *big.Int) { 101 | return 102 | }) 103 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "GetNonce", func(*repository.Repository, types.Address) uint64 { 104 | return 0 105 | }) 106 | ret, used, ok, err, address := state.TransitionDb() 107 | assert.Equal(t, err, evm.ErrInsufficientBalance) 108 | assert.Equal(t, ok, false) 109 | assert.Equal(t, uint64(0), used) 110 | assert.Equal(t, to[:10], ret) 111 | assert.Equal(t, contractAddress, address) 112 | monkey.UnpatchAll() 113 | } 114 | 115 | func TestStateTransition_TransitionDb1(t *testing.T) { 116 | defer monkey.UnpatchAll() 117 | // test transfer token 118 | bc := &repository.Repository{} 119 | var gp = common.GasPool(10000) 120 | state = NewStateTransition(author, MockBlock.Header, bc, mockTrx(), &gp) 121 | var evmd *evm.EVM 122 | monkey.PatchInstanceMethod(reflect.TypeOf(evmd), "Create", func(*evm.EVM, evm.ContractRef, []byte, uint64, *big.Int) ([]byte, types.Address, uint64, error) { 123 | return to[:10], contractAddress, 0, evm.ErrInsufficientBalance 124 | }) 125 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "GetBalance", func(*repository.Repository, types.Address) *big.Int { 126 | return new(big.Int).SetUint64(1000) 127 | }) 128 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "SubBalance", func(*repository.Repository, types.Address, *big.Int) { 129 | return 130 | }) 131 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "GetNonce", func(*repository.Repository, types.Address) uint64 { 132 | return 0 133 | }) 134 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "SetNonce", func(b *repository.Repository, a types.Address, n uint64) { 135 | assert.Equal(t, uint64(1), n) 136 | return 137 | }) 138 | monkey.PatchInstanceMethod(reflect.TypeOf(evmd), "Call", func(*evm.EVM, evm.ContractRef, types.Address, []byte, uint64, *big.Int) ([]byte, uint64, error) { 139 | return []byte{0}, math.MaxUint64, nil 140 | }) 141 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "GetCode", func(*repository.Repository, types.Address) []byte { 142 | return []byte{} 143 | }) 144 | ret, used, ok, err, _ := state.TransitionDb() 145 | assert.Equal(t, nil, err) 146 | assert.Equal(t, ok, false) 147 | assert.Equal(t, uint64(0), used) 148 | assert.Equal(t, []byte{0}, ret) 149 | 150 | state.nonce = 100 151 | ret, used, ok, err, _ = state.TransitionDb() 152 | assert.NotNil(t, err) 153 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "GetNonce", func(*repository.Repository, types.Address) uint64 { 154 | return 3 155 | }) 156 | ret, used, ok, err, _ = state.TransitionDb() 157 | assert.NotNil(t, err) 158 | } 159 | 160 | // test create wasm contract 161 | func TestStateTransition_TransitionDb2(t *testing.T) { 162 | // test carets contract 163 | bc := &repository.Repository{} 164 | var gp = common.GasPool(10000) 165 | tx := mockTrx() 166 | code, _ := hex.DecodeString("0061736d0100000001070160027f7f017f03020100070801046961646400000a09010700200020016a0b") 167 | tx.Data.Payload = code 168 | state = NewStateTransition(author, MockBlock.Header, bc, tx, &gp) 169 | state.tx.Data.Recipient = nil 170 | var evmd *evm.EVM 171 | monkey.PatchInstanceMethod(reflect.TypeOf(evmd), "Create", func(*evm.EVM, evm.ContractRef, []byte, uint64, *big.Int) ([]byte, types.Address, uint64, error) { 172 | return to[:10], contractAddress, 0, evm.ErrInsufficientBalance 173 | }) 174 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "GetBalance", func(*repository.Repository, types.Address) *big.Int { 175 | return new(big.Int).SetUint64(1000) 176 | }) 177 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "SubBalance", func(*repository.Repository, types.Address, *big.Int) { 178 | return 179 | }) 180 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "GetNonce", func(*repository.Repository, types.Address) uint64 { 181 | return 0 182 | }) 183 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "AddBalance", func(*repository.Repository, types.Address, *big.Int) { 184 | }) 185 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "SetNonce", func(*repository.Repository, types.Address, uint64) { 186 | }) 187 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "CreateAccount", func(*repository.Repository, types.Address) { 188 | }) 189 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "SetCode", func(*repository.Repository, types.Address, []byte) { 190 | }) 191 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "GetCodeHash", func(*repository.Repository, types.Address) types.Hash { 192 | return types.Hash{} 193 | }) 194 | _, used, ok, err, address := state.TransitionDb() 195 | assert.Nil(t, err) 196 | assert.Equal(t, ok, false) 197 | assert.Equal(t, uint64(0), used) 198 | assert.Equal(t, wasmContractAddress, address) 199 | monkey.UnpatchAll() 200 | } 201 | 202 | // test call wasm contract 203 | func TestStateTransition_TransitionDb3(t *testing.T) { 204 | defer monkey.UnpatchAll() 205 | // test carets contract 206 | bc := &repository.Repository{} 207 | var gp = common.GasPool(10000) 208 | tx := mockTrx() 209 | tx.Data.Recipient = &wasmContractAddress 210 | code, _ := hex.DecodeString("0061736d01000000018c808080000260017f017f60027f7f017f028e808080000103656e76066d616c6c6f6300000382808080000101048480808000017000000583808080000100010681808080000007938080800002066d656d6f7279020006696e766f6b6500010a998080800001938080800001017f41021000220241c8d2013b000020020b") 211 | tx.Data.Payload, _ = json.Marshal([]string{"Hi", "Bob"}) 212 | fmt.Printf("%x", tx.Data.Payload) 213 | state = NewStateTransition(author, MockBlock.Header, bc, tx, &gp) 214 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "GetBalance", func(*repository.Repository, types.Address) *big.Int { 215 | return new(big.Int).SetUint64(1000) 216 | }) 217 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "SubBalance", func(*repository.Repository, types.Address, *big.Int) { 218 | return 219 | }) 220 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "GetNonce", func(*repository.Repository, types.Address) uint64 { 221 | return 0 222 | }) 223 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "AddBalance", func(*repository.Repository, types.Address, *big.Int) { 224 | }) 225 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "SetNonce", func(*repository.Repository, types.Address, uint64) { 226 | }) 227 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "CreateAccount", func(*repository.Repository, types.Address) { 228 | }) 229 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "GetCode", func(*repository.Repository, types.Address) []byte { 230 | return code 231 | }) 232 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "SetCode", func(*repository.Repository, types.Address, []byte) { 233 | }) 234 | monkey.PatchInstanceMethod(reflect.TypeOf(bc), "GetCodeHash", func(*repository.Repository, types.Address) types.Hash { 235 | return types.Hash{} 236 | }) 237 | ret, used, ok, err, address := state.TransitionDb() 238 | assert.Nil(t, err) 239 | assert.Equal(t, []byte{'H', 'i'}, ret) 240 | assert.Equal(t, ok, false) 241 | assert.Equal(t, uint64(0), used) 242 | assert.Equal(t, types.Address{}, address) 243 | monkey.UnpatchAll() 244 | } 245 | -------------------------------------------------------------------------------- /worker/worker.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "github.com/DSiSc/craft/log" 7 | "github.com/DSiSc/craft/types" 8 | "github.com/DSiSc/repository" 9 | vcommon "github.com/DSiSc/validator/common" 10 | "github.com/DSiSc/validator/tools/merkle_tree" 11 | "github.com/DSiSc/validator/worker/common" 12 | wallett "github.com/DSiSc/wallet/core/types" 13 | "math/big" 14 | ) 15 | 16 | type Worker struct { 17 | block *types.Block 18 | chain *repository.Repository 19 | receipts types.Receipts 20 | logs []*types.Log 21 | signature bool 22 | } 23 | 24 | func NewWorker(chain *repository.Repository, block *types.Block, signVerify bool) *Worker { 25 | return &Worker{ 26 | block: block, 27 | chain: chain, 28 | signature: signVerify, 29 | } 30 | } 31 | 32 | func GetTxsRoot(txs []*types.Transaction) types.Hash { 33 | txHash := make([]types.Hash, 0, len(txs)) 34 | for _, t := range txs { 35 | txHash = append(txHash, vcommon.TxHash(t)) 36 | } 37 | txRoot := merkle_tree.ComputeMerkleRoot(txHash) 38 | return txRoot 39 | } 40 | 41 | func (self *Worker) VerifyBlock() error { 42 | // 1. chainID 43 | currentBlock := self.chain.GetCurrentBlock() 44 | if self.block.Header.ChainID != currentBlock.Header.ChainID { 45 | return fmt.Errorf("wrong Block.Header.ChainID, expected %d, got %d", 46 | currentBlock.Header.ChainID, self.block.Header.ChainID) 47 | } 48 | // 2. hash 49 | if self.block.Header.PrevBlockHash != currentBlock.HeaderHash { 50 | return fmt.Errorf("wrong Block.Header.PrevBlockHash, expected %x, got %x", 51 | currentBlock.HeaderHash, self.block.Header.PrevBlockHash) 52 | } 53 | // 3. height 54 | if self.block.Header.Height != self.chain.GetCurrentBlockHeight()+1 { 55 | return fmt.Errorf("wrong Block.Header.Height, expected %x, got %x", 56 | self.chain.GetCurrentBlockHeight()+1, self.block.Header.Height) 57 | } 58 | // 4. txhash 59 | txsHash := GetTxsRoot(self.block.Transactions) 60 | if self.block.Header.TxRoot != txsHash { 61 | return fmt.Errorf("wrong Block.Header.TxRoot, expected %x, got %x", 62 | txsHash, self.block.Header.TxRoot) 63 | } 64 | //5. header hash 65 | if !(self.block.HeaderHash == types.Hash{}) { 66 | headerHash := vcommon.HeaderHash(self.block) 67 | if self.block.HeaderHash != headerHash { 68 | return fmt.Errorf("wrong Block.HeaderHash, expected %x, got %x", 69 | headerHash, self.block.HeaderHash) 70 | } 71 | } 72 | var ( 73 | receipts types.Receipts 74 | allLogs []*types.Log 75 | gp = new(common.GasPool).AddGas(uint64(65536)) 76 | ) 77 | // 6. verify every transactions in the block by evm 78 | for i, tx := range self.block.Transactions { 79 | self.chain.Prepare(vcommon.TxHash(tx), self.block.Header.PrevBlockHash, i) 80 | receipt, _, err := self.VerifyTransaction(self.block.Header.CoinBase, gp, self.block.Header, tx, new(uint64)) 81 | if err != nil { 82 | log.Error("Tx %x verify failed with error %v.", vcommon.TxHash(tx), err) 83 | return err 84 | } 85 | receipts = append(receipts, receipt) 86 | allLogs = append(allLogs, receipt.Logs...) 87 | } 88 | receiptsHash := make([]types.Hash, 0, len(receipts)) 89 | for _, t := range receipts { 90 | receiptsHash = append(receiptsHash, common.ReceiptHash(t)) 91 | log.Debug("Record tx %x receipt is %x.", t.TxHash, common.ReceiptHash(t)) 92 | } 93 | receiptHash := merkle_tree.ComputeMerkleRoot(receiptsHash) 94 | if !(self.block.Header.ReceiptsRoot == types.Hash{}) { 95 | log.Warn("Receipts root has assigned with %x.", self.block.Header.ReceiptsRoot) 96 | if !(receiptHash == self.block.Header.ReceiptsRoot) { 97 | log.Error("Receipts root has assigned with %x, but not consistent with %x.", 98 | self.block.Header.ReceiptsRoot, receiptHash) 99 | return fmt.Errorf("receipts hash not consistent") 100 | } 101 | } else { 102 | log.Debug("Assign receipts hash %x to block %d.", receiptHash, self.block.Header.Height) 103 | self.block.Header.ReceiptsRoot = receiptHash 104 | } 105 | // 7. verify digest if it exists 106 | if !(self.block.Header.MixDigest == types.Hash{}) { 107 | digestHash := vcommon.HeaderDigest(self.block.Header) 108 | if !bytes.Equal(digestHash[:], self.block.Header.MixDigest[:]) { 109 | log.Error("Block digest not consistent which assignment is [%x], while compute is [%x].", 110 | self.block.Header.MixDigest, digestHash) 111 | return fmt.Errorf("digest not in coincidence") 112 | } 113 | } 114 | // TODO 8. verify state root 115 | self.receipts = receipts 116 | self.logs = allLogs 117 | 118 | return nil 119 | } 120 | 121 | func (self *Worker) VerifyTransaction(author types.Address, gp *common.GasPool, header *types.Header, 122 | tx *types.Transaction, usedGas *uint64) (*types.Receipt, uint64, error) { 123 | // txs signature has been verified by tx switch already, so ignore it here 124 | if self.signature { 125 | if self.VerifyTrsSignature(tx) == false { 126 | log.Error("Transaction signature verify failed.") 127 | return nil, 0, fmt.Errorf("transaction signature failed") 128 | } 129 | } 130 | _, gas, failed, err, contractAddress := ApplyTransaction(author, header, self.chain, tx, gp) 131 | if err != nil { 132 | log.Error("Apply transaction %x failed with error %v.", vcommon.TxHash(tx), err) 133 | return nil, 0, err 134 | } 135 | 136 | root := self.chain.IntermediateRoot(false) 137 | *usedGas += gas 138 | 139 | // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx 140 | // based on the eip phase, we're passing wether the root touch-delete accounts. 141 | receipt := common.NewReceipt(vcommon.HashToByte(root), failed, *usedGas) 142 | receipt.TxHash = vcommon.TxHash(tx) 143 | receipt.GasUsed = gas 144 | // if the transaction created a contract, store the creation address in the receipt. 145 | if tx.Data.Recipient == nil { 146 | log.Info("Create contract with address %x within tx %x.", receipt.ContractAddress, receipt.TxHash) 147 | receipt.ContractAddress = contractAddress 148 | } 149 | // Set the receipt logs and create a bloom for filtering 150 | receipt.Logs = self.chain.GetLogs(receipt.TxHash) 151 | receipt.Bloom = vcommon.CreateBloom(types.Receipts{receipt}) 152 | 153 | return receipt, gas, err 154 | } 155 | 156 | func (self *Worker) VerifyTrsSignature(tx *types.Transaction) bool { 157 | id := self.block.Header.ChainID 158 | chainId := int64(id) 159 | signer := wallett.NewEIP155Signer(big.NewInt(chainId)) 160 | //signer := new(wallett.FrontierSigner) 161 | from, err := wallett.Sender(signer, tx) 162 | if nil != err { 163 | log.Error("Get from by tx's %x signer failed with %v.", vcommon.TxHash(tx), err) 164 | return false 165 | } 166 | if !bytes.Equal((*(tx.Data.From))[:], from.Bytes()) { 167 | log.Error("Transaction signature verify failed, tx.Data.From is %x, while signed from is %x.", *tx.Data.From, from) 168 | return false 169 | } 170 | return true 171 | } 172 | 173 | func (self *Worker) GetReceipts() types.Receipts { 174 | log.Debug("Get receipts.") 175 | return self.receipts 176 | } 177 | -------------------------------------------------------------------------------- /worker/worker_test.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "fmt" 5 | "github.com/DSiSc/craft/types" 6 | "github.com/DSiSc/evm-NG" 7 | "github.com/DSiSc/monkey" 8 | "github.com/DSiSc/repository" 9 | "github.com/DSiSc/validator/common" 10 | "github.com/DSiSc/validator/tools" 11 | workerc "github.com/DSiSc/validator/worker/common" 12 | walletc "github.com/DSiSc/wallet/common" 13 | wallett "github.com/DSiSc/wallet/core/types" 14 | "github.com/stretchr/testify/assert" 15 | "math/big" 16 | "reflect" 17 | "testing" 18 | ) 19 | 20 | func TestNewWorker(t *testing.T) { 21 | assert := assert.New(t) 22 | var worker = NewWorker(nil, nil, false) 23 | assert.NotNil(worker) 24 | assert.Nil(worker.block) 25 | assert.Nil(worker.chain) 26 | } 27 | 28 | func TestGetTxsRoot(t *testing.T) { 29 | var trxs = make([]*types.Transaction, 0) 30 | trx := new(types.Transaction) 31 | trxs = append(trxs, trx) 32 | hash := GetTxsRoot(trxs) 33 | assert.NotNil(t, hash) 34 | } 35 | 36 | var addressA = types.Address{ 37 | 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, 38 | 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, 39 | } 40 | 41 | var addressC = walletc.Address{ 42 | 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, 43 | 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x16, 44 | } 45 | 46 | var addressNew = types.Address{ 47 | 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, 48 | 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x17, 49 | } 50 | 51 | var addressB = tools.HexToAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b") 52 | 53 | var mockHash = types.Hash{ 54 | 0x1d, 0xcf, 0x7, 0xba, 0xfc, 0x42, 0xb0, 0x8d, 0xfd, 0x23, 0x9c, 0x45, 0xa4, 0xb9, 0x38, 0xd, 55 | 0x8d, 0xfe, 0x5d, 0x6f, 0xa7, 0xdb, 0xd5, 0x50, 0xc9, 0x25, 0xb1, 0xb3, 0x4, 0xdc, 0xc5, 0x1c, 56 | } 57 | 58 | var mockHash1 = types.Hash{ 59 | 0x1e, 0xcf, 0x7, 0xba, 0xfc, 0x42, 0xb0, 0x8d, 0xfd, 0x23, 0x9c, 0x45, 0xa4, 0xb9, 0x38, 0xd, 60 | 0x8d, 0xfe, 0x5d, 0x6f, 0xa7, 0xdb, 0xd5, 0x50, 0xc9, 0x25, 0xb1, 0xb3, 0x4, 0xdc, 0xc5, 0x1c, 61 | } 62 | 63 | func TestWorker_VerifyTrsSignature(t *testing.T) { 64 | key, _ := wallett.DefaultTestKey() 65 | mockBlock := &types.Block{ 66 | Header: &types.Header{ 67 | ChainID: uint64(1), 68 | Height: uint64(1), 69 | }, 70 | } 71 | 72 | mockTrx := &types.Transaction{ 73 | Data: types.TxData{ 74 | AccountNonce: uint64(0), 75 | Price: new(big.Int), 76 | Recipient: &addressA, 77 | From: &addressB, 78 | Amount: new(big.Int), 79 | Payload: addressB[:10], 80 | }, 81 | } 82 | mockTransaction, _ := wallett.SignTx(mockTrx, wallett.NewEIP155Signer(big.NewInt(1)), key) 83 | worker := NewWorker(nil, mockBlock, false) 84 | ok := worker.VerifyTrsSignature(mockTransaction) 85 | assert.Equal(t, true, ok) 86 | 87 | monkey.Patch(wallett.Sender, func(wallett.Signer, *types.Transaction) (walletc.Address, error) { 88 | return addressC, fmt.Errorf("unknown signer") 89 | }) 90 | ok = worker.VerifyTrsSignature(mockTransaction) 91 | assert.Equal(t, false, ok) 92 | 93 | monkey.Patch(wallett.Sender, func(wallett.Signer, *types.Transaction) (walletc.Address, error) { 94 | return addressC, nil 95 | }) 96 | ok = worker.VerifyTrsSignature(mockTransaction) 97 | assert.Equal(t, false, ok) 98 | monkey.UnpatchAll() 99 | } 100 | 101 | func TestWorker_VerifyBlock(t *testing.T) { 102 | assert := assert.New(t) 103 | var Repository *repository.Repository 104 | var mockBlock = &types.Block{ 105 | Header: &types.Header{ 106 | ChainID: uint64(1), 107 | Height: uint64(1), 108 | }, 109 | } 110 | worker := NewWorker(nil, mockBlock, false) 111 | 112 | monkey.PatchInstanceMethod(reflect.TypeOf(Repository), "GetCurrentBlock", func(*repository.Repository) *types.Block { 113 | return &types.Block{ 114 | Header: &types.Header{ 115 | ChainID: uint64(0), 116 | }, 117 | } 118 | }) 119 | err := worker.VerifyBlock() 120 | assert.NotNil(err, "chain id not consistent") 121 | 122 | monkey.PatchInstanceMethod(reflect.TypeOf(Repository), "GetCurrentBlock", func(*repository.Repository) *types.Block { 123 | return &types.Block{ 124 | Header: &types.Header{ 125 | ChainID: uint64(1), 126 | }, 127 | HeaderHash: mockHash, 128 | } 129 | }) 130 | err = worker.VerifyBlock() 131 | assert.NotNil(err, "Block pre block hash not consistent") 132 | 133 | monkey.PatchInstanceMethod(reflect.TypeOf(Repository), "GetCurrentBlock", func(*repository.Repository) *types.Block { 134 | return &types.Block{ 135 | Header: &types.Header{ 136 | ChainID: uint64(1), 137 | }, 138 | } 139 | }) 140 | monkey.PatchInstanceMethod(reflect.TypeOf(Repository), "GetCurrentBlockHeight", func(*repository.Repository) uint64 { 141 | return 1 142 | }) 143 | //mockBlock.Header.ChainID = uint64(0) 144 | err = worker.VerifyBlock() 145 | assert.NotNil(err, "Block height not consistent") 146 | 147 | monkey.PatchInstanceMethod(reflect.TypeOf(Repository), "GetCurrentBlockHeight", func(*repository.Repository) uint64 { 148 | return 0 149 | }) 150 | worker.block.Header.TxRoot = MockHash 151 | err = worker.VerifyBlock() 152 | assert.NotNil(err, "Block txroot hash not consistent") 153 | 154 | monkey.Patch(common.HeaderHash, func(*types.Block) types.Hash { 155 | return MockHash 156 | }) 157 | var tmp types.Hash 158 | worker.block.Header.TxRoot = tmp 159 | worker.block.HeaderHash = mockHash1 160 | err = worker.VerifyBlock() 161 | assert.NotNil(err, "Block header hash not consistent") 162 | 163 | monkey.Patch(common.HeaderHash, func(*types.Block) types.Hash { 164 | var tmp types.Hash 165 | return tmp 166 | }) 167 | worker.block.Header.ReceiptsRoot = MockHash 168 | worker.block.HeaderHash = common.HeaderHash(worker.block) 169 | err = worker.VerifyBlock() 170 | assert.NotNil(err, "Receipts hash not consistent") 171 | 172 | worker.block.Header.ReceiptsRoot = tmp 173 | err = worker.VerifyBlock() 174 | assert.Nil(err) 175 | monkey.UnpatchAll() 176 | 177 | } 178 | 179 | func TestWorker_VerifyTransaction(t *testing.T) { 180 | assert := assert.New(t) 181 | worker := NewWorker(nil, nil, false) 182 | 183 | monkey.Patch(evm.NewEVMContext, func(types.Transaction, *types.Header, *repository.Repository, types.Address) evm.Context { 184 | return evm.Context{ 185 | GasLimit: uint64(65536), 186 | } 187 | }) 188 | monkey.Patch(ApplyTransaction, func(author types.Address, header *types.Header, chain *repository.Repository, tx *types.Transaction, gp *workerc.GasPool) ([]byte, uint64, bool, error, types.Address) { 189 | return addressA[:10], uint64(0), false, fmt.Errorf("Apply failed."), types.Address{} 190 | }) 191 | mockTrx := &types.Transaction{ 192 | Data: types.TxData{ 193 | AccountNonce: uint64(0), 194 | Price: new(big.Int), 195 | Recipient: &addressA, 196 | From: &addressB, 197 | Amount: new(big.Int), 198 | Payload: addressB[:10], 199 | }, 200 | } 201 | receipt, gas, err := worker.VerifyTransaction(addressA, nil, nil, mockTrx, nil) 202 | assert.Equal(err, fmt.Errorf("Apply failed.")) 203 | assert.Nil(receipt) 204 | assert.Equal(uint64(0), gas) 205 | monkey.UnpatchAll() 206 | } 207 | 208 | func TestWorker_GetReceipts(t *testing.T) { 209 | assert := assert.New(t) 210 | worker := NewWorker(nil, nil, false) 211 | receipts := worker.GetReceipts() 212 | assert.Equal(len(receipts), len(worker.receipts)) 213 | } 214 | --------------------------------------------------------------------------------