From cfa6d7c77ab1be9da5db250586436190b4e62561 Mon Sep 17 00:00:00 2001 From: clearloop Date: Thu, 27 Aug 2020 13:17:42 +0800 Subject: [PATCH 01/36] Merge rustify into ropsten --- .github/workflows/golangci.yml | 3 - .github/workflows/shadow.yml | 90 --- Cargo.toml | 20 +- README.md | 66 +- api/api.go | 82 --- api/docs/docs.go | 577 ------------------ api/docs/swagger.json | 515 ---------------- api/docs/swagger.yaml | 350 ----------- api/http.go | 242 -------- api/types.go | 7 - bin/main.go | 10 - build.rs | 32 + cmd/epoch.go | 29 - cmd/header.go | 45 -- cmd/import.go | 91 --- cmd/mmr.go | 1 - cmd/proof.go | 58 -- cmd/receipt.go | 29 - cmd/root.go | 60 -- cmd/run.go | 161 ----- cmd/version.go | 15 - examples/doctor.rs | 4 +- examples/header.rs | 11 + examples/proof.rs | 10 + examples/receipt.rs | 38 ++ examples/runner.rs | 6 +- examples/uncle.rs | 4 +- go.mod | 12 +- go.sum | 227 ------- internal/core/cache.go | 201 ------ internal/core/enum.go | 28 - internal/core/scale.go | 93 --- internal/core/schema.go | 132 ---- internal/core/shadow.go | 210 ------- internal/core/sql.go | 31 - internal/core/types.go | 132 ---- internal/eth/geth.go | 60 -- internal/eth/serde.go | 86 --- internal/ffi/mmr.go | 18 - internal/tests/shadow_test.go | 94 --- internal/util/parallel.go | 18 - makefile | 14 - mmr/bridge/ethash_proof.rs | 36 -- mmr/bridge/header.rs | 92 --- mmr/bridge/mod.rs | 32 - mmr/bridge/util.rs | 91 --- mmr/ffi/mod.rs | 54 -- mmr/result.rs | 26 - mmr/runner.rs | 154 ----- mmr/schema.rs | 16 - mock/proofs.go | 160 ----- mock/uncle.go | 18 - {internal => pkg/internal}/config.go | 2 +- {internal => pkg/internal}/eth/api.go | 0 {internal => pkg/internal}/eth/header.go | 27 +- {internal => pkg/internal}/eth/mock.go | 2 +- {internal => pkg/internal}/eth/proof.go | 10 +- {internal => pkg/internal}/eth/receipt.go | 13 +- pkg/internal/eth/scale.go | 48 ++ {internal => pkg/internal}/eth/types.go | 0 pkg/internal/ffi/mod.go | 43 ++ {internal => pkg/internal}/lock.go | 0 {internal => pkg/internal}/log/mod.go | 0 {internal => pkg/internal}/util/assert.go | 2 +- {internal => pkg/internal}/util/collection.go | 0 {internal => pkg/internal}/util/encode.go | 0 src/api/eth/mod.rs | 6 + src/api/eth/proposal.rs | 108 ++++ src/api/eth/receipt.rs | 59 ++ src/api/mod.rs | 19 + src/bin/shadow.rs | 4 + src/chain/array.rs | 38 ++ src/chain/byte.rs | 156 +++++ src/chain/eth/ethash_proof.rs | 56 ++ src/chain/eth/header.rs | 170 ++++++ mmr/bridge/relay.rs => src/chain/eth/mod.rs | 13 +- src/chain/mod.rs | 8 + src/chain/req.rs | 1 + src/cmd/mod.rs | 63 ++ src/conf.rs | 3 + src/db/mod.rs | 4 + {mmr => src/db}/model.rs | 12 - {mmr => src/db}/pool.rs | 2 +- src/db/schema.rs | 9 + {mmr => src/db}/sql.rs | 0 {mmr => src}/lib.rs | 24 +- {mmr => src/mmr}/hash.rs | 0 {mmr => src/mmr}/helper.rs | 1 - src/mmr/mod.rs | 4 + src/mmr/runner.rs | 112 ++++ {mmr => src/mmr}/store.rs | 4 +- src/result.rs | 53 ++ tests/mmr.rs | 6 +- tests/mock/mod.rs | 29 +- tests/scale.rs | 12 +- 95 files changed, 1164 insertions(+), 4550 deletions(-) delete mode 100644 .github/workflows/shadow.yml delete mode 100644 api/api.go delete mode 100644 api/docs/docs.go delete mode 100644 api/docs/swagger.json delete mode 100644 api/docs/swagger.yaml delete mode 100644 api/http.go delete mode 100644 api/types.go delete mode 100644 bin/main.go create mode 100644 build.rs delete mode 100644 cmd/epoch.go delete mode 100644 cmd/header.go delete mode 100644 cmd/import.go delete mode 100644 cmd/mmr.go delete mode 100644 cmd/proof.go delete mode 100644 cmd/receipt.go delete mode 100644 cmd/root.go delete mode 100644 cmd/run.go delete mode 100644 cmd/version.go create mode 100644 examples/header.rs create mode 100644 examples/proof.rs create mode 100644 examples/receipt.rs delete mode 100644 internal/core/cache.go delete mode 100644 internal/core/enum.go delete mode 100644 internal/core/scale.go delete mode 100644 internal/core/schema.go delete mode 100644 internal/core/shadow.go delete mode 100644 internal/core/sql.go delete mode 100644 internal/core/types.go delete mode 100644 internal/eth/geth.go delete mode 100644 internal/eth/serde.go delete mode 100644 internal/ffi/mmr.go delete mode 100644 internal/tests/shadow_test.go delete mode 100644 internal/util/parallel.go delete mode 100755 makefile delete mode 100644 mmr/bridge/ethash_proof.rs delete mode 100644 mmr/bridge/header.rs delete mode 100644 mmr/bridge/mod.rs delete mode 100644 mmr/bridge/util.rs delete mode 100644 mmr/ffi/mod.rs delete mode 100644 mmr/result.rs delete mode 100644 mmr/runner.rs delete mode 100644 mmr/schema.rs delete mode 100644 mock/proofs.go delete mode 100644 mock/uncle.go rename {internal => pkg/internal}/config.go (95%) rename {internal => pkg/internal}/eth/api.go (100%) rename {internal => pkg/internal}/eth/header.go (80%) rename {internal => pkg/internal}/eth/mock.go (94%) rename {internal => pkg/internal}/eth/proof.go (93%) rename {internal => pkg/internal}/eth/receipt.go (96%) create mode 100644 pkg/internal/eth/scale.go rename {internal => pkg/internal}/eth/types.go (100%) create mode 100644 pkg/internal/ffi/mod.go rename {internal => pkg/internal}/lock.go (100%) rename {internal => pkg/internal}/log/mod.go (100%) rename {internal => pkg/internal}/util/assert.go (89%) rename {internal => pkg/internal}/util/collection.go (100%) rename {internal => pkg/internal}/util/encode.go (100%) create mode 100644 src/api/eth/mod.rs create mode 100644 src/api/eth/proposal.rs create mode 100644 src/api/eth/receipt.rs create mode 100644 src/api/mod.rs create mode 100644 src/bin/shadow.rs create mode 100644 src/chain/array.rs create mode 100644 src/chain/byte.rs create mode 100644 src/chain/eth/ethash_proof.rs create mode 100644 src/chain/eth/header.rs rename mmr/bridge/relay.rs => src/chain/eth/mod.rs (50%) create mode 100644 src/chain/mod.rs create mode 100644 src/chain/req.rs create mode 100644 src/cmd/mod.rs create mode 100644 src/conf.rs create mode 100644 src/db/mod.rs rename {mmr => src/db}/model.rs (59%) rename {mmr => src/db}/pool.rs (95%) create mode 100644 src/db/schema.rs rename {mmr => src/db}/sql.rs (100%) rename {mmr => src}/lib.rs (61%) rename {mmr => src/mmr}/hash.rs (100%) rename {mmr => src/mmr}/helper.rs (99%) create mode 100644 src/mmr/mod.rs create mode 100644 src/mmr/runner.rs rename {mmr => src/mmr}/store.rs (95%) create mode 100644 src/result.rs diff --git a/.github/workflows/golangci.yml b/.github/workflows/golangci.yml index b272e45a..e353b7e3 100644 --- a/.github/workflows/golangci.yml +++ b/.github/workflows/golangci.yml @@ -35,9 +35,6 @@ jobs: path: ./target key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./Cargo.lock') }} - # Build packages - - name: Build - run: make # Lint code - name: Lint uses: golangci/golangci-lint-action@v1 diff --git a/.github/workflows/shadow.yml b/.github/workflows/shadow.yml deleted file mode 100644 index ec7c5ccd..00000000 --- a/.github/workflows/shadow.yml +++ /dev/null @@ -1,90 +0,0 @@ -# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions - -name: Golang Shadow - -on: - push: - branches: [ master, next ] - pull_request: - branches: [ master, next ] - -jobs: - shadow: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [macOS-latest, ubuntu-latest] - steps: - - # Set up golang env - - name: Set up GO 1.14.4 - uses: actions/setup-go@v1 - with: - go-version: 1.14.4 - id: go - - # Checkout Go module directory - - name: Check out code into the Go module directory - uses: actions/checkout@v2 - with: - working-directory: $GOPATH/src/github.com/darwinia-network/shadow - - # Sqlite3 deps - - name: Environment - run: | - if [[ "$(uname)" == 'Darwin' ]]; then - brew update - brew install sqlite3 - else - sudo apt-get update -y - sudo apt-get install -y libsqlite3-dev libdbus-1-dev - fi - - # Cache go modules - - name: Cache Go Modules - uses: actions/cache@v1 - env: - cache-name: cache-go-modules - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./go.sum') }} - - # Cache ethash - - name: Cache Eth Hash - uses: actions/cache@v1 - env: - cache-name: cache-eth-hash - with: - path: ~/.ethash - key: ${{ runner.os }}-build-${{ env.cache-name }} - - # Cache MMR Library - - name: Cache MMR Library - uses: actions/cache@v1 - env: - cache-name: mmr-cache - with: - path: ./target - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./Cargo.lock') }} - - # Get deps - - name: Get dependencies - run: go mod download - - # Build packages - - name: Build - run: make - - # Trigger api tests when merge - - name: Test shadow API - env: - INFURA_KEY: ${{ secrets.INFURA_KEY }} - run: | - if [[ "$(uname)" == 'Darwin' ]]; then - sudo update_dyld_shared_cache - else - sudo ldconfig - fi - - go test -v ./... diff --git a/Cargo.toml b/Cargo.toml index 077e6d99..46275b3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,22 +1,34 @@ [package] -name = "mmr" +name = "shadow" version = "0.1.0" authors = ["clearloop "] edition = "2018" +[[bin]] +name = "shadow" +path = "src/bin/shadow.rs" + [lib] -path = "mmr/lib.rs" -crate_type = ["rlib", "staticlib"] +path = "src/lib.rs" [dependencies] -uint = "0.8.3" +async-std = "1.6.3" +actix-web = "2.0.0" +actix-rt = "1.0" blake2-rfc = "0.2.18" cmmr = { version = "0.3.0", package = "ckb-merkle-mountain-range"} dirs = "2.0.2" env_logger = "0.7.1" etc = "0.1.7" +futures = "0.3" libc = "0.2.71" log = "0.4.0" +reqwest = { version = "0.10", features = ["json"] } +rlp = "0.4.5" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +structopt = "0.3.17" +uint = "0.8.3" [dependencies.scale] package = "parity-scale-codec" diff --git a/README.md b/README.md index 9d7dcc35..7a86ad64 100644 --- a/README.md +++ b/README.md @@ -7,53 +7,22 @@ The shadow service for relayers and verify workers to retrieve header data and g ## Usage ```sh -$ shadow -The way to Go +shadow 0.1.0 -Usage: - shadow [command] +USAGE: + shadow -Available Commands: - epoch Calculate epoch cache - header Get eth block by number - help Help about any command - proof Proof the block by number - receipt Get receipt by tx hash - run Start shadow service - version Print the version number of dargo +FLAGS: + -h, --help Prints help information + -V, --version Prints version information -Flags: - -h, --help help for shadow - -Use "shadow [command] --help" for more information about a command. +SUBCOMMANDS: + count Current block height in mmr store + help Prints this message or the help of the given subcommand(s) + run Start shadow service + trim Trim mmr from target leaf ``` -You can find shadow's API docs [here][api]. - - -## Getting start with docker - -Downloads the docker compose file of shadow - -``` -$ wget https://raw.githubusercontent.com/darwinia-network/go1/docker-compose/docker-compose.yml -``` - -Swarm the `docker-compose.yml` file - -``` -$ docker-compose up -``` - -This will start: - -+ A geth node -+ A fetcher service -+ A MMR generating service - - -More detail please check the [docker-compose.yml](./docker-compose.yml) - ## Contribute and Build Downloads shadow service @@ -62,17 +31,14 @@ Downloads shadow service git clone https://github.com/darwinia-network/shadow.git ``` -Builds shadow service - -``` -cd shadow && make -``` - Starts shadow service: ``` -# Start shadow service at port 3000 -./target/shadow run -v --http 3000 +# Starts shadow serives at port 3000 +$ cargo run -p 3000 + +# If you have fast eth node: +$ ETHEREUM_RPC= cargo run -p 3000 ``` ## Trouble Shooting diff --git a/api/api.go b/api/api.go deleted file mode 100644 index 15e691ba..00000000 --- a/api/api.go +++ /dev/null @@ -1,82 +0,0 @@ -// @title Shadow API -// @version 1.0 -// @description The shadow service for relayers and verify workers to retrieve header data and generate proof. Shadow will index the data it needs from blockchain nodes, such as Ethereum and Darwinia. -// @termsOfService http://swagger.io/terms/ - -// @contact.name API Support -// @contact.url http://www.swagger.io/support -// @contact.email support@swagger.io - -// @license.name Apache 2.0 -// @license.url http://www.apache.org/licenses/LICENSE-2.0.html - -// @host localhost:8080 -// @BasePath /api/v1 -// @query.collection.format multi - -// @securityDefinitions.basic BasicAuth - -// @securityDefinitions.apikey ApiKeyAuth -// @in header -// @name Authorization - -// @securitydefinitions.oauth2.application OAuth2Application -// @tokenUrl https://example.com/oauth/token -// @scope.write Grants write access -// @scope.admin Grants read and write access to administrative information - -// @securitydefinitions.oauth2.implicit OAuth2Implicit -// @authorizationurl https://example.com/oauth/authorize -// @scope.write Grants write access -// @scope.admin Grants read and write access to administrative information - -// @securitydefinitions.oauth2.password OAuth2Password -// @tokenUrl https://example.com/oauth/token -// @scope.read Grants read access -// @scope.write Grants write access -// @scope.admin Grants read and write access to administrative information - -// @securitydefinitions.oauth2.accessCode OAuth2AccessCode -// @tokenUrl https://example.com/oauth/token -// @authorizationurl https://example.com/oauth/authorize -// @scope.admin Grants read and write access to administrative information - -// @x-extension-openapi {"example": "value on a json format"} -package api - -import ( - "fmt" - - "github.com/darwinia-network/shadow/api/docs" - "github.com/darwinia-network/shadow/internal/core" - "github.com/darwinia-network/shadow/internal/util" - "github.com/gin-gonic/gin" - "github.com/swaggo/files" - "github.com/swaggo/gin-swagger" -) - -func Swagger(shadow *core.Shadow, port string) { - // programatically set swagger info - docs.SwaggerInfo.Title = "Swagger Example API" - docs.SwaggerInfo.Description = "This is a sample server Petstore server." - docs.SwaggerInfo.Version = "1.0" - docs.SwaggerInfo.Host = "petstore.swagger.io" - docs.SwaggerInfo.BasePath = "/v2" - docs.SwaggerInfo.Schemes = []string{"http", "https"} - - gin.SetMode(gin.ReleaseMode) - r := gin.Default() - c, err := NewShadowHTTP(shadow) - util.Assert(err) - - v1 := r.Group("/api/v1") - { - v1.GET("/batch/:block", c.BatchHeaders) - v1.GET("/header/:block", c.GetHeader) - v1.GET("/proof/:block", c.GetProof) - v1.GET("/receipt/:tx", c.GetReceipt) - v1.POST("/proposal", c.Proposal) - } - r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) - util.Assert(r.Run(fmt.Sprintf(":%s", port))) -} diff --git a/api/docs/docs.go b/api/docs/docs.go deleted file mode 100644 index cf55017c..00000000 --- a/api/docs/docs.go +++ /dev/null @@ -1,577 +0,0 @@ -// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT -// This file was generated by swaggo/swag - -package docs - -import ( - "bytes" - "encoding/json" - "strings" - - "github.com/alecthomas/template" - "github.com/swaggo/swag" -) - -var doc = `{ - "schemes": {{ marshal .Schemes }}, - "swagger": "2.0", - "info": { - "description": "{{.Description}}", - "title": "{{.Title}}", - "termsOfService": "http://swagger.io/terms/", - "contact": { - "name": "API Support", - "url": "http://www.swagger.io/support", - "email": "support@swagger.io" - }, - "license": { - "name": "Apache 2.0", - "url": "http://www.apache.org/licenses/LICENSE-2.0.html" - }, - "version": "{{.Version}}" - }, - "host": "{{.Host}}", - "basePath": "{{.BasePath}}", - "paths": { - "/header/{block}": { - "get": { - "description": "Get ETH Header by block number or hash", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "summary": "Get ETH Header by block", - "operationId": "get-header-by-block", - "parameters": [ - { - "type": "number", - "description": "Eth header number", - "name": "block", - "in": "path", - "required": true - }, - { - "type": "number", - "description": "Batch how many blocks", - "name": "batch", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "supports ` + "`" + `[", - "name": "format", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/types.Header" - }, - "headers": { - "Token": { - "type": "string", - "description": "qwerty" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/api.HTTPError" - } - } - } - } - }, - "/proof/{block}": { - "get": { - "description": "Get header with hash proof and mmr roothash", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "summary": "Get header with proof", - "operationId": "get-header-with-proof", - "parameters": [ - { - "type": "string", - "description": "Eth header number or hash", - "name": "block", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "supports ` + "`" + `[", - "name": "format", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/core.GetEthHeaderWithProofJSONResp" - }, - "headers": { - "Token": { - "type": "string", - "description": "qwerty" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/api.HTTPError" - } - } - } - } - }, - "/proposal": { - "post": { - "description": "Get headers by block numbers, used for relay proposal", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "summary": "Get headers by block numbers", - "operationId": "get-headers-by-proposal", - "parameters": [ - { - "type": "array", - "items": { - "type": "integer" - }, - "collectionFormat": "multi", - "description": "Eth header numbers", - "name": "numbers", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "supports ` + "`" + `[", - "name": "format", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "type": "array", - "items": { - "$ref": "#/definitions/core.GetEthHeaderWithProofJSONResp" - } - } - }, - "headers": { - "Token": { - "type": "string", - "description": "qwerty" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/api.HTTPError" - } - } - } - } - }, - "/receipt/{tx}": { - "get": { - "description": "Get receipt by tx hash, used for cross-chain transfer", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "summary": "Get receipt by tx hash", - "operationId": "get-receipt-by-tx", - "parameters": [ - { - "type": "string", - "description": "tx hash", - "name": "tx", - "in": "path", - "required": true - }, - { - "type": "number", - "description": "last confirm block", - "name": "last", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/core.GetReceiptResp" - } - }, - "headers": { - "Token": { - "type": "string", - "description": "qwerty" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/api.HTTPError" - } - } - } - } - } - }, - "definitions": { - "api.HTTPError": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "example": 400 - }, - "message": { - "type": "string", - "example": "status bad request" - } - } - }, - "core.GetEthHeaderWithProofJSONResp": { - "type": "object", - "properties": { - "eth_header": { - "type": "object", - "$ref": "#/definitions/eth.DarwiniaEthHeaderHexFormat" - }, - "ethash_proof": { - "type": "array", - "items": { - "$ref": "#/definitions/eth.DoubleNodeWithMerkleProof" - } - }, - "mmr_root": { - "type": "string" - } - } - }, - "core.GetReceiptResp": { - "type": "object", - "properties": { - "header": { - "type": "object", - "$ref": "#/definitions/eth.DarwiniaEthHeader" - }, - "mmr_proof": { - "type": "array", - "items": { - "type": "string" - } - }, - "receipt_proof": { - "type": "string" - } - } - }, - "eth.DarwiniaEthHeader": { - "type": "object", - "properties": { - "author": { - "type": "string" - }, - "difficulty": { - "type": "integer" - }, - "extra_data": { - "type": "string" - }, - "gas_limit": { - "type": "integer" - }, - "gas_used": { - "type": "integer" - }, - "hash": { - "type": "string" - }, - "log_bloom": { - "type": "string" - }, - "number": { - "type": "integer" - }, - "parent_hash": { - "type": "string" - }, - "receipts_root": { - "type": "string" - }, - "seal": { - "type": "array", - "items": { - "type": "string" - } - }, - "state_root": { - "type": "string" - }, - "timestamp": { - "type": "integer" - }, - "transactions_root": { - "type": "string" - }, - "uncles_hash": { - "type": "string" - } - } - }, - "eth.DarwiniaEthHeaderHexFormat": { - "type": "object", - "properties": { - "author": { - "type": "string" - }, - "difficulty": { - "type": "string" - }, - "extra_data": { - "type": "string" - }, - "gas_limit": { - "type": "string" - }, - "gas_used": { - "type": "string" - }, - "hash": { - "type": "string" - }, - "log_bloom": { - "type": "string" - }, - "number": { - "type": "string" - }, - "parent_hash": { - "type": "string" - }, - "receipts_root": { - "type": "string" - }, - "seal": { - "type": "array", - "items": { - "type": "string" - } - }, - "state_root": { - "type": "string" - }, - "timestamp": { - "type": "string" - }, - "transactions_root": { - "type": "string" - }, - "uncles_hash": { - "type": "string" - } - } - }, - "eth.DoubleNodeWithMerkleProof": { - "type": "object", - "properties": { - "dag_nodes": { - "type": "array", - "items": { - "type": "string" - } - }, - "proof": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "types.Header": { - "type": "object", - "properties": { - "difficulty": { - "type": "string" - }, - "extraData": { - "type": "array", - "items": { - "type": "integer" - } - }, - "gasLimit": { - "type": "integer" - }, - "gasUsed": { - "type": "integer" - }, - "logsBloom": { - "type": "Bloom" - }, - "miner": { - "type": "string" - }, - "mixHash": { - "type": "string" - }, - "nonce": { - "type": "BlockNonce" - }, - "number": { - "type": "string" - }, - "parentHash": { - "type": "string" - }, - "receiptsRoot": { - "type": "string" - }, - "sha3Uncles": { - "type": "string" - }, - "stateRoot": { - "type": "string" - }, - "timestamp": { - "type": "integer" - }, - "transactionsRoot": { - "type": "string" - } - } - } - }, - "securityDefinitions": { - "ApiKeyAuth": { - "type": "apiKey", - "name": "Authorization", - "in": "header" - }, - "BasicAuth": { - "type": "basic" - }, - "OAuth2AccessCode": { - "type": "oauth2", - "flow": "accessCode", - "authorizationUrl": "https://example.com/oauth/authorize", - "tokenUrl": "https://example.com/oauth/token", - "scopes": { - "admin": " Grants read and write access to administrative information" - } - }, - "OAuth2Application": { - "type": "oauth2", - "flow": "application", - "tokenUrl": "https://example.com/oauth/token", - "scopes": { - "admin": " Grants read and write access to administrative information", - "write": " Grants write access" - } - }, - "OAuth2Implicit": { - "type": "oauth2", - "flow": "implicit", - "authorizationUrl": "https://example.com/oauth/authorize", - "scopes": { - "admin": " Grants read and write access to administrative information", - "write": " Grants write access" - } - }, - "OAuth2Password": { - "type": "oauth2", - "flow": "password", - "tokenUrl": "https://example.com/oauth/token", - "scopes": { - "admin": " Grants read and write access to administrative information", - "read": " Grants read access", - "write": " Grants write access" - } - } - }, - "x-extension-openapi": { - "example": "value on a json format" - } -}` - -type swaggerInfo struct { - Version string - Host string - BasePath string - Schemes []string - Title string - Description string -} - -// SwaggerInfo holds exported Swagger Info so clients can modify it -var SwaggerInfo = swaggerInfo{ - Version: "1.0", - Host: "localhost:8080", - BasePath: "/api/v1", - Schemes: []string{}, - Title: "Shadow API", - Description: "The shadow service for relayers and verify workers to retrieve header data and generate proof. Shadow will index the data it needs from blockchain nodes, such as Ethereum and Darwinia.", -} - -type s struct{} - -func (s *s) ReadDoc() string { - sInfo := SwaggerInfo - sInfo.Description = strings.Replace(sInfo.Description, "\n", "\\n", -1) - - t, err := template.New("swagger_info").Funcs(template.FuncMap{ - "marshal": func(v interface{}) string { - a, _ := json.Marshal(v) - return string(a) - }, - }).Parse(doc) - if err != nil { - return doc - } - - var tpl bytes.Buffer - if err := t.Execute(&tpl, sInfo); err != nil { - return doc - } - - return tpl.String() -} - -func init() { - swag.Register(swag.Name, &s{}) -} diff --git a/api/docs/swagger.json b/api/docs/swagger.json deleted file mode 100644 index 6967f071..00000000 --- a/api/docs/swagger.json +++ /dev/null @@ -1,515 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "description": "The shadow service for relayers and verify workers to retrieve header data and generate proof. Shadow will index the data it needs from blockchain nodes, such as Ethereum and Darwinia.", - "title": "Shadow API", - "termsOfService": "http://swagger.io/terms/", - "contact": { - "name": "API Support", - "url": "http://www.swagger.io/support", - "email": "support@swagger.io" - }, - "license": { - "name": "Apache 2.0", - "url": "http://www.apache.org/licenses/LICENSE-2.0.html" - }, - "version": "1.0" - }, - "host": "localhost:8080", - "basePath": "/api/v1", - "paths": { - "/header/{block}": { - "get": { - "description": "Get ETH Header by block number or hash", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "summary": "Get ETH Header by block", - "operationId": "get-header-by-block", - "parameters": [ - { - "type": "number", - "description": "Eth header number", - "name": "block", - "in": "path", - "required": true - }, - { - "type": "number", - "description": "Batch how many blocks", - "name": "batch", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "supports `[", - "name": "format", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/types.Header" - }, - "headers": { - "Token": { - "type": "string", - "description": "qwerty" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/api.HTTPError" - } - } - } - } - }, - "/proof/{block}": { - "get": { - "description": "Get header with hash proof and mmr roothash", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "summary": "Get header with proof", - "operationId": "get-header-with-proof", - "parameters": [ - { - "type": "string", - "description": "Eth header number or hash", - "name": "block", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "supports `[", - "name": "format", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/core.GetEthHeaderWithProofJSONResp" - }, - "headers": { - "Token": { - "type": "string", - "description": "qwerty" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/api.HTTPError" - } - } - } - } - }, - "/proposal": { - "post": { - "description": "Get headers by block numbers, used for relay proposal", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "summary": "Get headers by block numbers", - "operationId": "get-headers-by-proposal", - "parameters": [ - { - "type": "array", - "items": { - "type": "integer" - }, - "collectionFormat": "multi", - "description": "Eth header numbers", - "name": "numbers", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "supports `[", - "name": "format", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "type": "array", - "items": { - "$ref": "#/definitions/core.GetEthHeaderWithProofJSONResp" - } - } - }, - "headers": { - "Token": { - "type": "string", - "description": "qwerty" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/api.HTTPError" - } - } - } - } - }, - "/receipt/{tx}": { - "get": { - "description": "Get receipt by tx hash, used for cross-chain transfer", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "summary": "Get receipt by tx hash", - "operationId": "get-receipt-by-tx", - "parameters": [ - { - "type": "string", - "description": "tx hash", - "name": "tx", - "in": "path", - "required": true - }, - { - "type": "number", - "description": "last confirm block", - "name": "last", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/core.GetReceiptResp" - } - }, - "headers": { - "Token": { - "type": "string", - "description": "qwerty" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/api.HTTPError" - } - } - } - } - } - }, - "definitions": { - "api.HTTPError": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "example": 400 - }, - "message": { - "type": "string", - "example": "status bad request" - } - } - }, - "core.GetEthHeaderWithProofJSONResp": { - "type": "object", - "properties": { - "eth_header": { - "type": "object", - "$ref": "#/definitions/eth.DarwiniaEthHeaderHexFormat" - }, - "ethash_proof": { - "type": "array", - "items": { - "$ref": "#/definitions/eth.DoubleNodeWithMerkleProof" - } - }, - "mmr_root": { - "type": "string" - } - } - }, - "core.GetReceiptResp": { - "type": "object", - "properties": { - "header": { - "type": "object", - "$ref": "#/definitions/eth.DarwiniaEthHeader" - }, - "mmr_proof": { - "type": "array", - "items": { - "type": "string" - } - }, - "receipt_proof": { - "type": "string" - } - } - }, - "eth.DarwiniaEthHeader": { - "type": "object", - "properties": { - "author": { - "type": "string" - }, - "difficulty": { - "type": "integer" - }, - "extra_data": { - "type": "string" - }, - "gas_limit": { - "type": "integer" - }, - "gas_used": { - "type": "integer" - }, - "hash": { - "type": "string" - }, - "log_bloom": { - "type": "string" - }, - "number": { - "type": "integer" - }, - "parent_hash": { - "type": "string" - }, - "receipts_root": { - "type": "string" - }, - "seal": { - "type": "array", - "items": { - "type": "string" - } - }, - "state_root": { - "type": "string" - }, - "timestamp": { - "type": "integer" - }, - "transactions_root": { - "type": "string" - }, - "uncles_hash": { - "type": "string" - } - } - }, - "eth.DarwiniaEthHeaderHexFormat": { - "type": "object", - "properties": { - "author": { - "type": "string" - }, - "difficulty": { - "type": "string" - }, - "extra_data": { - "type": "string" - }, - "gas_limit": { - "type": "string" - }, - "gas_used": { - "type": "string" - }, - "hash": { - "type": "string" - }, - "log_bloom": { - "type": "string" - }, - "number": { - "type": "string" - }, - "parent_hash": { - "type": "string" - }, - "receipts_root": { - "type": "string" - }, - "seal": { - "type": "array", - "items": { - "type": "string" - } - }, - "state_root": { - "type": "string" - }, - "timestamp": { - "type": "string" - }, - "transactions_root": { - "type": "string" - }, - "uncles_hash": { - "type": "string" - } - } - }, - "eth.DoubleNodeWithMerkleProof": { - "type": "object", - "properties": { - "dag_nodes": { - "type": "array", - "items": { - "type": "string" - } - }, - "proof": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "types.Header": { - "type": "object", - "properties": { - "difficulty": { - "type": "string" - }, - "extraData": { - "type": "array", - "items": { - "type": "integer" - } - }, - "gasLimit": { - "type": "integer" - }, - "gasUsed": { - "type": "integer" - }, - "logsBloom": { - "type": "Bloom" - }, - "miner": { - "type": "string" - }, - "mixHash": { - "type": "string" - }, - "nonce": { - "type": "BlockNonce" - }, - "number": { - "type": "string" - }, - "parentHash": { - "type": "string" - }, - "receiptsRoot": { - "type": "string" - }, - "sha3Uncles": { - "type": "string" - }, - "stateRoot": { - "type": "string" - }, - "timestamp": { - "type": "integer" - }, - "transactionsRoot": { - "type": "string" - } - } - } - }, - "securityDefinitions": { - "ApiKeyAuth": { - "type": "apiKey", - "name": "Authorization", - "in": "header" - }, - "BasicAuth": { - "type": "basic" - }, - "OAuth2AccessCode": { - "type": "oauth2", - "flow": "accessCode", - "authorizationUrl": "https://example.com/oauth/authorize", - "tokenUrl": "https://example.com/oauth/token", - "scopes": { - "admin": " Grants read and write access to administrative information" - } - }, - "OAuth2Application": { - "type": "oauth2", - "flow": "application", - "tokenUrl": "https://example.com/oauth/token", - "scopes": { - "admin": " Grants read and write access to administrative information", - "write": " Grants write access" - } - }, - "OAuth2Implicit": { - "type": "oauth2", - "flow": "implicit", - "authorizationUrl": "https://example.com/oauth/authorize", - "scopes": { - "admin": " Grants read and write access to administrative information", - "write": " Grants write access" - } - }, - "OAuth2Password": { - "type": "oauth2", - "flow": "password", - "tokenUrl": "https://example.com/oauth/token", - "scopes": { - "admin": " Grants read and write access to administrative information", - "read": " Grants read access", - "write": " Grants write access" - } - } - }, - "x-extension-openapi": { - "example": "value on a json format" - } -} \ No newline at end of file diff --git a/api/docs/swagger.yaml b/api/docs/swagger.yaml deleted file mode 100644 index 551b7464..00000000 --- a/api/docs/swagger.yaml +++ /dev/null @@ -1,350 +0,0 @@ -basePath: /api/v1 -definitions: - api.HTTPError: - properties: - code: - example: 400 - type: integer - message: - example: status bad request - type: string - type: object - core.GetEthHeaderWithProofJSONResp: - properties: - eth_header: - $ref: '#/definitions/eth.DarwiniaEthHeaderHexFormat' - type: object - ethash_proof: - items: - $ref: '#/definitions/eth.DoubleNodeWithMerkleProof' - type: array - mmr_root: - type: string - type: object - core.GetReceiptResp: - properties: - header: - $ref: '#/definitions/eth.DarwiniaEthHeader' - type: object - mmr_proof: - items: - type: string - type: array - receipt_proof: - type: string - type: object - eth.DarwiniaEthHeader: - properties: - author: - type: string - difficulty: - type: integer - extra_data: - type: string - gas_limit: - type: integer - gas_used: - type: integer - hash: - type: string - log_bloom: - type: string - number: - type: integer - parent_hash: - type: string - receipts_root: - type: string - seal: - items: - type: string - type: array - state_root: - type: string - timestamp: - type: integer - transactions_root: - type: string - uncles_hash: - type: string - type: object - eth.DarwiniaEthHeaderHexFormat: - properties: - author: - type: string - difficulty: - type: string - extra_data: - type: string - gas_limit: - type: string - gas_used: - type: string - hash: - type: string - log_bloom: - type: string - number: - type: string - parent_hash: - type: string - receipts_root: - type: string - seal: - items: - type: string - type: array - state_root: - type: string - timestamp: - type: string - transactions_root: - type: string - uncles_hash: - type: string - type: object - eth.DoubleNodeWithMerkleProof: - properties: - dag_nodes: - items: - type: string - type: array - proof: - items: - type: string - type: array - type: object - types.Header: - properties: - difficulty: - type: string - extraData: - items: - type: integer - type: array - gasLimit: - type: integer - gasUsed: - type: integer - logsBloom: - type: Bloom - miner: - type: string - mixHash: - type: string - nonce: - type: BlockNonce - number: - type: string - parentHash: - type: string - receiptsRoot: - type: string - sha3Uncles: - type: string - stateRoot: - type: string - timestamp: - type: integer - transactionsRoot: - type: string - type: object -host: localhost:8080 -info: - contact: - email: support@swagger.io - name: API Support - url: http://www.swagger.io/support - description: The shadow service for relayers and verify workers to retrieve header data and generate proof. Shadow will index the data it needs from blockchain nodes, such as Ethereum and Darwinia. - license: - name: Apache 2.0 - url: http://www.apache.org/licenses/LICENSE-2.0.html - termsOfService: http://swagger.io/terms/ - title: Shadow API - version: "1.0" -paths: - /header/{block}: - get: - consumes: - - application/json - description: Get ETH Header by block number or hash - operationId: get-header-by-block - parameters: - - description: Eth header number - in: path - name: block - required: true - type: number - - description: Batch how many blocks - in: query - name: batch - required: true - type: number - - description: supports `[ - in: query - name: format - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - headers: - Token: - description: qwerty - type: string - schema: - $ref: '#/definitions/types.Header' - "400": - description: Bad Request - schema: - $ref: '#/definitions/api.HTTPError' - summary: Get ETH Header by block - /proof/{block}: - get: - consumes: - - application/json - description: Get header with hash proof and mmr roothash - operationId: get-header-with-proof - parameters: - - description: Eth header number or hash - in: path - name: block - required: true - type: string - - description: supports `[ - in: query - name: format - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - headers: - Token: - description: qwerty - type: string - schema: - $ref: '#/definitions/core.GetEthHeaderWithProofJSONResp' - "400": - description: Bad Request - schema: - $ref: '#/definitions/api.HTTPError' - summary: Get header with proof - /proposal: - post: - consumes: - - application/json - description: Get headers by block numbers, used for relay proposal - operationId: get-headers-by-proposal - parameters: - - collectionFormat: multi - description: Eth header numbers - in: query - items: - type: integer - name: numbers - required: true - type: array - - description: supports `[ - in: query - name: format - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - headers: - Token: - description: qwerty - type: string - schema: - items: - items: - $ref: '#/definitions/core.GetEthHeaderWithProofJSONResp' - type: array - type: array - "400": - description: Bad Request - schema: - $ref: '#/definitions/api.HTTPError' - summary: Get headers by block numbers - /receipt/{tx}: - get: - consumes: - - application/json - description: Get receipt by tx hash, used for cross-chain transfer - operationId: get-receipt-by-tx - parameters: - - description: tx hash - in: path - name: tx - required: true - type: string - - description: last confirm block - in: query - name: last - required: true - type: number - produces: - - application/json - responses: - "200": - description: OK - headers: - Token: - description: qwerty - type: string - schema: - items: - $ref: '#/definitions/core.GetReceiptResp' - type: array - "400": - description: Bad Request - schema: - $ref: '#/definitions/api.HTTPError' - summary: Get receipt by tx hash -securityDefinitions: - ApiKeyAuth: - in: header - name: Authorization - type: apiKey - BasicAuth: - type: basic - OAuth2AccessCode: - authorizationUrl: https://example.com/oauth/authorize - flow: accessCode - scopes: - admin: ' Grants read and write access to administrative information' - tokenUrl: https://example.com/oauth/token - type: oauth2 - OAuth2Application: - flow: application - scopes: - admin: ' Grants read and write access to administrative information' - write: ' Grants write access' - tokenUrl: https://example.com/oauth/token - type: oauth2 - OAuth2Implicit: - authorizationUrl: https://example.com/oauth/authorize - flow: implicit - scopes: - admin: ' Grants read and write access to administrative information' - write: ' Grants write access' - type: oauth2 - OAuth2Password: - flow: password - scopes: - admin: ' Grants read and write access to administrative information' - read: ' Grants read access' - write: ' Grants write access' - tokenUrl: https://example.com/oauth/token - type: oauth2 -swagger: "2.0" -x-extension-openapi: - example: value on a json format diff --git a/api/http.go b/api/http.go deleted file mode 100644 index 83eba76c..00000000 --- a/api/http.go +++ /dev/null @@ -1,242 +0,0 @@ -package api - -import ( - "net/http" - "strconv" - "strings" - - "github.com/darwinia-network/shadow/internal/core" - "github.com/darwinia-network/shadow/internal/ffi" - "github.com/darwinia-network/shadow/internal/util" - "github.com/ethereum/go-ethereum/core/types" - "github.com/gin-gonic/gin" -) - -// NewError example -func NewError(ctx *gin.Context, status int, err error) { - er := HTTPError{ - Code: status, - Message: err.Error(), - } - ctx.JSON(status, er) -} - -// HTTPError example -type HTTPError struct { - Code int `json:"code" example:"400"` - Message string `json:"message" example:"status bad request"` -} - -type ShadowHTTP struct { - Shadow *core.Shadow -} - -func NewShadowHTTP(shadow *core.Shadow) (ShadowHTTP, error) { - return ShadowHTTP{ - shadow, - }, nil -} - -// Get Header by hash godoc -// @Summary Get ETH Header by block -// @Description Get ETH Header by block number or hash -// @ID get-header-by-block -// @Accept json -// @Produce json -// @Param block path string true "Eth header number or hash" -// @Success 200 {object} types.Header -// @Header 200 {string} Token "qwerty" -// @Failure 400 {object} HTTPError -// @Router /header/{block} [get] -func (c *ShadowHTTP) GetHeader(ctx *gin.Context) { - var header types.Header - block, err := util.NumberOrString(ctx.Param("block")) - if err != nil { - NewError(ctx, http.StatusBadRequest, err) - return - } - - header, err = c.Shadow.GetHeader(core.Ethereum, block) - if err != nil { - NewError(ctx, http.StatusBadRequest, err) - return - } - - ctx.JSON(http.StatusOK, header) -} - -// Get Header by hash godoc -// @Summary Get ETH Header by block -// @Description Get ETH Header by block number or hash -// @ID get-header-by-block -// @Accept json -// @Produce json -// @Param block path number true "Eth header number" -// @Param batch query number true "Batch how many blocks" -// @Param format query string true "supports `["raw", "json", "codec"]`" -// @Success 200 {object} types.Header -// @Header 200 {string} Token "qwerty" -// @Failure 400 {object} HTTPError -// @Router /header/{block} [get] -func (c *ShadowHTTP) BatchHeaders(ctx *gin.Context) { - blockStr := ctx.Param("block") - block, err := strconv.ParseUint(blockStr, 10, 64) - if err != nil { - NewError(ctx, http.StatusBadRequest, err) - return - } - - batchStr := ctx.DefaultQuery("batch", "1") - batch, err := strconv.ParseInt(batchStr, 10, 64) - if err != nil { - NewError(ctx, http.StatusBadRequest, err) - return - } - - rawHeaders, err := c.Shadow.BatchHeaderWithProof(block, int(batch)) - if err != nil { - NewError(ctx, http.StatusBadRequest, err) - return - } - - /// Formats response - var resp []interface{} - format := ctx.DefaultQuery("format", "raw") - if format == "json" { - for _, h := range rawHeaders { - resp = append(resp, h.IntoJSON()) - } - } else if format == "codec" { - for _, h := range rawHeaders { - resp = append(resp, h.IntoCodec()) - } - } else { - for _, h := range rawHeaders { - resp = append(resp, h) - } - } - - ctx.JSON(http.StatusOK, resp) -} - -// Get header with proof godoc -// @Summary Get header with proof -// @Description Get header with hash proof and mmr roothash -// @ID get-header-with-proof -// @Accept json -// @Produce json -// @Param block path string true "Eth header number or hash" -// @Param format query string true "supports `["raw", "json", "codec"]`" -// @Success 200 {object} core.GetEthHeaderWithProofJSONResp -// @Header 200 {string} Token "qwerty" -// @Failure 400 {object} HTTPError -// @Router /proof/{block} [get] -func (c *ShadowHTTP) GetProof(ctx *gin.Context) { - var resp interface{} - block, err := util.NumberOrString(ctx.Param("block")) - if err != nil { - NewError(ctx, http.StatusBadRequest, err) - return - } - - rawResp, err := c.Shadow.GetHeaderWithProof( - core.Ethereum, - block, - ) - - format := ctx.DefaultQuery("format", "json") - if format == "json" { - resp = rawResp.IntoJSON() - } else if format == "codec" { - resp = rawResp.IntoCodec() - } else { - resp = rawResp - } - - if err != nil { - NewError(ctx, http.StatusBadRequest, err) - return - } - - ctx.JSON(http.StatusOK, resp) -} - -// Get receipt by hash -// @Summary Get receipt by tx hash -// @Description Get receipt by tx hash, used for cross-chain transfer -// @ID get-receipt-by-tx -// @Accept json -// @Produce json -// @Param tx path string true "tx hash" -// @Param last query number true "last confirm block" -// @Success 200 {array} core.GetReceiptResp -// @Header 200 {string} Token "qwerty" -// @Failure 400 {object} HTTPError -// @Router /receipt/{tx} [get] -func (c *ShadowHTTP) GetReceipt(ctx *gin.Context) { - receipt, err := c.Shadow.GetReceipt(ctx.Param("tx")) - if err != nil { - NewError(ctx, http.StatusBadRequest, err) - return - } - - last := ctx.DefaultQuery("last", "0") - member, err := strconv.ParseUint(last, 10, 64) - if err != nil { - NewError(ctx, http.StatusBadRequest, err) - return - } - - receipt.MMRProof = strings.Split(ffi.ProofLeaves(receipt.Header.Number, member), ",") - ctx.JSON(http.StatusOK, receipt) -} - -// Get headers by proposal -// @Summary Get headers by block numbers -// @Description Get headers by block numbers, used for relay proposal -// @ID get-headers-by-proposal -// @Accept json -// @Produce json -// @Param numbers query []uint64 true "Eth header numbers" -// @Param format query string true "supports `["raw", "json", "codec"]`" -// @Success 200 {array} []core.GetEthHeaderWithProofJSONResp -// @Header 200 {string} Token "qwerty" -// @Failure 400 {object} HTTPError -// @Router /proposal [post] -func (c *ShadowHTTP) Proposal(ctx *gin.Context) { - var ( - err error - params ProposalParams - proposalHeaders []interface{} - ) - err = ctx.BindJSON(¶ms) - if err != nil { - NewError(ctx, http.StatusBadRequest, err) - return - } - - headers, err := c.Shadow.GetProposalHeaders(params.Members) - if err != nil { - NewError(ctx, http.StatusBadRequest, err) - return - } - - // Construct headers - for _, h := range headers { - if params.Format == "codec" { - proposalHeaders = append( - proposalHeaders, - h.IntoProposalCodec(params.LastLeaf), - ) - } else { - proposalHeaders = append( - proposalHeaders, - h.IntoProposal(params.LastLeaf), - ) - } - } - - ctx.JSON(http.StatusOK, core.ProposalResp{ - Headers: proposalHeaders, - }) -} diff --git a/api/types.go b/api/types.go deleted file mode 100644 index 021978f9..00000000 --- a/api/types.go +++ /dev/null @@ -1,7 +0,0 @@ -package api - -type ProposalParams struct { - Members []uint64 `json:"members"` - LastLeaf uint64 `json:"last_leaf"` - Format string `json:"format"` -} diff --git a/bin/main.go b/bin/main.go deleted file mode 100644 index 65835b60..00000000 --- a/bin/main.go +++ /dev/null @@ -1,10 +0,0 @@ -package main - -import ( - "github.com/darwinia-network/shadow/cmd" - "github.com/darwinia-network/shadow/internal/util" -) - -func main() { - util.Assert(cmd.Execute()) -} diff --git a/build.rs b/build.rs new file mode 100644 index 00000000..2f30ea77 --- /dev/null +++ b/build.rs @@ -0,0 +1,32 @@ +use std::process::Command; + +fn main() { + let os = Command::new("uname").output().unwrap(); + let ext = match String::from_utf8_lossy(os.stdout.as_slice()) + .into_owned() + .trim_end() + .as_ref() + { + "Darwin" => "dylib", + _ => "so", + }; + + let profile = match std::env::var("PROFILE").unwrap().as_str() { + "release" => "release", + _ => "debug", + }; + + let lib = format!("target/{}/libeth.{}", profile, ext); + Command::new("go") + .args(&[ + "build", + "-o", + &lib, + "-buildmode=c-shared", + "pkg/internal/ffi/mod.go", + ]) + .status() + .unwrap(); + + println!(r"cargo:rustc-link-search=target/debug"); +} diff --git a/cmd/epoch.go b/cmd/epoch.go deleted file mode 100644 index e4c42b92..00000000 --- a/cmd/epoch.go +++ /dev/null @@ -1,29 +0,0 @@ -package cmd - -import ( - "fmt" - "strconv" - - "github.com/darwinia-network/shadow/internal/util" - "github.com/darwinia-network/shadow/pkg/ethashproof" - "github.com/spf13/cobra" -) - -var cmdEpoch = &cobra.Command{ - Use: "epoch [number]", - Short: "Calculate epoch cache", - Long: "This will take a long time", - Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - // parse epoch - epoch, err := strconv.ParseUint(args[0], 10, 64) - util.Assert(err) - - // calculating - root, err := ethashproof.CalculateDatasetMerkleRoot(epoch, true) - util.Assert(err) - - // output - fmt.Printf("Root: %s\n", root.Hex()) - }, -} diff --git a/cmd/header.go b/cmd/header.go deleted file mode 100644 index cc7f9f43..00000000 --- a/cmd/header.go +++ /dev/null @@ -1,45 +0,0 @@ -package cmd - -import ( - "encoding/json" - "fmt" - - "github.com/darwinia-network/shadow/internal/core" - "github.com/darwinia-network/shadow/internal/util" - "github.com/spf13/cobra" -) - -func init() { - cmdHeader.PersistentFlags().BoolVarP( - &VERBOSE, - "verbose", - "v", - false, - "Enable all shadow logs", - ) -} - -var cmdHeader = &cobra.Command{ - Use: "header [number]", - Short: "Get eth block by number", - Long: "This command will use the config at `~/.darwinia/config.json`", - Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - verboseCheck() - - // new shadow service - shadow, err := core.NewShadow() - util.Assert(err) - - header, err := shadow.GetHeader( - core.Ethereum, - args[0], - ) - util.Assert(err) - - // Get the header string - js, err := json.Marshal(header) - util.Assert(err) - fmt.Printf("%v\n", string(js)) - }, -} diff --git a/cmd/import.go b/cmd/import.go deleted file mode 100644 index 97a7b1e5..00000000 --- a/cmd/import.go +++ /dev/null @@ -1,91 +0,0 @@ -package cmd - -// -// import ( -// "fmt" -// "os" -// "runtime" -// "strings" -// "time" -// -// "github.com/darwinia-network/shadow/internal" -// "github.com/darwinia-network/shadow/internal/core" -// "github.com/darwinia-network/shadow/internal/log" -// "github.com/darwinia-network/shadow/internal/util" -// "github.com/spf13/cobra" -// ) -// -// func init() { -// cmdImport.PersistentFlags().BoolVarP( -// &VERBOSE, -// "verbose", -// "v", -// false, -// "Enable all shadow logs", -// ) -// -// cmdImport.PersistentFlags().Uint32VarP( -// &LIMITS, -// "limits", -// "l", -// 1000000, -// "block limits", -// ) -// -// cmdImport.PersistentFlags().Int64VarP( -// &CHANNELS, -// "channels", -// "r", -// 300, -// "goroutine channel conunts", -// ) -// } -// -// var cmdImport = &cobra.Command{ -// Use: "import ", -// Short: "Import Shadow blocks", -// Long: "Import Shadow blocks from leveldb", -// Args: cobra.MinimumNArgs(1), -// Run: func(cmd *cobra.Command, args []string) { -// verboseCheck() -// runtime.GOMAXPROCS(runtime.NumCPU()) -// ch := make(chan int, CHANNELS) -// -// // Set env -// os.Setenv(internal.GETH_DATADIR, args[0]) -// shadow, err := core.NewShadow() -// util.Assert(err) -// -// // Fetch headers -// for b := uint64(0); b < uint64(LIMITS); b++ { -// defer func() { _ = recover() }() -// ch <- 1 -// go importBlock(&shadow, b, ch) -// } -// }, -// } -// -// func importBlock(shadow *core.Shadow, block uint64, ch chan int) { -// header := shadow.Geth.Header(block) -// defer func() { _ = recover() }() -// if util.IsEmpty(header) { -// log.Warn("fetch block %v from leveldb faield, sleep 10s", block) -// time.Sleep(time.Second * 10) -// } -// -// _, err := core.CreateEthHeaderCache(shadow.DB, header) -// if err != nil { -// util.Assert(err) -// } -// -// bs := fmt.Sprintf( -// "%s%v", -// strings.Repeat( -// " ", -// len(fmt.Sprintf("%v", LIMITS))-len(fmt.Sprintf("%v", block)), -// ), -// block, -// ) -// log.Info("Imported block %v/%v", bs, LIMITS) -// <-ch -// } diff --git a/cmd/mmr.go b/cmd/mmr.go deleted file mode 100644 index 1d619dd0..00000000 --- a/cmd/mmr.go +++ /dev/null @@ -1 +0,0 @@ -package cmd diff --git a/cmd/proof.go b/cmd/proof.go deleted file mode 100644 index c7fd320c..00000000 --- a/cmd/proof.go +++ /dev/null @@ -1,58 +0,0 @@ -package cmd - -import ( - "encoding/json" - "fmt" - - "github.com/darwinia-network/shadow/internal/core" - "github.com/darwinia-network/shadow/internal/util" - "github.com/spf13/cobra" -) - -func init() { - cmdProof.PersistentFlags().StringVarP( - &PROOF_FORMAT, - "format", - "f", - "json", - "set port of http rpc server", - ) - - cmdProof.PersistentFlags().BoolVarP( - &VERBOSE, - "verbose", - "v", - false, - "Enable all shadow logs", - ) -} - -var cmdProof = &cobra.Command{ - Use: "proof [number]", - Short: "Proof the block by number", - Long: "DANGEROUS! This cmd will fill up your screen!", - Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - verboseCheck() - - // new shadow service - shadow, err := core.NewShadow() - util.Assert(err) - - proof, err := shadow.GetHeaderWithProof( - core.Ethereum, - args[0], - ) - util.Assert(err) - - var ret interface{} = proof - if PROOF_FORMAT == "codec" { - ret = proof.IntoCodec() - } - - // toJSON - js, err := json.Marshal(ret) - util.Assert(err) - fmt.Printf("%s\n", js) - }, -} diff --git a/cmd/receipt.go b/cmd/receipt.go deleted file mode 100644 index ace34a02..00000000 --- a/cmd/receipt.go +++ /dev/null @@ -1,29 +0,0 @@ -package cmd - -import ( - "encoding/json" - "fmt" - - "github.com/darwinia-network/shadow/internal/core" - "github.com/darwinia-network/shadow/internal/util" - "github.com/spf13/cobra" -) - -var cmdReceipt = &cobra.Command{ - Use: "receipt [tx]", - Short: "Get receipt by tx hash", - Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - shadow, err := core.NewShadow() - util.Assert(err) - - receipt, err := shadow.GetReceipt(args[0]) - util.Assert(err) - - // output receipt - js, err := json.Marshal(receipt) - util.Assert(err) - - fmt.Printf("%s\n", js) - }, -} diff --git a/cmd/root.go b/cmd/root.go deleted file mode 100644 index 7bacdfb8..00000000 --- a/cmd/root.go +++ /dev/null @@ -1,60 +0,0 @@ -package cmd - -import ( - "github.com/spf13/cobra" - "os" -) - -var ( - rootCmd = &cobra.Command{ - Use: "shadow", - Short: "Darwinia shadow service", - Long: `The way to Go`, - } - FETCH bool - VERBOSE bool - HTTP string - PROOF_FORMAT string - PATH string - NAME string - MMR bool - CHANNELS int64 - LIMITS uint32 - PERTX uint64 - CHECK bool - GETH_DATADIR string - NOFETCH bool - NOAPI bool -) - -const ( - // Rust log env - GO_LOG = "GO_LOG" - // Rust log env - RUST_LOG = "RUST_LOG" -) - -// Init commands to dargo -func init() { - rootCmd.AddCommand( - cmdEpoch, - cmdHeader, - cmdProof, - cmdReceipt, - cmdRun, - cmdVersion, - ) -} - -/// Enable all logs -func verboseCheck() { - if VERBOSE { - os.Setenv(GO_LOG, "ALL") - os.Setenv(RUST_LOG, "mmr") - } -} - -// Execute the command -func Execute() error { - return rootCmd.Execute() -} diff --git a/cmd/run.go b/cmd/run.go deleted file mode 100644 index 09695013..00000000 --- a/cmd/run.go +++ /dev/null @@ -1,161 +0,0 @@ -package cmd - -import ( - "runtime" - "sync" - "time" - - "github.com/darwinia-network/shadow/api" - "github.com/darwinia-network/shadow/internal/core" - "github.com/darwinia-network/shadow/internal/ffi" - "github.com/darwinia-network/shadow/internal/log" - "github.com/darwinia-network/shadow/internal/util" - "github.com/spf13/cobra" -) - -func init() { - cmdRun.PersistentFlags().Uint32VarP( - &LIMITS, - "limits", - "l", - 300, - "handle blocks per second", - ) - - cmdRun.PersistentFlags().Int64VarP( - &CHANNELS, - "channels", - "r", - 10, - "goroutine channel conunts", - ) - - cmdRun.PersistentFlags().BoolVarP( - &NOFETCH, - "no-fetch", - "", - false, - "doesn't fetch blocks", - ) - - cmdRun.PersistentFlags().BoolVarP( - &NOAPI, - "no-api", - "", - false, - "doesn't start api server", - ) - - cmdRun.PersistentFlags().BoolVarP( - &CHECK, - "check", - "c", - false, - "fetch headers from block 0, check all blocks exists", - ) - - cmdRun.PersistentFlags().BoolVarP( - &MMR, - "mmr", - "m", - false, - "trigger mmr service", - ) - - cmdRun.PersistentFlags().BoolVarP( - &VERBOSE, - "verbose", - "v", - false, - "Enable all shadow logs", - ) - - cmdRun.PersistentFlags().StringVar( - &HTTP, - "http", - "3000", - "set port of http api server", - ) -} - -const ( - GIN_MODE = "GIN_MODE" -) - -func fetchRoutine(shadow *core.Shadow, ptr uint64, mutex *sync.Mutex) { - mutex.Lock() - _, err := core.FetchHeaderCache(shadow, ptr) - for err != nil { - log.Warn("fetch header %v failed: %v, refetching after 10s...", ptr, err) - time.Sleep(10 * time.Second) - _, err = core.FetchHeaderCache(shadow, ptr) - } - mutex.Unlock() -} - -func fetch(shadow *core.Shadow, channels chan struct{}) { - var ( - base uint64 = shadow.Config.Genesis - mutex *sync.Mutex = &sync.Mutex{} - ) - if !CHECK { - count := core.CountCache(shadow.DB) - if count == 0 { - base = count - } else { - base = count - 1 - } - log.Info("current ethereum block height: %v", base) - } - - gap := 1 * time.Second / time.Duration(int64(LIMITS)) - for ptr := base; ; ptr++ { - channels <- struct{}{} - fetchRoutine(shadow, ptr, mutex) - time.Sleep(gap) - <-channels - } -} - -var cmdRun = &cobra.Command{ - Use: "run", - Short: "Start shadow service", - Long: "The main command of shadow service, lots of available flags", - Args: cobra.MinimumNArgs(0), - Run: func(cmd *cobra.Command, _ []string) { - verboseCheck() - runtime.GOMAXPROCS(3) - - // Generate Shadow - shadow, err := core.NewShadow() - util.Assert(err) - - // Remove all locks - err = shadow.Config.RemoveAllLocks() - util.Assert(err) - - funcs := []func(){} - - // append swagger - if !NOAPI { - funcs = append(funcs, func() { - log.Info("Shadow HTTP service start at %s", HTTP) - api.Swagger(&shadow, HTTP) - }) - } - - // if need fetch - if !NOFETCH { - channels := make(chan struct{}, CHANNELS) - funcs = append(funcs, func() { fetch(&shadow, channels) }) - } - - // if trigger MMR - if MMR { - funcs = append(funcs, func() { ffi.RunMMR(CHANNELS, LIMITS) }) - } - - // run parallelize - util.Parallelize(funcs) - }, -} diff --git a/cmd/version.go b/cmd/version.go deleted file mode 100644 index 51b74436..00000000 --- a/cmd/version.go +++ /dev/null @@ -1,15 +0,0 @@ -package cmd - -import ( - "fmt" - - "github.com/spf13/cobra" -) - -var cmdVersion = &cobra.Command{ - Use: "version", - Short: "Print the version number of shadow", - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("shadow 0.1.9") - }, -} diff --git a/examples/doctor.rs b/examples/doctor.rs index 36ba6d79..3b6a8b37 100644 --- a/examples/doctor.rs +++ b/examples/doctor.rs @@ -1,6 +1,6 @@ //! Mock the uncle block use cmmr::{leaf_index_to_mmr_size, MMR}; -use mmr::{ +use shadow::{ hash::{MergeHash, H256}, pool, store::Store, @@ -10,7 +10,7 @@ fn main() { let conn = pool::conn(None); let store = Store::with(conn); - let mmr = MMR::<_, MergeHash, _>::new(leaf_index_to_mmr_size(1), store); + let mmr = MMR::<_, MergeHash, _>::new(leaf_index_to_mmr_size(1), &store); let leaf_root = mmr.get_root().expect("get root failed"); // let proofs = mmr diff --git a/examples/header.rs b/examples/header.rs new file mode 100644 index 00000000..377426ab --- /dev/null +++ b/examples/header.rs @@ -0,0 +1,11 @@ +use shadow::chain::eth::{EthHeader, EthHeaderRPCResp}; + +fn main() { + let client = reqwest::Client::new(); + let header = async_std::task::block_on(EthHeaderRPCResp::get(&client, 1)) + .unwrap() + .result; + println!("{:?}", &header); + println!("{:?}", i64::from_str_radix("1f", 16)); + println!("{:?}", Into::::into(header)); +} diff --git a/examples/proof.rs b/examples/proof.rs new file mode 100644 index 00000000..e3d98495 --- /dev/null +++ b/examples/proof.rs @@ -0,0 +1,10 @@ +use std::{ffi::CStr, os::raw::c_char}; + +#[link(name = "eth")] +extern "C" { + fn Proof(input: libc::c_uint) -> *const c_char; +} + +fn main() { + println!("{:?}", unsafe { CStr::from_ptr(Proof(1)) }); +} diff --git a/examples/receipt.rs b/examples/receipt.rs new file mode 100644 index 00000000..4bd3ee16 --- /dev/null +++ b/examples/receipt.rs @@ -0,0 +1,38 @@ +use std::{ + ffi::{CStr, CString}, + os::raw::c_char, +}; + +const TX: &str = "0x3b82a55f5e752c23359d5c3c4c3360455ce0e485ed37e1faabe9ea10d5db3e7a"; + +#[repr(C)] +struct GoString { + a: *const c_char, + b: i64, +} + +#[repr(C)] +struct GoTuple { + proof: *const c_char, + hash: *const c_char, +} + +#[link(name = "eth")] +extern "C" { + fn Receipt(input: GoString) -> GoTuple; +} + +fn main() { + let c_tx = CString::new(TX).expect("CString::new failed"); + let ptr = c_tx.as_ptr(); + let tx = GoString { + a: ptr, + b: c_tx.as_bytes().len() as i64, + }; + + unsafe { + let gt = Receipt(tx); + println!("{:?}", CStr::from_ptr(gt.proof)); + println!("{:?}", CStr::from_ptr(gt.hash)); + } +} diff --git a/examples/runner.rs b/examples/runner.rs index 219a09d1..effebad0 100644 --- a/examples/runner.rs +++ b/examples/runner.rs @@ -1,8 +1,8 @@ -use mmr::Runner; +use shadow::Runner; fn main() { env_logger::init(); - let conn = mmr::pool::conn(None); + let conn = shadow::pool::conn(None); let mut runner = Runner::with(conn); - runner.start(1, 500).unwrap(); + async_std::task::block_on(runner.start()).unwrap(); } diff --git a/examples/uncle.rs b/examples/uncle.rs index 9cb87f84..780e31e2 100644 --- a/examples/uncle.rs +++ b/examples/uncle.rs @@ -1,6 +1,6 @@ //! Mock the uncle block use cmmr::MMR; -use mmr::{ +use shadow::{ hash::{MergeHash, H256}, pool, store::Store, @@ -37,7 +37,7 @@ fn main() { let db = env::temp_dir().join("test_mmr_proof.db"); let conn = pool::conn(Some(db)); let store = Store::with(conn); - let mut mmr = MMR::<_, MergeHash, _>::new(0, store); + let mut mmr = MMR::<_, MergeHash, _>::new(0, &store); let mut roots: Vec = vec![]; let pos: Vec = (0..20) .map(|h| { diff --git a/go.mod b/go.mod index d3de4968..299e6163 100644 --- a/go.mod +++ b/go.mod @@ -3,26 +3,24 @@ module github.com/darwinia-network/shadow go 1.14 require ( - github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/deckarep/golang-set v1.7.1 github.com/edsrzf/mmap-go v1.0.0 github.com/ethereum/go-ethereum v1.9.15 github.com/fatih/color v1.3.0 - github.com/gin-gonic/gin v1.6.3 + github.com/go-logfmt/logfmt v0.4.0 // indirect + github.com/golang/protobuf v1.3.3 // indirect github.com/hashicorp/golang-lru v0.5.4 github.com/huandu/xstrings v1.3.2 - github.com/jinzhu/gorm v1.9.14 + github.com/mattn/go-isatty v0.0.12 // indirect github.com/mitchellh/mapstructure v1.3.2 github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6 github.com/panjf2000/ants v1.2.0 + github.com/prometheus/tsdb v0.7.1 // indirect github.com/regcostajr/go-web3 v0.0.0-20180609031449-555e83b623dd github.com/shopspring/decimal v1.2.0 - github.com/spf13/cobra v1.0.0 - github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 - github.com/swaggo/gin-swagger v1.2.0 - github.com/swaggo/swag v1.6.7 github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 // indirect github.com/ttacon/libphonenumber v1.1.0 github.com/tuvistavie/securerandom v0.0.0-20140719024926-15512123a948 golang.org/x/crypto v0.0.0-20200707235045-ab33eee955e0 + gopkg.in/yaml.v2 v2.2.8 // indirect ) diff --git a/go.sum b/go.sum index c9764b2b..7f350a29 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,3 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= @@ -14,32 +13,19 @@ github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6L github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= -github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= -github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VictoriaMetrics/fastcache v1.5.7 h1:4y6y0G8PRzszQUYIQHHssv/jgPHAb5qQuuDNdCbyAgw= github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= -github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847 h1:rtI0fD4oG/8eVokGVPYJEW1F88p1ZNgXiEIs9thEE4A= github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6 h1:Eey/GGQ/E5Xp1P2Lyx1qj007hLZfbi0+CoVeJruGCtI= github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= @@ -48,24 +34,14 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= -github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= -github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= @@ -74,8 +50,6 @@ github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87/go.mod h1:Mw6PkjjMXWbT github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= -github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/ethereum/go-ethereum v1.9.15 h1:wrWl+QrtutRUJ9LZXdUqBoGoo2b1tOCYRDrAOQhCY3A= github.com/ethereum/go-ethereum v1.9.15/go.mod h1:slT8bPPRhXsyNTwHQxrOnjuTZ1sDXRajW11EkJ84QJ0= github.com/fatih/color v1.3.0 h1:YehCCcyeQ6Km0D6+IapqPinWBK6y+0eB5umvZXK9WPs= @@ -86,19 +60,6 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc= -github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= -github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= -github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y= -github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ= -github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -106,66 +67,23 @@ github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80n github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= -github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo= -github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= -github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= -github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c h1:zqAKixg3cTcIasAMJV+EcfVbWwLpOZ7LeoWJvcuD/5Q= github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989 h1:giknQ4mEuDFmmHSrGcbargOuLHQGtywqo4mheITex54= github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= @@ -173,82 +91,35 @@ github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jinzhu/gorm v1.9.14 h1:Kg3ShyTPcM6nzVo148fRrcMO6MNKuqtOUwnzqMgVniM= -github.com/jinzhu/gorm v1.9.14/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= -github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 h1:I/yrLt2WilKxlQKCM52clh5rGzTKpVctGT1lH4Dc8Jw= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= -github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-colorable v0.1.0 h1:v2XXALHHh6zHfYTJ+cSkwtyffnaOyR1MXaA91mTrb8o= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035 h1:USWjF42jDCSEeikX/G1g40ZWnsPXN5WkZ4jMHZWyBK4= github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA= -github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg= github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -267,8 +138,6 @@ github.com/panjf2000/ants v1.2.0 h1:pMQ1/XpSgnWx3ro4y1xr/uA3jXUsTuAaU3Dm0JjwggE= github.com/panjf2000/ants v1.2.0/go.mod h1:AaACblRPzq35m1g3enqYcxspbbiOJJYaxU2wMpm1cXY= github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222 h1:goeTyGkArOZIVOMA0dQbyuPWGNQJZGPwPu/QS9GlpnA= github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= -github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -277,13 +146,9 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= @@ -291,35 +156,19 @@ github.com/regcostajr/go-web3 v0.0.0-20180609031449-555e83b623dd h1:RzU+Dh0rt2M5 github.com/regcostajr/go-web3 v0.0.0-20180609031449-555e83b623dd/go.mod h1:yuc1rIPDUnwvT7Mtp5ACumMGoCp0p7FtGhwLjPhBE68= github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00 h1:8DPul/X0IT/1TNMIxoKLwdemEOBBHDC/K4EB16Cw5WE= github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521 h1:3hxavr+IHMsQBrYUPQM5v0CgENFktkkbg1sfpgM3h20= github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/shirou/gopsutil v2.20.5-0.20200531151128-663af789c085+incompatible h1:+gAR1bMhuoQnZMTWFIvp7ukynULPsteLzG+siZKLtD8= github.com/shirou/gopsutil v2.20.5-0.20200531151128-663af789c085+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1vJb5vwEjIp5kBj/eu99p/bl0Ay2goiPe5xE= @@ -327,22 +176,12 @@ github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8 github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM= github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 h1:PyYN9JH5jY9j6av01SpfRMb+1DWg/i3MbGOKPxJ2wjM= -github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= -github.com/swaggo/gin-swagger v1.2.0 h1:YskZXEiv51fjOMTsXrOetAjrMDfFaXD79PEoQBOe2W0= -github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI= -github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= -github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s= -github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 h1:5u+EJUQiosu3JFX0XS0qTf5FznsMOzTjGqavBGuCbo0= github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2/go.mod h1:4kyMkleCiLkgY6z8gK5BkI01ChBtxR0ro3I1ZDcGM3w= github.com/ttacon/libphonenumber v1.1.0 h1:tC6kE4t8UI4OqQVQjW5q8gSWhG2wnY5moEpSEORdYm4= @@ -351,74 +190,26 @@ github.com/tuvistavie/securerandom v0.0.0-20140719024926-15512123a948 h1:yL0l/u2 github.com/tuvistavie/securerandom v0.0.0-20140719024926-15512123a948/go.mod h1:a06d/M1pxWi51qiSrfGMHaEydtuXT06nha8N2aNQuXk= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go v1.1.5-pre h1:jyJKFOSEbdOc2HODrf2qcCkYOdq7zzXqA9bhW5oV4fM= -github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v1.1.5-pre h1:5YV9PsFAN+ndcCtTM7s60no7nY7eTG3LPtxhSwuxzCs= -github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k= -github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk= github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 h1:QmwruyY+bKbDDL0BaglrbZABEali68eoMFhTZpCjYVA= golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200707235045-ab33eee955e0 h1:eIYIE7EC5/Wv5Kbz8bJPaq+TN3kq3W8S+LSm62vM0DY= golang.org/x/crypto v0.0.0-20200707235045-ab33eee955e0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 h1:Jcxah/M+oLZ/R4/z5RzfPzGbPXnVDPkEDtf2JnuxN+U= golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -427,41 +218,23 @@ golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59 h1:QjA/9ArTfVTLfEhClDCG7SGrZkZixxWpwNCDiwJfh88= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= -gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ= -gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200603215123-a4a8cb9d2cbc h1:17cdygvFw3DEyNMh81Bk687W74d5pcC5qEKQICv9N6g= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200603215123-a4a8cb9d2cbc/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/core/cache.go b/internal/core/cache.go deleted file mode 100644 index 96742684..00000000 --- a/internal/core/cache.go +++ /dev/null @@ -1,201 +0,0 @@ -package core - -import ( - "encoding/json" - "fmt" - "os" - "os/user" - "path" - "path/filepath" - - "github.com/darwinia-network/shadow/internal" - "github.com/darwinia-network/shadow/internal/eth" - "github.com/darwinia-network/shadow/internal/log" - "github.com/darwinia-network/shadow/internal/util" - "github.com/ethereum/go-ethereum/core/types" - "github.com/jinzhu/gorm" - _ "github.com/jinzhu/gorm/dialects/sqlite" -) - -// Same directory as `darwinia.js` -const RELATIVE_DB_PATH = ".darwinia/cache/shadow.db" - -// Connect to cache -func ConnectDb() (*gorm.DB, error) { - usr, err := user.Current() - if err != nil { - log.Error("Can not find current os user") - } - - // Check path exists - cachePath := path.Join(usr.HomeDir, path.Dir(RELATIVE_DB_PATH)) - if _, err = os.Stat(cachePath); os.IsNotExist(err) { - err = os.MkdirAll(cachePath, 0700) - if err != nil { - log.Error("Can not create cache folder at %s", cachePath) - } - } - - log.Info("Connecting database ~/%v...", cachePath) - realDBPath := filepath.Join(usr.HomeDir, RELATIVE_DB_PATH) - db, err := gorm.Open("sqlite3", fmt.Sprintf( - "file:%s?cache=shared&mode=rwc&_journal_mode=WAL", - realDBPath, - )) - - if err != nil { - return db, err - } - - // Setings - db.DB().SetMaxOpenConns(1) - - // bootstrap sqlite3 - db.AutoMigrate(&EthHeaderWithProofCache{}) - return db, err -} - -func CountCache(db *gorm.DB) uint64 { - var count uint64 - db.Model(&EthHeaderWithProofCache{}).Count(&count) - return count -} - -func FetchHeader(shadow *Shadow, block interface{}) ( - header types.Header, - err error, -) { - num, err := shadow.checkGenesis(shadow.Config.Genesis, block) - if err != nil { - return - } - - log.Trace("Request block %v ...", num) - header, err = eth.Header(num, shadow.Config.Api) - if err != nil { - return - } - - _, err = CreateEthHeaderCache(shadow.DB, &header) - return -} - -func FetchHeaderCache(shadow *Shadow, block interface{}) ( - cache EthHeaderWithProofCache, - err error, -) { - var header types.Header - num, err := shadow.checkGenesis(shadow.Config.Genesis, block) - if err != nil { - return - } - - shadow.DB.Raw(SelectHeader(num)).Scan(&cache) - if !util.IsEmpty(cache.Header) { - log.Trace("Block %v exists in shadowdb...", block) - return - } - - log.Trace("Requesting block %v...", block) - header, err = eth.Header(num, shadow.Config.Api) - if err != nil { - return - } - - cache, err = CreateEthHeaderCache(shadow.DB, &header) - return -} - -func CreateEthHeaderCache( - db *gorm.DB, - header *types.Header, -) ( - cache EthHeaderWithProofCache, - err error, -) { - if util.IsEmpty(header) { - err = fmt.Errorf("empty ethereum header") - return - } - - dh, err := eth.IntoDarwiniaEthHeader(header) - if err != nil { - log.Error(err.Error()) - return - } - - hstr, err := dh.ToString() - if err != nil { - log.Error(err.Error()) - return - } - - cache = EthHeaderWithProofCache{ - Hash: header.Hash().Hex(), - Number: header.Number.Uint64(), - Header: hstr, - } - - if err = db.Exec(UpsertHeaderSQL(&cache)).Error; err != nil { - return - } - - return -} - -func CreateProofCache( - shadow *Shadow, - cache *EthHeaderWithProofCache, - header *types.Header, -) error { - // Proof header - proof, err := eth.Proof(header, shadow.Config) - if err != nil { - return err - } - - proofBytes, err := json.Marshal(proof.Format()) - if err != nil { - return err - } - - cache.Proof = string(proofBytes) - err = shadow.DB.Model(&cache).Where( - "number = ?", cache.Number, - ).Updates(EthHeaderWithProofCache{ - Proof: cache.Proof, - Root: cache.Root, - }).Error - - if err != nil { - return err - } - - // Remove proof lock - err = shadow.Config.RemoveLock(internal.PROOF_LOCK) - if err != nil { - return err - } - - return nil -} - -func IndexHeaderFromDB( - db *gorm.DB, - cache *EthHeaderWithProofCache, -) (interface{}, error) { - var ( - err error - block interface{} - ) - - if !util.IsEmpty(cache.Number) || cache.Number == 0 { - block = cache.Number - err = db.Where("number = ?", cache.Number).Take(&cache).Error - } else if !util.IsEmpty(cache.Hash) { - block = cache.Hash - err = db.Where("hash = ?", cache.Hash).Take(&cache).Error - } - - return block, err -} diff --git a/internal/core/enum.go b/internal/core/enum.go deleted file mode 100644 index 09e0d31c..00000000 --- a/internal/core/enum.go +++ /dev/null @@ -1,28 +0,0 @@ -package core - -// chain -type Chain string - -const ( - Ethereum Chain = "Ethereum" -) - -// proof -type ProofFormat string - -const ( - JsonFormat ProofFormat = "json" - ScaleFormat ProofFormat = "scale" - RawFormat ProofFormat = "raw" -) - -func (f *ProofFormat) From(s string) ProofFormat { - switch s { - case "json": - return JsonFormat - case "scale": - return ScaleFormat - default: - return RawFormat - } -} diff --git a/internal/core/scale.go b/internal/core/scale.go deleted file mode 100644 index 978dbdd9..00000000 --- a/internal/core/scale.go +++ /dev/null @@ -1,93 +0,0 @@ -package core - -import ( - "encoding/binary" - "encoding/hex" - "strings" - - "github.com/darwinia-network/shadow/internal/eth" -) - -func lenToBytes(b []uint8, len int) ([]uint8, int) { - if len < 255 { - b = append(b, uint8(len)) - len = 0 - return b, len - } - - b = append(b, uint8(len/0xff)) - len = len % 0xff - return lenToBytes(b, len) -} - -func LenToHex(len int) string { - b, _ := lenToBytes([]uint8{}, len*4) - return hex.EncodeToString(b) -} - -// Pack encode proof -func EncodeProofArray(arr []eth.DoubleNodeWithMerkleProof) string { - hex := "0x" + LenToHex(len(arr)) - for _, v := range arr { - hex += EncodeProof(v) - } - - return hex -} - -// Encode proof to hex with exist hex -func EncodeProof(dnmp eth.DoubleNodeWithMerkleProof) string { - hex := "" - for _, v := range dnmp.DagNodes { - hex += v[2:] - } - - // pad the length - hex += LenToHex(len(dnmp.Proof)) - for _, v := range dnmp.Proof { - hex += v[2:] - } - - return hex -} - -// Encode Darwinia Eth Header -func EncodeDarwiniaEthHeader(header eth.DarwiniaEthHeader) string { - hb, _ := hex.DecodeString(header.ExtraData[2:]) - len := LenToHex(len(hb)) - - hex := "0x" - hex += header.ParentHash[2:] - hex += encodeUint(header.TimeStamp, 64) - hex += encodeUint(header.Number, 64) - hex += strings.ToLower(header.Author[2:]) - hex += header.TransactionsRoot[2:] - hex += header.UnclesHash[2:] - hex += len - hex += header.ExtraData[2:] - hex += header.StateRoot[2:] - hex += header.ReceiptsRoot[2:] - hex += header.LogBloom[2:] - hex += encodeUint(header.GasUsed, 256) - hex += encodeUint(header.GasLimited, 256) - hex += encodeUint(header.Difficulty, 256) - // length - hex += "0884" - hex += header.Seal[0][2:] - // length - hex += "24" - hex += header.Seal[1][2:] - // Option - hex += "01" - hex += header.Hash[2:] - - return hex -} - -// Encode uint to hex -func encodeUint(n uint64, d int16) string { - b := make([]byte, d/8) - binary.LittleEndian.PutUint64(b, n) - - return hex.EncodeToString(b) -} diff --git a/internal/core/schema.go b/internal/core/schema.go deleted file mode 100644 index ba82202b..00000000 --- a/internal/core/schema.go +++ /dev/null @@ -1,132 +0,0 @@ -package core - -import ( - "encoding/json" - "fmt" - - "github.com/darwinia-network/shadow/internal" - "github.com/darwinia-network/shadow/internal/eth" - "github.com/darwinia-network/shadow/internal/log" - "github.com/darwinia-network/shadow/internal/util" - "github.com/ethereum/go-ethereum/core/types" - "github.com/jinzhu/gorm" - _ "github.com/jinzhu/gorm/dialects/sqlite" -) - -type EthHeaderWithProofCache struct { - Hash string `json:"hash"` - Number uint64 `json:"number" gorm:"unique_index"` - Header string `json:"eth_header"` - Proof string `json:"proof"` - Root string `json:"root" gorm:"DEFAULT:NULL"` -} - -// Fetch Eth Header by number -func (c *EthHeaderWithProofCache) Fetch(shadow *Shadow) error { - block, err := IndexHeaderFromDB(shadow.DB, c) - - if err != nil || util.IsEmpty(c.Header) || c.Header == "" { - log.Trace("fetching block %v ...", block) - *c, err = FetchHeaderCache(shadow, block) - if err != nil { - return err - } - - // Prints logs every 100 headers - if c.Number > 0 && c.Number%100 == 0 { - log.Info( - "imported headers from #%v to #%v\n", - c.Number-100, - c.Number, - ) - } - } - - // Return resp - return nil -} - -/// The func should run after `Fetch` -func (c *EthHeaderWithProofCache) ApplyProof(shadow *Shadow) error { - block, err := IndexHeaderFromDB(shadow.DB, c) - - // Check proof lock - if err != nil || util.IsEmpty(c.Proof) || c.Proof == "" { - if shadow.Config.CheckLock(internal.PROOF_LOCK) { - return fmt.Errorf("Shadow service is busy now, please try again later") - } else { - err := shadow.Config.CreateLock(internal.PROOF_LOCK) - if err != nil { - return err - } - } - - // Fetch EthHeader - var ethHeader types.Header - ethHeader, err = FetchHeader(shadow, block) - if err != nil { - return err - } - - err = CreateProofCache(shadow, c, ðHeader) - if err != nil { - return err - } - - } - return nil -} - -// Convert EthHeader -func (c *EthHeaderWithProofCache) IntoResp() (GetEthHeaderWithProofRawResp, error) { - var rResp GetEthHeaderWithProofRawResp - header, proof := eth.DarwiniaEthHeader{}, []eth.DoubleNodeWithMerkleProof{} - - // Decode header - err := json.Unmarshal([]byte(c.Header), &header) - if err != nil { - log.Error("Unmarshal eth header failed %v", c.Header) - return rResp, err - } - - // Decode proof - if !util.IsEmpty(c.Proof) { - err = json.Unmarshal([]byte(c.Proof), &proof) - if err != nil { - log.Error("Unmarshal eth header proof failed %v", c.Proof) - return rResp, err - } - } - - // Construct resp - return GetEthHeaderWithProofRawResp{ - Header: header, - Proof: proof, - Root: c.Root, - }, nil -} - -func (c *EthHeaderWithProofCache) FromResp( - db *gorm.DB, - resp GetEthHeaderWithProofRawResp, -) error { - // Convert header to string - header, err := json.Marshal(resp.Header) - if err != nil { - return err - } - - proof, err := json.Marshal(resp.Proof) - if err != nil { - return err - } - - db.Create(&EthHeaderWithProofCache{ - Hash: resp.Header.Hash, - Number: resp.Header.Number, - Header: string(header), - Proof: string(proof), - }) - - return nil -} diff --git a/internal/core/shadow.go b/internal/core/shadow.go deleted file mode 100644 index d38bf903..00000000 --- a/internal/core/shadow.go +++ /dev/null @@ -1,210 +0,0 @@ -package core - -import ( - "fmt" - - "github.com/darwinia-network/shadow/internal" - "github.com/darwinia-network/shadow/internal/eth" - "github.com/darwinia-network/shadow/internal/log" - "github.com/darwinia-network/shadow/internal/util" - "github.com/ethereum/go-ethereum/core/types" - "github.com/jinzhu/gorm" -) - -// Shadow genesis block error message -const GENESIS_ERROR = "The requested block number is too low, only support blocks heigher than %v" - -// Dimmy shadow service -type Shadow struct { - Config internal.Config - DB *gorm.DB -} - -func NewShadow() (Shadow, error) { - conf := new(internal.Config) - err := conf.Load() - if err != nil { - return Shadow{}, err - } - - db, err := ConnectDb() - if err != nil { - return Shadow{}, err - } - - return Shadow{ - *conf, - db, - }, err -} - -// Genesis block checker -func (s *Shadow) checkGenesis(genesis uint64, block interface{}) (uint64, error) { - block, err := util.NumberOrString(block) - if err != nil { - return genesis, err - } - - switch b := block.(type) { - case uint64: - if b < genesis { - return genesis, fmt.Errorf(GENESIS_ERROR, genesis) - } - - return b, nil - case string: - eH, err := eth.Header(b, s.Config.Api) - if err != nil { - return genesis, err - } - - // convert ethHeader to darwinia header - dH, err := eth.IntoDarwiniaEthHeader(&eH) - if err != nil { - return dH.Number, err - } - - // Check hash empty response - if util.IsEmpty(dH) { - return genesis, fmt.Errorf("Empty block: %s", b) - } - - // Check genesis by number - if dH.Number < genesis { - log.Error("Requesting block %v", dH.Number) - return genesis, fmt.Errorf(GENESIS_ERROR, genesis) - } - - return dH.Number, nil - default: - return genesis, fmt.Errorf("Invaild block param: %v", block) - } -} - -/** - * GetEthHeaderByNumber - */ -func (s *Shadow) GetHeader( - chain Chain, - block interface{}, -) (types.Header, error) { - switch chain { - default: - num, err := s.checkGenesis(s.Config.Genesis, block) - if err != nil { - return types.Header{}, err - } - - return eth.Header(num, s.Config.Api) - } - -} - -func (s *Shadow) GetHeaderWithProof( - chain Chain, - block interface{}, -) (GetEthHeaderWithProofRawResp, error) { - switch chain { - default: - num, err := s.checkGenesis(s.Config.Genesis, block) - if err != nil { - return GetEthHeaderWithProofRawResp{}, err - } - - // Log the event - log.Trace("Request block %v with proof...", num) - - // Fetch header from cache - cache, err := FetchHeaderCache(s, num) - if err != nil { - return GetEthHeaderWithProofRawResp{}, err - } - - err = cache.ApplyProof(s) - if err != nil { - return GetEthHeaderWithProofRawResp{}, err - } - - rawResp, err := cache.IntoResp() - if err != nil { - return GetEthHeaderWithProofRawResp{}, err - } - - return rawResp, nil - } -} - -/** - * BatchEthHeaderWithProofByNumber - */ -func (s *Shadow) BatchHeaderWithProof( - block uint64, - batch int, -) ([]GetEthHeaderWithProofRawResp, error) { - log.Trace("Batching blocks %v - %v...", block, block+uint64(batch)) - - // Batch headers - var nps []GetEthHeaderWithProofRawResp - for i := 0; i < batch; i++ { - np, err := s.GetHeaderWithProof( - Ethereum, - block+uint64(i), - ) - - if err != nil { - return nps, err - } - - nps = append(nps, np) - } - - return nps, nil -} - -/** - * Get proposal headers - */ -func (s *Shadow) GetProposalHeaders(numbers []uint64) ([]GetEthHeaderWithProofRawResp, error) { - var ( - phs []GetEthHeaderWithProofRawResp - ) - - log.Trace("Geting proposal block %v...", numbers) - for _, i := range numbers { - rawp, err := s.GetHeaderWithProof( - Ethereum, - uint64(i), - ) - if err != nil { - return phs, err - } - - phs = append(phs, rawp) - } - - return phs, nil -} - -/** - * Get proposal headers - */ -func (s *Shadow) GetReceipt( - tx string, -) (resp GetReceiptResp, err error) { - log.Trace("Geting ethereum receipt of tx %v...", tx) - proof, hash, err := eth.GetReceipt(tx) - if err != nil { - return - } - - resp.ReceiptProof = proof.Proof - cache := EthHeaderWithProofCache{Hash: hash} - err = cache.Fetch(s) - if err != nil { - return - } - - cr, err := cache.IntoResp() - resp.Header = cr.Header - return -} diff --git a/internal/core/sql.go b/internal/core/sql.go deleted file mode 100644 index 7714dd51..00000000 --- a/internal/core/sql.go +++ /dev/null @@ -1,31 +0,0 @@ -package core - -import ( - "fmt" -) - -func UpsertHeaderSQL(cache *EthHeaderWithProofCache) string { - return fmt.Sprintf( - "%s %s %s %s ('%s', %v, '%s', '%s', '%s');", - "INSERT or REPLACE INTO", // insert or replace - "eth_header_with_proof_caches", // table - "(hash, number, header, proof, root)", // columns - "values", // values - cache.Hash, - cache.Number, - cache.Header, - cache.Proof, - cache.Root, - ) -} - -func SelectHeader(number uint64) string { - return fmt.Sprintf( - "%s %s %s %s %v;", - "SELECT * FROM", - "eth_header_with_proof_caches", - "WHERE", - "number =", - number, - ) -} diff --git a/internal/core/types.go b/internal/core/types.go deleted file mode 100644 index 1217c12e..00000000 --- a/internal/core/types.go +++ /dev/null @@ -1,132 +0,0 @@ -package core - -import ( - "fmt" - "strings" - - "github.com/darwinia-network/shadow/internal/eth" - "github.com/darwinia-network/shadow/internal/ffi" - "github.com/ethereum/go-ethereum/core/types" -) - -// Get Header -type GetEthHeaderByNumberParams struct { - Number uint64 `json:"number"` -} - -type GetEthHeaderByHashParams struct { - Hash string `json:"hash"` -} - -type GetEthHeaderResp struct { - Header types.Header `json:"header"` -} - -// Get Header With Proof -type GetEthHeaderWithProofByNumberParams struct { - Number uint64 `json:"block_num"` - Options GetEthHeaderWithProofByNumberOptions `json:"options"` -} - -type GetEthHeaderWithProofByNumberOptions struct { - Format string `json:"format"` -} - -type GetEthHeaderWithProofByHashParams struct { - Hash string `json:"hash"` - Options GetEthHeaderWithProofByNumberOptions `json:"options"` -} - -type GetEthHeaderWithProofJSONResp struct { - Header eth.DarwiniaEthHeaderHexFormat `json:"eth_header"` - Proof []eth.DoubleNodeWithMerkleProof `json:"ethash_proof"` - Root string `json:"mmr_root"` -} - -type GetEthHeaderWithProofCodecResp struct { - Header string `json:"eth_header"` - Proof string `json:"ethash_proof"` - Root string `json:"mmr_root"` -} - -type GetEthHeaderWithProofRawResp struct { - Header eth.DarwiniaEthHeader `json:"eth_header"` - Proof []eth.DoubleNodeWithMerkleProof `json:"ethash_proof"` - Root string `json:"mmr_root"` -} - -func (r *GetEthHeaderWithProofRawResp) IntoCodec() GetEthHeaderWithProofCodecResp { - return GetEthHeaderWithProofCodecResp{ - EncodeDarwiniaEthHeader(r.Header), - EncodeProofArray(r.Proof), - r.Root, - } -} - -func (r *GetEthHeaderWithProofRawResp) IntoJSON() GetEthHeaderWithProofJSONResp { - return GetEthHeaderWithProofJSONResp{ - r.Header.HexFormat(), - r.Proof, - r.Root, - } -} - -func (r *GetEthHeaderWithProofRawResp) IntoProposal(leaf uint64) ProposalHeader { - mmrProof := ffi.ProofLeaves(leaf, r.Header.Number) - return ProposalHeader{ - r.Header, - r.Proof, - r.Root, - strings.Split(mmrProof, ","), - } -} - -func (r *GetEthHeaderWithProofRawResp) IntoProposalCodec(leaf uint64) string { - codec := r.IntoCodec() - mmrProof := strings.Split(ffi.ProofLeaves(leaf, r.Header.Number), ",") - return codec.Header + codec.Proof[2:] + codec.Root + LenToHex(len(mmrProof)) + strings.Join(mmrProof[:], "") -} - -func (r *GetEthHeaderWithProofRawResp) IntoProposalCodecWithExProof(mmrProof []string) string { - codec := r.IntoCodec() - fmt.Println(LenToHex(len(mmrProof)) + strings.Join(mmrProof[:], "")) - return codec.Header + codec.Proof[2:] + codec.Root + LenToHex(len(mmrProof)) + strings.Join(mmrProof[:], "") -} - -// Batch Header -type BatchEthHeaderWithProofByNumberParams struct { - Number uint64 `json:"number"` - Batch int `json:"batch"` - Options GetEthHeaderWithProofByNumberOptions `json:"options"` -} - -// Proposal Header -type GetProposalEthHeadersParams struct { - Numbers []uint64 `json:"number"` - Options GetEthHeaderWithProofByNumberOptions `json:"options"` -} - -type ProposalHeader struct { - Header eth.DarwiniaEthHeader `json:"eth_header"` - Proof []eth.DoubleNodeWithMerkleProof `json:"ethash_proof"` - Root string `json:"mmr_root"` - MMRProof []string `json:"mmr_proof"` -} - -type ProposalHeaderCodecFormat struct { - Header string `json:"eth_header"` - Proof string `json:"ethash_proof"` - Root string `json:"mmr_root"` - MMRProof string `json:"mmr_proof"` -} - -type ProposalResp struct { - Headers []interface{} `json:"headers"` -} - -// Receipt -type GetReceiptResp struct { - Header eth.DarwiniaEthHeader `json:"header"` - ReceiptProof string `json:"receipt_proof"` - MMRProof []string `json:"mmr_proof"` -} diff --git a/internal/eth/geth.go b/internal/eth/geth.go deleted file mode 100644 index 837bb050..00000000 --- a/internal/eth/geth.go +++ /dev/null @@ -1,60 +0,0 @@ -package eth - -import ( - "path" - - "github.com/darwinia-network/shadow/internal/util" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethdb" -) - -type Geth struct { - db ethdb.Database -} - -func NewGeth(datadir string) (Geth, error) { - if util.IsEmpty(datadir) { - return Geth{}, nil - } - - db, err := rawdb.NewLevelDBDatabaseWithFreezer( - datadir, - 768, - 16, - path.Join(datadir, "ancient"), - "", - ) - - return Geth{db}, err -} - -func (g *Geth) HashToNumber(h string) uint64 { - return *rawdb.ReadHeaderNumber(g.db, common.BytesToHash(common.FromHex(h))) -} - -func (g *Geth) Header(block interface{}) *types.Header { - block, err := util.NumberOrString(block) - if err != nil || g.db == nil { - return &types.Header{} - } - - switch b := block.(type) { - case string: - hash := common.BytesToHash(common.FromHex(b)) - return g.Header(rawdb.ReadHeaderNumber(g.db, hash)) - case uint64: - block := rawdb.ReadBlock( - g.db, - rawdb.ReadCanonicalHash(g.db, b), - b, - ) - if util.IsEmpty(block) { - return &types.Header{} - } - return block.Header() - default: - return &types.Header{} - } -} diff --git a/internal/eth/serde.go b/internal/eth/serde.go deleted file mode 100644 index c8951a5a..00000000 --- a/internal/eth/serde.go +++ /dev/null @@ -1,86 +0,0 @@ -package eth - -import ( - "fmt" - "strconv" - "strings" -) - -func (h *DarwiniaEthHeader) Ser() string { - return fmt.Sprintf( - "%s|%v|%v|%s|%s|%s|%s|%s|%s|%s|%v|%v|%v|%s|%s", - h.ParentHash, - h.TimeStamp, - h.Number, - h.Author, - h.TransactionsRoot, - h.UnclesHash, - h.ExtraData, - h.StateRoot, - h.ReceiptsRoot, - h.LogBloom, - h.GasUsed, - h.GasLimited, - h.Difficulty, - fmt.Sprintf("%s.%s", h.Seal[0], h.Seal[1]), - h.Hash, - ) -} - -func (h *DarwiniaEthHeader) De(str string) error { - sa := strings.Split(str, "|") - if len(sa) != 15 { - return fmt.Errorf( - "Deserialize DarwiniaEthHeader failed, the lenght is %v, expect 15", - len(sa), - ) - } - - // timestamp - ts, err := strconv.ParseUint(sa[1], 10, 64) - if err != nil { - return fmt.Errorf("Parse timestamp failed: %v", sa[1]) - } - - // number - num, err := strconv.ParseUint(sa[2], 10, 64) - if err != nil { - return fmt.Errorf("Parse block number failed: %v", sa[2]) - } - - // gas used - gasUsed, err := strconv.ParseUint(sa[10], 10, 64) - if err != nil { - return fmt.Errorf("Parse block gas used failed: %v", sa[10]) - } - - // gas limited - gasLimited, err := strconv.ParseUint(sa[11], 10, 64) - if err != nil { - return fmt.Errorf("Parse block gas limited failed: %v", sa[11]) - } - - // difficulty - diff, err := strconv.ParseUint(sa[12], 10, 64) - if err != nil { - return fmt.Errorf("Parse block gas used failed: %v", sa[12]) - } - - h.ParentHash = sa[0] - h.TimeStamp = ts - h.Number = num - h.Author = sa[3] - h.TransactionsRoot = sa[4] - h.UnclesHash = sa[5] - h.ExtraData = sa[6] - h.StateRoot = sa[7] - h.ReceiptsRoot = sa[8] - h.LogBloom = sa[9] - h.GasUsed = gasUsed - h.GasUsed = gasLimited - h.Difficulty = diff - h.Seal = strings.Split(sa[13], ".") - h.Hash = sa[14] - - return nil -} diff --git a/internal/ffi/mmr.go b/internal/ffi/mmr.go deleted file mode 100644 index 0d09e58e..00000000 --- a/internal/ffi/mmr.go +++ /dev/null @@ -1,18 +0,0 @@ -package ffi - -/* -#cgo LDFLAGS: -lmmr -lsqlite3 -ldl -#include - -extern int32_t run(int64_t thread, uint32_t limits); -extern char* proof(uint64_t last_leaf, uint64_t member); -*/ -import "C" - -func RunMMR(thread int64, limits uint32) { - C.run((C.int64_t)(thread), (C.uint32_t)(limits)) -} - -func ProofLeaves(last_leaf uint64, member uint64) string { - return C.GoString(C.proof((C.uint64_t)(last_leaf), (C.uint64_t)(member))) -} diff --git a/internal/tests/shadow_test.go b/internal/tests/shadow_test.go deleted file mode 100644 index cf6c509d..00000000 --- a/internal/tests/shadow_test.go +++ /dev/null @@ -1,94 +0,0 @@ -package tests - -import ( - "fmt" - "testing" - - "github.com/darwinia-network/shadow/internal" - "github.com/darwinia-network/shadow/internal/core" - "github.com/darwinia-network/shadow/internal/util" -) - -/** - * Generate Shadow API - */ -func genShadow() core.Shadow { - conf := internal.Config{} - err := conf.Load() - util.Assert(err) - - // Generate Shadow - shadow, err := core.NewShadow() - util.Assert(err) - return shadow -} - -func TestGetBlockByNumber(t *testing.T) { - t.Run("Test GetBlockByNumber", func(t *testing.T) { - shadow := genShadow() - resp, err := shadow.GetHeader(core.Ethereum, uint64(1)) - util.Assert(err) - util.AssertEmpty(resp) - }) -} - -func TestGetBlockByHash(t *testing.T) { - t.Run("Test GetBlockByHash", func(t *testing.T) { - shadow := genShadow() - resp, err := shadow.GetHeader(core.Ethereum, fmt.Sprintf( - "%s%s", - "0x88e96d4537bea4d9c05d12549907b32", - "561d3bf31f45aae734cdc119f13406cb6", - )) - util.Assert(err) - util.AssertEmpty(resp) - }) -} - -func TestGetEthHeaderWithProofByNumber(t *testing.T) { - t.Run("Test GetEthHeaderWithProofByNumber", func(t *testing.T) { - shadow := genShadow() - resp, err := shadow.GetHeaderWithProof(core.Ethereum, uint64(1)) - util.Assert(err) - util.AssertEmpty(resp) - }) -} - -func TestGetEthHeaderWithProofByHash(t *testing.T) { - t.Run("Test GetEthHeaderWithProofByHash", func(t *testing.T) { - shadow := genShadow() - resp, err := shadow.GetHeaderWithProof(core.Ethereum, fmt.Sprintf( - "%s%s", - "0x88e96d4537bea4d9c05d12549907b32", - "561d3bf31f45aae734cdc119f13406cb6", - )) - util.Assert(err) - util.AssertEmpty(resp) - }) -} - -func TestBatchEthHeaderWithProofByNumber(t *testing.T) { - t.Run("Test BatchEthHeaderWithProofByNumber", func(t *testing.T) { - shadow := genShadow() - resp, err := shadow.BatchHeaderWithProof(1, 3) - util.Assert(err) - util.AssertEmpty(resp) - - if len(resp) != 3 { - t.Errorf("Wrong length %v in batch header resp", resp) - } - }) -} - -func TestGetReceipt(t *testing.T) { - t.Run("Test GetReceipt", func(t *testing.T) { - shadow, err := core.NewShadow() - util.Assert(err) - - resp, err := shadow.GetReceipt("/0x663cffc56aece411d9dc8096a162b65089d720d69e06f953bd58804cedebb06f") - util.Assert(err) - - util.AssertEmpty(resp.Header) - util.AssertEmpty(resp.ReceiptProof) - }) -} diff --git a/internal/util/parallel.go b/internal/util/parallel.go deleted file mode 100644 index 83f46163..00000000 --- a/internal/util/parallel.go +++ /dev/null @@ -1,18 +0,0 @@ -package util - -import "sync" - -// Parallelize parallelizes the function calls -func Parallelize(functions []func()) { - var waitGroup sync.WaitGroup - waitGroup.Add(len(functions)) - - defer waitGroup.Wait() - - for _, function := range functions { - go func(copy func()) { - defer waitGroup.Done() - copy() - }(function) - } -} diff --git a/makefile b/makefile deleted file mode 100755 index 12aaafdb..00000000 --- a/makefile +++ /dev/null @@ -1,14 +0,0 @@ -EXT := a -SUDO := sudo - -ifeq ($(shell uname),Darwin) - EXT := a - SUDO := -endif - -build: target/release/libmmr.$(EXT) - @go mod tidy - @go build -o ./target/shadow -v github.com/darwinia-network/shadow/bin -target/release/libmmr.$(EXT): mmr/lib.rs Cargo.toml - @cargo build --verbose --release - $(SUDO) cp ./target/release/libmmr.$(EXT) /usr/local/lib diff --git a/mmr/bridge/ethash_proof.rs b/mmr/bridge/ethash_proof.rs deleted file mode 100644 index 7491236a..00000000 --- a/mmr/bridge/ethash_proof.rs +++ /dev/null @@ -1,36 +0,0 @@ -use super::{H128, H512}; -use scale::{Decode, Encode}; - -/// Ethash proof -#[derive(Encode, Decode, Debug, PartialEq, Eq)] -pub struct DoubleNodeWithMerkleProof { - /// Dag nodes - pub dag_nodes: [H512; 2], - /// Merkle Proofs - pub proof: Vec, -} - -impl DoubleNodeWithMerkleProof { - /// Generate DoubleNodeWithMerkleProof from hex array - pub fn from_tuple(dag_nodes: [&str; 2], proof: [&str; 23]) -> DoubleNodeWithMerkleProof { - DoubleNodeWithMerkleProof { - dag_nodes: [ - H512(bytes!(dag_nodes[0], 64)), - H512(bytes!(dag_nodes[1], 64)), - ], - proof: proof - .iter() - .map(|s| H128(bytes!(*s, 16))) - .collect::>(), - } - } -} - -impl Default for DoubleNodeWithMerkleProof { - fn default() -> DoubleNodeWithMerkleProof { - DoubleNodeWithMerkleProof { - dag_nodes: <[H512; 2]>::default(), - proof: Vec::new(), - } - } -} diff --git a/mmr/bridge/header.rs b/mmr/bridge/header.rs deleted file mode 100644 index 0cc62df2..00000000 --- a/mmr/bridge/header.rs +++ /dev/null @@ -1,92 +0,0 @@ -use super::{Bloom, U256}; -use scale::{Decode, Encode}; -use std::fmt::Debug; - -/// Darwinia Eth header -#[derive(Decode, Encode, Debug, PartialEq, Eq)] -pub struct EthHeader { - parent_hash: [u8; 32], - timestamp: u64, - number: u64, - author: [u8; 20], - transactions_root: [u8; 32], - uncles_hash: [u8; 32], - extra_data: Vec, - state_root: [u8; 32], - receipts_root: [u8; 32], - log_bloom: Bloom, - gas_used: U256, - gas_limit: U256, - difficulty: U256, - seal: Vec>, - hash: Option<[u8; 32]>, -} - -impl EthHeader { - /// New EthHeader from string array - pub fn from_go_ffi( - parent_hash: &str, - timestamp: u64, - number: u64, - author: &str, - transactions_root: &str, - uncles_hash: &str, - extra_data: &str, - state_root: &str, - receipts_root: &str, - log_bloom: &str, - gas_used: &str, - gas_limit: &str, - difficulty: &str, - mixh: &str, - nonce: &str, - hash: &str, - ) -> EthHeader { - EthHeader { - parent_hash: bytes!(parent_hash, 32), - timestamp, - number, - author: bytes!(author, 20), - transactions_root: bytes!(transactions_root, 32), - uncles_hash: bytes!(uncles_hash, 32), - extra_data: bytes!(extra_data), - state_root: bytes!(state_root, 32), - receipts_root: bytes!(receipts_root, 32), - log_bloom: Bloom(bytes!(log_bloom, 256)), - gas_used: U256::from_dec_str(gas_used).unwrap_or_default(), - gas_limit: U256::from_dec_str(gas_limit).unwrap_or_default(), - difficulty: U256::from_dec_str(difficulty).unwrap_or_default(), - seal: match mixh.is_empty() && nonce.is_empty() { - true => vec![], - false => vec![bytes!(mixh), bytes!(nonce)], - }, - hash: match hash.is_empty() { - true => None, - false => Some(bytes!(hash, 32)), - }, - } - } -} - -impl Default for EthHeader { - fn default() -> EthHeader { - EthHeader::from_go_ffi( - "0x0000000000000000000000000000000000000000000000000000000000000000", - 0, - 0, - "0x0000000000000000000000000000000000000000", - "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "", - "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "0", - "0", - "0", - "", - "", - "" - ) - } -} diff --git a/mmr/bridge/mod.rs b/mmr/bridge/mod.rs deleted file mode 100644 index dada5f3d..00000000 --- a/mmr/bridge/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! format bridge -use scale::{Decode, Encode}; -use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; - -// macros -mod util; - -// types -mod ethash_proof; -mod header; -mod relay; - -// shared -use uint::construct_uint; -construct_uint! { - #[derive(Encode, Decode)] - pub struct U256(4); -} - -construct_hash_bytes! { - pub struct H128(16); -} - -construct_hash_bytes! { - pub struct H512(64); -} - -construct_hash_bytes! { - pub struct Bloom(256); -} - -pub use self::{ethash_proof::DoubleNodeWithMerkleProof, header::EthHeader, relay::HeaderThing}; diff --git a/mmr/bridge/util.rs b/mmr/bridge/util.rs deleted file mode 100644 index d22ffb28..00000000 --- a/mmr/bridge/util.rs +++ /dev/null @@ -1,91 +0,0 @@ -#![macro_use] - -/// Doc with expr -#[macro_export] -macro_rules! doc_comment { - ($x:expr, $($tt:tt)*) => { - #[doc = $x] - $($tt)* - }; -} - -/// Convert bytes to hex -#[macro_export] -macro_rules! hex { - ($bytes:expr) => {{ - let mut s = String::new(); - for i in $bytes { - s.push_str(&format!("{:02x}", i)); - } - s - }}; -} - -/// Convert hext to `Vec` or `[u8; n]` -#[macro_export] -macro_rules! bytes { - // Convert hex to Vec - ($hex:expr) => {{ - let mut h = $hex; - if h.starts_with("0x") { - h = &h[2..]; - } - - (0..h.len()) - .step_by(2) - .map(|i| u8::from_str_radix(&h[i..i + 2], 16)) - .collect::, _>>() - .unwrap_or_default() - }}; - - // Convert hex to [u8; $bits] - ($hex:expr, $bits:expr) => {{ - let mut hash = [0_u8; $bits]; - hash.copy_from_slice(&bytes!($hex)); - hash - }}; -} - -#[macro_export] -/// Construct hash bytes -macro_rules! construct_hash_bytes { - ( $(#[$attr:meta])* $visibility:vis struct $name:ident ( $n_words:tt ); ) => { - doc_comment!{ - concat!("The ", stringify!($n_words), "-bit hash type."), - $(#[$attr])* - #[derive(Decode, Encode)] - $visibility struct $name (pub [u8; $n_words]); - } - - impl Display for $name { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str(&hex!(self.0.as_ref())) - } - } - - impl Debug for $name { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - f.debug_list().entries(self.0.iter()).finish() - } - } - - impl Default for $name { - fn default() -> $name { - $name([0; $n_words]) - } - } - - impl PartialEq for $name { - fn eq(&self, other: &Self) -> bool { - for i in 0..self.0.len() { - if self.0[i] != other.0[i] { - return false; - } - } - true - } - } - - impl Eq for $name {} - }; -} diff --git a/mmr/ffi/mod.rs b/mmr/ffi/mod.rs deleted file mode 100644 index 83c61bab..00000000 --- a/mmr/ffi/mod.rs +++ /dev/null @@ -1,54 +0,0 @@ -//! C Bridge -use crate::{ - hash::{MergeHash, H256}, - pool, - runner::Runner, - store::Store, -}; -use cmmr::MMR; -use std::ffi::CString; - -/// Run the mmr service -#[no_mangle] -pub extern "C" fn run(t: i64, g: u32) -> i32 { - env_logger::init(); - info!("starting mmr service..."); - let conn = pool::conn(None); - if Runner::with(conn).start(t, g).is_ok() { - 0 - } else { - error!("mmr service start failed"); - 1 - } -} - -/// Proof leaves -/// -/// # Safe -/// -/// Concatenate strings -#[no_mangle] -pub unsafe extern "C" fn proof(last_leaf: u64, member: u64) -> CString { - let conn = pool::conn(None); - let store = Store::with(conn); - let mmr = MMR::<_, MergeHash, _>::new(cmmr::leaf_index_to_mmr_size(last_leaf), store); - match mmr.gen_proof(vec![cmmr::leaf_index_to_pos(member)]) { - Err(e) => { - error!( - "Generate proof failed {:?}, last_leaf: {:?}, member: {:?}", - e, last_leaf, member - ); - CString::new("").unwrap() - } - Ok(proof) => CString::new( - proof - .proof_items() - .iter() - .map(|item| H256::hex(item)) - .collect::>() - .join(",") - .as_bytes(), - ) - .unwrap(), - } -} diff --git a/mmr/result.rs b/mmr/result.rs deleted file mode 100644 index 20b718b8..00000000 --- a/mmr/result.rs +++ /dev/null @@ -1,26 +0,0 @@ -//! MMR Errors -use cmmr::Error as MMRError; -use diesel::result::Error as DieselError; - -/// MMR Errors -#[derive(Debug)] -pub enum Error { - /// Diesel Error - Diesel(DieselError), - /// MMR Error - MMR(MMRError), - /// Custom - Custom(String), -} - -impl From for Error { - fn from(e: MMRError) -> Error { - Error::MMR(e) - } -} - -impl From for Error { - fn from(e: DieselError) -> Error { - Error::Diesel(e) - } -} diff --git a/mmr/runner.rs b/mmr/runner.rs deleted file mode 100644 index 9132fe3f..00000000 --- a/mmr/runner.rs +++ /dev/null @@ -1,154 +0,0 @@ -//! MMR Runner -use super::{ - hash::{MergeHash, H256}, - helper, - model::Cache, - pool::{ConnPool, PooledConn}, - result::Error, - schema::{eth_header_with_proof_caches::dsl::*, mmr_store::dsl::*}, - store::Store, -}; -use cmmr::{Error as StoreError, MMR}; -use diesel::{dsl::count, prelude::*, result::Error as DieselError}; -use std::{ - sync::{mpsc, Arc, Mutex}, - thread, time, -}; - -/// MMR Runner -#[derive(Clone)] -pub struct Runner { - store: Store, - pool: ConnPool, -} - -impl Runner { - /// Get Pooled connection - pub fn conn(&self) -> Result { - let cfp = self.pool.get(); - if cfp.is_err() { - return Err(Error::Custom("Connect to database failed".into())); - } - - Ok(cfp.unwrap()) - } - - /// Start with sqlite3 conn - pub fn with(pool: ConnPool) -> Runner { - let store = Store::with(pool.clone()); - Runner { store, pool } - } - - fn check_push(&mut self, cur: i64) -> i64 { - if let Err(e) = self.push(cur) { - let mut locked = |m: &str| { - if m.contains("database is locked") { - warn!("Database if locked, retry after 100ms..."); - thread::sleep(time::Duration::from_millis(100)); - Some(self.check_push(cur)) - } else { - error!("{:?}", m); - None - } - }; - match e { - Error::Diesel(DieselError::NotFound) => { - trace!("Could not find block {:?} in cache", cur) - } - Error::Diesel(DieselError::DatabaseError(_, e)) => { - if let Some(r) = locked(e.message()) { - return r; - } - } - Error::MMR(StoreError::StoreError(e)) => { - if let Some(r) = locked(&e) { - return r; - } - } - _ => error!("Push block to mmr_store failed: {:?}", e), - } - - trace!("MMR service restarting after 10s..."); - thread::sleep(time::Duration::from_secs(10)); - self.check_push(cur) - } else { - trace!("push mmr of eth block {} into db succeed.", cur); - cur + 1 - } - } - - /// Start the runner - pub fn start(&mut self, thread: i64, limits: u32) -> Result<(), Error> { - let mut ptr = { - let last_leaf = helper::mmr_size_to_last_leaf(self.mmr_count()?); - if last_leaf == 0 { - 0 - } else { - last_leaf + 1 - } - }; - - let gap: time::Duration = time::Duration::from_secs(1) / limits; - loop { - let next = Arc::new(Mutex::new(ptr)); - let (tx, rx) = mpsc::channel(); - for _ in 0..thread { - let (next, tx) = (Arc::clone(&next), tx.clone()); - let mut this = self.clone(); - thread::spawn(move || { - let mut cur = next.lock().unwrap(); - *cur = this.check_push(*cur); - thread::sleep(gap); - if *cur == thread + ptr { - tx.send(*cur).unwrap(); - } - }); - } - - ptr = rx.recv().unwrap(); - } - } - - /// Get block hash by number - pub fn get_hash(&mut self, block: i64) -> Result { - let cache = eth_header_with_proof_caches - .filter(number.eq(block)) - .first::(&self.conn()?)?; - - Ok(cache.hash) - } - - /// Push new header hash into storage - pub fn push(&mut self, pnumber: i64) -> Result<(), Error> { - let conn = self.conn()?; - let cache = eth_header_with_proof_caches - .filter(number.eq(pnumber)) - .first::(&conn)?; - - let mut mmr = - MMR::<_, MergeHash, _>::new(self.mmr_count().unwrap_or(0) as u64, self.store.clone()); - if let Err(e) = mmr.push(H256::from(&cache.hash[2..])) { - return Err(Error::MMR(e)); - } - - // eth_header_with_proof_caches - let proot = mmr.get_root()?; - diesel::update(eth_header_with_proof_caches.filter(number.eq(pnumber))) - .set(root.eq(Some(H256::hex(&proot)))) - .execute(&conn)?; - - mmr.commit()?; - Ok(()) - } - - /// Get the count of mmr store - fn mmr_count(&self) -> Result { - let conn = self.conn()?; - let res = mmr_store.select(count(elem)).first::(&conn); - if let Err(e) = res { - Err(Error::Diesel(e)) - } else { - Ok(res?) - } - } -} diff --git a/mmr/schema.rs b/mmr/schema.rs deleted file mode 100644 index b6532eca..00000000 --- a/mmr/schema.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Data schemas - -table! { - mmr_store(pos) { - elem -> Text, - pos -> BigInt, - } -} - -table! { - eth_header_with_proof_caches(number) { - hash -> Text, - number -> BigInt, - root -> Nullable, - } -} diff --git a/mock/proofs.go b/mock/proofs.go deleted file mode 100644 index 9e5ee8fc..00000000 --- a/mock/proofs.go +++ /dev/null @@ -1,160 +0,0 @@ -package mock - -var ( - ROOTS = []string{ - "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", - "0x58991bd1987e8b65ddcaf584128e2833ff5fc7209aa9de585fc5138e7ce708cc", - "0x7387059a3d6baaeeaff0b915f5039ea00d4458992041e43ede26dbbaca6cc012", - "0xe58f9c9747938e1cf5ea7f4693214b1d149a21ba03b40be480d1b6828403821e", - "0xb050765c6c3fee82dae70e0d604005e86c3b50c28f45b9acf15f078a8e1aee67", - "0x7e15edffeb736dd12731d1ed8146533cacc91a21b5733282c2ef19118d4b69d9", - "0x330b89cabf5d24e4592644034e4cf833f3a3a82b149dd8e94e3e4882ebaf397a", - "0x46d1ff289f1a0bf317bb4125cf64630d52b73d66b754522a25d229ae51ed7f76", - "0x5f49d8fd17a4bc2fda0a7cd3a9bdec2c30572c17452d033de2fe7d9ba647b26d", - "0xe28d7f650efb9cbaaca7f485d078c0f6b1104807a3a31f85fc1268b0673140ff", - "0x0040238931f92a948d551329e83e6a058518db0b0b47a934426f7b81e138ec4c", - "0x00f8829bbfc85a4e747f8e36bf961b388418b32bd14940767e1ff233fc7a18cd", - "0x288af0b45e92e35d826219cea19abfed542978bbbc2bd7721eb133f3dceadb5b", - "0x9e44fd882d0ce3c33f78c713fb45fc1ad22d324d6dfb9802e12419dbd28b0c1a", - "0x2dcb5b9039b2b577de6ddc209c06c6e718aee84211fbaefd4b5cff72c18066d1", - "0x7a0bf9a39dc552cf4ce072783c571a2a76b675fb96caf14254fca2c59f66dc3b", - "0x4b77589413bf2b7d4a7395060584b6736b04c0f64e2a8be537a57ff6edfc1364", - "0xffa3182b5048c35359f2a2c287329ebd89be42f90e4bb9f78c3ec0f10d29283e", - "0x364dda14a7068ac910db783c2471a66cb6b31b48c0d81c6bf355d4696f519115", - "0x54d123c9f298ae54a9af7309fbc264499f70637cf6947d2390626f2d73b6de74", - } - PROOFS = [][]string{ - []string{ - "88e96d4537bea4d9c05d12549907b32561d3bf31f45aae734cdc119f13406cb6", - "cea81d50343714a15b240c330d617f0259526bfd55e41a074cdb6eeb5f2fc97b", - "843749778a9d9df1a7d2751c7bb4d5a38cdc01ad3c2e5b154715474386c8df48", - "fe81caba806652061fecef0b8701830f1124fbb23ced5db7efb09f13842049be", - "12dd5150eec5232c712f1ee01e10c34ed3788acaf7a1740b3a91a5c3096717f7", - }, - []string{ - "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", - "cea81d50343714a15b240c330d617f0259526bfd55e41a074cdb6eeb5f2fc97b", - "843749778a9d9df1a7d2751c7bb4d5a38cdc01ad3c2e5b154715474386c8df48", - "fe81caba806652061fecef0b8701830f1124fbb23ced5db7efb09f13842049be", - "12dd5150eec5232c712f1ee01e10c34ed3788acaf7a1740b3a91a5c3096717f7", - }, - []string{ - "3d6122660cc824376f11ee842f83addc3525e2dd6756b9bcf0affa6aa88cf741", - "58991bd1987e8b65ddcaf584128e2833ff5fc7209aa9de585fc5138e7ce708cc", - "843749778a9d9df1a7d2751c7bb4d5a38cdc01ad3c2e5b154715474386c8df48", - "fe81caba806652061fecef0b8701830f1124fbb23ced5db7efb09f13842049be", - "12dd5150eec5232c712f1ee01e10c34ed3788acaf7a1740b3a91a5c3096717f7", - }, - []string{ - "b495a1d7e6663152ae92708da4843337b958146015a2802f4193a410044698c9", - "58991bd1987e8b65ddcaf584128e2833ff5fc7209aa9de585fc5138e7ce708cc", - "843749778a9d9df1a7d2751c7bb4d5a38cdc01ad3c2e5b154715474386c8df48", - "fe81caba806652061fecef0b8701830f1124fbb23ced5db7efb09f13842049be", - "12dd5150eec5232c712f1ee01e10c34ed3788acaf7a1740b3a91a5c3096717f7", - }, - []string{ - "f37c632d361e0a93f08ba29b1a2c708d9caa3ee19d1ee8d2a02612bffe49f0a9", - "e16bf391a7271bf54e2739d203cf9a5d21df4821ae9caa27869e0dcf825d572a", - "e58f9c9747938e1cf5ea7f4693214b1d149a21ba03b40be480d1b6828403821e", - "fe81caba806652061fecef0b8701830f1124fbb23ced5db7efb09f13842049be", - "12dd5150eec5232c712f1ee01e10c34ed3788acaf7a1740b3a91a5c3096717f7", - }, - []string{ - "23adf5a3be0f5235b36941bcb29b62504278ec5b9cdfa277b992ba4a7a3cd3a2", - "e16bf391a7271bf54e2739d203cf9a5d21df4821ae9caa27869e0dcf825d572a", - "e58f9c9747938e1cf5ea7f4693214b1d149a21ba03b40be480d1b6828403821e", - "fe81caba806652061fecef0b8701830f1124fbb23ced5db7efb09f13842049be", - "12dd5150eec5232c712f1ee01e10c34ed3788acaf7a1740b3a91a5c3096717f7", - }, - []string{ - "e0c7c0b46e116b874354dce6f64b8581bd239186b03f30a978e3dc38656f723a", - "c4ba5dd93c14f2febe02da5a764afcefcb77fe0f70e205357a2f224b82f86b91", - "e58f9c9747938e1cf5ea7f4693214b1d149a21ba03b40be480d1b6828403821e", - "fe81caba806652061fecef0b8701830f1124fbb23ced5db7efb09f13842049be", - "12dd5150eec5232c712f1ee01e10c34ed3788acaf7a1740b3a91a5c3096717f7", - }, - []string{ - "1f1aed8e3694a067496c248e61879cda99b0709a1dfbacd0b693750df06b326e", - "c4ba5dd93c14f2febe02da5a764afcefcb77fe0f70e205357a2f224b82f86b91", - "e58f9c9747938e1cf5ea7f4693214b1d149a21ba03b40be480d1b6828403821e", - "fe81caba806652061fecef0b8701830f1124fbb23ced5db7efb09f13842049be", - "12dd5150eec5232c712f1ee01e10c34ed3788acaf7a1740b3a91a5c3096717f7", - }, - []string{ - "997e47bf4cac509c627753c06385ac866641ec6f883734ff7944411000dc576e", - "e372fdd5267fe6554c5313a7e025f50e80777cd7f28176bb8113101e55459b49", - "eb87d3540689835e0392c937e10bd8146d1447335befaf0e34cbab9f6cbfd1af", - "46d1ff289f1a0bf317bb4125cf64630d52b73d66b754522a25d229ae51ed7f76", - "12dd5150eec5232c712f1ee01e10c34ed3788acaf7a1740b3a91a5c3096717f7", - }, - []string{ - "2ce94342df186bab4165c268c43ab982d360c9474f429fec5565adfc5d1f258b", - "e372fdd5267fe6554c5313a7e025f50e80777cd7f28176bb8113101e55459b49", - "eb87d3540689835e0392c937e10bd8146d1447335befaf0e34cbab9f6cbfd1af", - "46d1ff289f1a0bf317bb4125cf64630d52b73d66b754522a25d229ae51ed7f76", - "12dd5150eec5232c712f1ee01e10c34ed3788acaf7a1740b3a91a5c3096717f7", - }, - []string{ - "3f5e756c3efcb93099361b7ddd0dabfeaa592439437c1c836e443ccb81e93242", - "8e57ae1d44d62821b07a46c0e20d1ea5d1d3ef0200623a946dc82c4373f971df", - "eb87d3540689835e0392c937e10bd8146d1447335befaf0e34cbab9f6cbfd1af", - "46d1ff289f1a0bf317bb4125cf64630d52b73d66b754522a25d229ae51ed7f76", - "12dd5150eec5232c712f1ee01e10c34ed3788acaf7a1740b3a91a5c3096717f7", - }, - []string{ - "4ff4a38b278ab49f7739d3a4ed4e12714386a9fdf72192f2e8f7da7822f10b4d", - "8e57ae1d44d62821b07a46c0e20d1ea5d1d3ef0200623a946dc82c4373f971df", - "eb87d3540689835e0392c937e10bd8146d1447335befaf0e34cbab9f6cbfd1af", - "46d1ff289f1a0bf317bb4125cf64630d52b73d66b754522a25d229ae51ed7f76", - "12dd5150eec5232c712f1ee01e10c34ed3788acaf7a1740b3a91a5c3096717f7", - }, - []string{ - "55b6a7e73c57d1ca35b35cad22869eaa33e10fa2a822fb7308f419269794d611", - "d54570f903a13dd105012d1a61eb59016e5e1ca37e41b9f8937d7b352a2a398b", - "c83974302a5fed6385d81d97a5cce4aaa29ca5fea684d270a57cc33e1dc6a167", - "46d1ff289f1a0bf317bb4125cf64630d52b73d66b754522a25d229ae51ed7f76", - "12dd5150eec5232c712f1ee01e10c34ed3788acaf7a1740b3a91a5c3096717f7", - }, - []string{ - "c63f666315fa1eae17e354fab532aeeecf549be93e358737d0648f50d57083a0", - "d54570f903a13dd105012d1a61eb59016e5e1ca37e41b9f8937d7b352a2a398b", - "c83974302a5fed6385d81d97a5cce4aaa29ca5fea684d270a57cc33e1dc6a167", - "46d1ff289f1a0bf317bb4125cf64630d52b73d66b754522a25d229ae51ed7f76", - "12dd5150eec5232c712f1ee01e10c34ed3788acaf7a1740b3a91a5c3096717f7", - }, - []string{ - "2d33dc73755afbbbeb6ec4885f2923398901bf1ad94beb325a4c4ecad5bf0f1c", - "75cd460d026fed15ef9b0fb87a2338d0adcfb6fdfe7bb2c954da66dd35dcc5bb", - "c83974302a5fed6385d81d97a5cce4aaa29ca5fea684d270a57cc33e1dc6a167", - "46d1ff289f1a0bf317bb4125cf64630d52b73d66b754522a25d229ae51ed7f76", - "12dd5150eec5232c712f1ee01e10c34ed3788acaf7a1740b3a91a5c3096717f7", - }, - []string{ - "46015afbe00cf61ff284c26cc09a776a7303e422c7b359fe4317b4e6aaa410a4", - "75cd460d026fed15ef9b0fb87a2338d0adcfb6fdfe7bb2c954da66dd35dcc5bb", - "c83974302a5fed6385d81d97a5cce4aaa29ca5fea684d270a57cc33e1dc6a167", - "46d1ff289f1a0bf317bb4125cf64630d52b73d66b754522a25d229ae51ed7f76", - "12dd5150eec5232c712f1ee01e10c34ed3788acaf7a1740b3a91a5c3096717f7", - }, - []string{ - "7a0bf9a39dc552cf4ce072783c571a2a76b675fb96caf14254fca2c59f66dc3b", - "f25fe829ebbf3e2459ecb89cbc1aaa5f83c04501df08d63fa8dd1589f6b1cae0", - "1023dd460ff654107307616f6de01d4b0fcd6a3af721611582de7e809b65e46d", - }, - []string{ - "7a0bf9a39dc552cf4ce072783c571a2a76b675fb96caf14254fca2c59f66dc3b", - "9657beaf8542273d7448f6d277bb61aef0f700a91b238ac8b34c020f7fb8664c", - "1023dd460ff654107307616f6de01d4b0fcd6a3af721611582de7e809b65e46d", - }, - []string{ - "7a0bf9a39dc552cf4ce072783c571a2a76b675fb96caf14254fca2c59f66dc3b", - "b31db2ee05835be4fd025ae16eecaa55b670c1b67a009969a7912bea39f9951b", - "c0b665675897534496760f178673f8c563f68f7813f858ba00739933b528ca73", - }, - []string{ - "7a0bf9a39dc552cf4ce072783c571a2a76b675fb96caf14254fca2c59f66dc3b", - "480ff3f8a495b764e4361a6c2e296f34e8721cf1ec54fe5c46827937353bf118", - "c0b665675897534496760f178673f8c563f68f7813f858ba00739933b528ca73", - }, - } -) diff --git a/mock/uncle.go b/mock/uncle.go deleted file mode 100644 index 34bd13be..00000000 --- a/mock/uncle.go +++ /dev/null @@ -1,18 +0,0 @@ -package mock - -import ( - "github.com/darwinia-network/shadow/internal" - "github.com/darwinia-network/shadow/internal/core" - "github.com/darwinia-network/shadow/internal/eth" -) - -func Proposal(number uint64, conf internal.Config) (core.GetEthHeaderWithProofRawResp, error) { - header, _ := eth.UncleBlock(number, conf.Api) - proof, _ := eth.Proof(&header, conf) - dh, _ := eth.IntoDarwiniaEthHeader(&header) - - return core.GetEthHeaderWithProofRawResp{ - Header: dh, - Proof: proof.Format(), - }, nil -} diff --git a/internal/config.go b/pkg/internal/config.go similarity index 95% rename from internal/config.go rename to pkg/internal/config.go index 8a8b0859..f515352f 100644 --- a/internal/config.go +++ b/pkg/internal/config.go @@ -5,7 +5,7 @@ import ( "path/filepath" "strconv" - "github.com/darwinia-network/shadow/internal/util" + "github.com/darwinia-network/shadow/pkg/internal/util" ) const ( diff --git a/internal/eth/api.go b/pkg/internal/eth/api.go similarity index 100% rename from internal/eth/api.go rename to pkg/internal/eth/api.go diff --git a/internal/eth/header.go b/pkg/internal/eth/header.go similarity index 80% rename from internal/eth/header.go rename to pkg/internal/eth/header.go index ddd83c77..f29623df 100644 --- a/internal/eth/header.go +++ b/pkg/internal/eth/header.go @@ -7,14 +7,14 @@ import ( "net/http" "strings" - "github.com/darwinia-network/shadow/internal" + "github.com/darwinia-network/shadow/pkg/internal" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" ) // Get ethereum header by block number -func Header(block interface{}, api string) (types.Header, error) { +func Header(block uint64, api string) (types.Header, error) { // Get header from infura var ( resp *http.Response @@ -22,23 +22,12 @@ func Header(block interface{}, api string) (types.Header, error) { infuraResp InfuraResponse ) - // Request block by number or hash - switch b := block.(type) { - case uint64: - resp, err = http.Post( - api, - "application/json", - strings.NewReader(fmt.Sprintf(GETBLOCK, b)), - ) - case string: - resp, err = http.Post( - api, - "application/json", - strings.NewReader(fmt.Sprintf(GETBLOCK_BYHASH, b)), - ) - default: - return infuraResp.Result, fmt.Errorf("Heaader function only accepts blockHash and blockNumber") - } + resp, err = http.Post( + api, + "application/json", + strings.NewReader(fmt.Sprintf(GETBLOCK, block)), + ) + if err != nil { if !strings.Contains(api, "infura") { return Header(block, internal.DEFAULT_ETHEREUM_RPC) diff --git a/internal/eth/mock.go b/pkg/internal/eth/mock.go similarity index 94% rename from internal/eth/mock.go rename to pkg/internal/eth/mock.go index 17d54158..bbfd4e3f 100644 --- a/internal/eth/mock.go +++ b/pkg/internal/eth/mock.go @@ -7,7 +7,7 @@ import ( "reflect" "strings" - "github.com/darwinia-network/shadow/internal/log" + "github.com/darwinia-network/shadow/pkg/internal/log" "github.com/ethereum/go-ethereum/core/types" ) diff --git a/internal/eth/proof.go b/pkg/internal/eth/proof.go similarity index 93% rename from internal/eth/proof.go rename to pkg/internal/eth/proof.go index 0e056f8a..d3da4a04 100644 --- a/internal/eth/proof.go +++ b/pkg/internal/eth/proof.go @@ -7,11 +7,11 @@ import ( "os" "path/filepath" - "github.com/darwinia-network/shadow/internal" - "github.com/darwinia-network/shadow/internal/util" "github.com/darwinia-network/shadow/pkg/ethashproof" "github.com/darwinia-network/shadow/pkg/ethashproof/ethash" "github.com/darwinia-network/shadow/pkg/ethashproof/mtree" + "github.com/darwinia-network/shadow/pkg/internal" + "github.com/darwinia-network/shadow/pkg/internal/util" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" ) @@ -65,13 +65,13 @@ func (o *ProofOutput) Format() []DoubleNodeWithMerkleProof { } // Epoch in background -func bgEpoch(epoch uint64, config internal.Config) { +func bgEpoch(epoch uint64, config *internal.Config) { _, _ = ethashproof.CalculateDatasetMerkleRoot(epoch, true) _ = config.RemoveLock(internal.EPOCH_LOCK) } // Check if need epoch -func epochGently(epoch uint64, config internal.Config) error { +func epochGently(epoch uint64, config *internal.Config) error { // Check if is epoching if config.CheckLock(internal.EPOCH_LOCK) { return nil @@ -113,7 +113,7 @@ func epochGently(epoch uint64, config internal.Config) error { } // Proof eth blockheader -func Proof(header *types.Header, config internal.Config) (ProofOutput, error) { +func Proof(header *types.Header, config *internal.Config) (ProofOutput, error) { blockno := header.Number.Uint64() epoch := blockno / 30000 output := &ProofOutput{} diff --git a/internal/eth/receipt.go b/pkg/internal/eth/receipt.go similarity index 96% rename from internal/eth/receipt.go rename to pkg/internal/eth/receipt.go index c9550104..b3844fd8 100644 --- a/internal/eth/receipt.go +++ b/pkg/internal/eth/receipt.go @@ -8,8 +8,8 @@ import ( "strings" "sync" - "github.com/darwinia-network/shadow/internal" - "github.com/darwinia-network/shadow/internal/util" + "github.com/darwinia-network/shadow/pkg/internal" + "github.com/darwinia-network/shadow/pkg/internal/util" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" @@ -60,9 +60,12 @@ func GetReceiptLog(tx string) (*Receipts, error) { params[0] = tx var receipt Receipts if receiptResult, err := RPC("eth_getTransactionReceipt", params); err != nil { - return &Receipts{}, err + return nil, err } else { err := mapstructure.Decode(receiptResult.Result, &receipt) + if err != nil { + return nil, err + } receipt.ChainSource = "Eth" receipt.Solidity = true return &receipt, err @@ -114,7 +117,7 @@ type RedeemFor struct { func GetReceipt(tx string) (ProofRecord, string, error) { r, err := GetReceiptLog(tx) - if err != nil { + if err != nil || r == nil { return ProofRecord{}, "", err } @@ -128,7 +131,7 @@ func BuildProofRecord(r *Receipts) (ProofRecord, string, error) { } block, err := GetChainBlockInfo(util.U256(r.BlockNumber).Int64()) if err != nil { - return ProofRecord{}, block.Hash, err + return ProofRecord{}, "", err } receiptsMap := cmap.New() diff --git a/pkg/internal/eth/scale.go b/pkg/internal/eth/scale.go new file mode 100644 index 00000000..61193d76 --- /dev/null +++ b/pkg/internal/eth/scale.go @@ -0,0 +1,48 @@ +package eth + +import ( + "encoding/hex" +) + +func lenToBytes(b []uint8, len int) ([]uint8, int) { + if len < 255 { + b = append(b, uint8(len)) + len = 0 + return b, len + } + + b = append(b, uint8(len/0xff)) + len = len % 0xff + return lenToBytes(b, len) +} + +func LenToHex(len int) string { + b, _ := lenToBytes([]uint8{}, len*4) + return hex.EncodeToString(b) +} + +// Pack encode proof +func EncodeProofArray(arr []DoubleNodeWithMerkleProof) string { + hex := "0x" + LenToHex(len(arr)) + for _, v := range arr { + hex += EncodeProof(v) + } + + return hex +} + +// Encode proof to hex with exist hex +func EncodeProof(dnmp DoubleNodeWithMerkleProof) string { + hex := "" + for _, v := range dnmp.DagNodes { + hex += v[2:] + } + + // pad the length + hex += LenToHex(len(dnmp.Proof)) + for _, v := range dnmp.Proof { + hex += v[2:] + } + + return hex +} diff --git a/internal/eth/types.go b/pkg/internal/eth/types.go similarity index 100% rename from internal/eth/types.go rename to pkg/internal/eth/types.go diff --git a/pkg/internal/ffi/mod.go b/pkg/internal/ffi/mod.go new file mode 100644 index 00000000..5595ef90 --- /dev/null +++ b/pkg/internal/ffi/mod.go @@ -0,0 +1,43 @@ +package main + +import "C" +import ( + "github.com/darwinia-network/shadow/pkg/internal" + "github.com/darwinia-network/shadow/pkg/internal/eth" +) + +var ( + CONFIG internal.Config = internal.Config{} +) + +func init() { + _ = CONFIG.Load() +} + +//export Proof +func Proof(number uint64) *C.char { + header, err := eth.Header(number, CONFIG.Api) + if err != nil { + return C.CString("") + } + + proof, err := eth.Proof(&header, &CONFIG) + if err != nil { + return C.CString("") + } + + return C.CString(eth.EncodeProofArray(proof.Format())) +} + +//export Receipt +func Receipt(tx string) (*C.char, *C.char) { + tx = "0x" + tx[2:] + proof, hash, err := eth.GetReceipt(tx) + if err != nil { + return C.CString(""), C.CString("") + } + + return C.CString(proof.Proof), C.CString(hash) +} + +func main() {} diff --git a/internal/lock.go b/pkg/internal/lock.go similarity index 100% rename from internal/lock.go rename to pkg/internal/lock.go diff --git a/internal/log/mod.go b/pkg/internal/log/mod.go similarity index 100% rename from internal/log/mod.go rename to pkg/internal/log/mod.go diff --git a/internal/util/assert.go b/pkg/internal/util/assert.go similarity index 89% rename from internal/util/assert.go rename to pkg/internal/util/assert.go index a859830f..8a88b77b 100644 --- a/internal/util/assert.go +++ b/pkg/internal/util/assert.go @@ -4,7 +4,7 @@ import ( "os" "reflect" - "github.com/darwinia-network/shadow/internal/log" + "github.com/darwinia-network/shadow/pkg/internal/log" ) // Check if is empty diff --git a/internal/util/collection.go b/pkg/internal/util/collection.go similarity index 100% rename from internal/util/collection.go rename to pkg/internal/util/collection.go diff --git a/internal/util/encode.go b/pkg/internal/util/encode.go similarity index 100% rename from internal/util/encode.go rename to pkg/internal/util/encode.go diff --git a/src/api/eth/mod.rs b/src/api/eth/mod.rs new file mode 100644 index 00000000..e44518e5 --- /dev/null +++ b/src/api/eth/mod.rs @@ -0,0 +1,6 @@ +//! Ethereum API +mod proposal; +mod receipt; + +pub use proposal::handle as proposal; +pub use receipt::handle as receipt; diff --git a/src/api/eth/proposal.rs b/src/api/eth/proposal.rs new file mode 100644 index 00000000..ffdd04f8 --- /dev/null +++ b/src/api/eth/proposal.rs @@ -0,0 +1,108 @@ +use crate::{ + bytes, + chain::eth::{EthHeader, EthHeaderJson, EthashProof, EthashProofJson}, + hash::{MergeHash, H256}, + pool, + store::Store, +}; +use actix_web::{web, Responder}; +use cmmr::MMR; +use reqwest::Client; +use scale::Decode; +use std::{ffi::CStr, os::raw::c_char}; + +/// Proposal post req +#[derive(Deserialize)] +pub struct ProposalReq { + members: Vec, + last_leaf: u64, +} + +impl ProposalReq { + /// Get `EthHeader` + async fn eth_header(client: &Client, block: u64) -> EthHeaderJson { + EthHeader::get(&client, block) + .await + .unwrap_or_default() + .into() + } + + /// Get `EtHashProof` + fn ethash_proof(block: u64) -> Vec { + unsafe { + let proof = CStr::from_ptr(Proof(block as u32)) + .to_string_lossy() + .to_string(); + >::decode(&mut bytes!(proof.as_str()).as_ref()) + .unwrap_or_default() + .iter() + .map(|p| Into::::into(p)) + .collect() + } + } + + // Get mmr root + fn mmr_root(store: &Store, leaf: u64) -> String { + let mmr = MMR::<_, MergeHash, _>::new(cmmr::leaf_index_to_mmr_size(leaf), store); + format!("0x{}", H256::hex(&mmr.get_root().unwrap_or_default())) + } + + /// Generate mmr proof + fn mmr_proof(&self, store: &Store, member: u64) -> Vec { + let mmr = MMR::<_, MergeHash, _>::new(cmmr::leaf_index_to_mmr_size(self.last_leaf), store); + match mmr.gen_proof(vec![cmmr::leaf_index_to_pos(member)]) { + Err(e) => { + error!( + "Generate proof failed {:?}, last_leaf: {:?}, member: {:?}", + e, self.last_leaf, member + ); + vec![] + } + Ok(proof) => proof + .proof_items() + .iter() + .map(|item| format!("0x{}", H256::hex(item))) + .collect::>(), + } + } + + /// To headers + pub async fn headers(&self) -> Vec { + // TODO: optimzie the `clients` below + // + // Move them out of this handler + let conn = pool::conn(None); + let store = Store::with(conn); + let client = Client::new(); + + // Proposal Headers + let mut phs = vec![]; + for m in self.members.iter() { + phs.push(ProposalHeader { + eth_header: ProposalReq::eth_header(&client, *m).await, + ethash_proof: ProposalReq::ethash_proof(*m), + mmr_root: ProposalReq::mmr_root(&store, *m), + mmr_proof: ProposalReq::mmr_proof(&self, &store, *m), + }); + } + phs + } +} + +/// Proposal Headers +#[derive(Serialize)] +pub struct ProposalHeader { + eth_header: EthHeaderJson, + ethash_proof: Vec, + mmr_root: String, + mmr_proof: Vec, +} + +pub async fn handle(req: web::Json) -> impl Responder { + web::Json(req.0.headers().await) +} + +#[link(name = "eth")] +extern "C" { + fn Proof(input: libc::c_uint) -> *const c_char; +} diff --git a/src/api/eth/receipt.rs b/src/api/eth/receipt.rs new file mode 100644 index 00000000..96c277ba --- /dev/null +++ b/src/api/eth/receipt.rs @@ -0,0 +1,59 @@ +use actix_web::{web, Responder}; +use std::{ + ffi::{CStr, CString}, + os::raw::c_char, +}; + +#[derive(Serialize)] +struct ReceiptResp { + proof: String, + hash: String, +} + +/// Receipt Handler +pub async fn handle(tx: web::Path) -> impl Responder { + unsafe { + web::Json(Into::::into(Receipt(GoString::from( + tx.to_string(), + )))) + } +} + +// FFI +#[link(name = "eth")] +extern "C" { + fn Receipt(input: GoString) -> GoTuple; +} + +#[repr(C)] +struct GoString { + a: *const c_char, + b: i64, +} + +impl From for GoString { + fn from(s: String) -> GoString { + let c_tx = CString::new(s).expect("CString::new failed"); + GoString { + a: c_tx.as_ptr(), + b: c_tx.as_bytes().len() as i64, + } + } +} + +#[repr(C)] +struct GoTuple { + proof: *const c_char, + hash: *const c_char, +} + +impl Into for GoTuple { + fn into(self) -> ReceiptResp { + unsafe { + ReceiptResp { + proof: format!("{:?}", CStr::from_ptr(self.proof)), + hash: format!("{:?}", CStr::from_ptr(self.hash)), + } + } + } +} diff --git a/src/api/mod.rs b/src/api/mod.rs new file mode 100644 index 00000000..5067108b --- /dev/null +++ b/src/api/mod.rs @@ -0,0 +1,19 @@ +//! The API server of Shadow +use actix_web::{middleware, web, App, HttpServer}; + +mod eth; + +/// Run HTTP Server +pub async fn serve(port: u16) -> std::io::Result<()> { + HttpServer::new(|| { + App::new() + .wrap(middleware::Compress::default()) + .wrap(middleware::Logger::default()) + .service(web::resource("/eth/receipt/{tx}").to(eth::receipt)) + .service(web::resource("/eth/proposal").to(eth::proposal)) + }) + .disable_signals() + .bind(format!("0.0.0.0:{}", port))? + .run() + .await +} diff --git a/src/bin/shadow.rs b/src/bin/shadow.rs new file mode 100644 index 00000000..0658e90e --- /dev/null +++ b/src/bin/shadow.rs @@ -0,0 +1,4 @@ +#[actix_rt::main] +async fn main() { + shadow::cmd::exec().await.unwrap(); +} diff --git a/src/chain/array.rs b/src/chain/array.rs new file mode 100644 index 00000000..c15f07e7 --- /dev/null +++ b/src/chain/array.rs @@ -0,0 +1,38 @@ +use scale::{Decode, Encode}; +use serde::{ + de::{Deserialize, Deserializer, Error, SeqAccess, Visitor}, + ser::{Serialize, SerializeTuple, Serializer}, +}; +use std::{ + fmt::{self, Debug, Display, Formatter, Result as FmtResult}, + marker::PhantomData, +}; +use uint::construct_uint; + +/// Big Array Serde +pub trait BigArray<'de>: Sized { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer; + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>; +} + +// shared +construct_uint! { + #[derive(Encode, Decode, Serialize, Deserialize)] + pub struct U256(4); +} + +construct_hash_bytes! { + pub struct H128(16); +} + +construct_hash_bytes! { + pub struct H512(64); +} + +construct_hash_bytes! { + pub struct H1024(256); +} diff --git a/src/chain/byte.rs b/src/chain/byte.rs new file mode 100644 index 00000000..1e42c9d8 --- /dev/null +++ b/src/chain/byte.rs @@ -0,0 +1,156 @@ +#![macro_use] + +/// Doc with expr +#[macro_export] +macro_rules! doc_comment { + ($x:expr, $($tt:tt)*) => { + #[doc = $x] + $($tt)* + }; +} + +/// Convert bytes to hex +#[macro_export] +macro_rules! hex { + ($bytes:expr) => {{ + let mut s = String::new(); + for i in $bytes { + s.push_str(&format!("{:02x}", i)); + } + s + }}; +} + +/// Convert hext to `Vec` or `[u8; n]` +#[macro_export] +macro_rules! bytes { + // Convert hex to Vec + ($hex:expr) => {{ + let mut h = $hex; + if h.starts_with("0x") { + h = &h[2..]; + } + + (0..h.len()) + .step_by(2) + .map(|i| u8::from_str_radix(&h[i..i + 2], 16)) + .collect::, _>>() + .unwrap_or_default() + }}; + + // Convert hex to [u8; $bits] + ($hex:expr, $bits:expr) => {{ + let mut hash = [0_u8; $bits]; + hash.copy_from_slice(&bytes!($hex)); + hash + }}; +} + +/// Serde for big array +#[macro_export] +macro_rules! array { + ($len:expr) => { + impl<'de, T> BigArray<'de> for [T; $len] + where + T: Default + Copy + Serialize + Deserialize<'de>, + { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut seq = serializer.serialize_tuple(self.len())?; + for elem in &self[..] { + seq.serialize_element(elem)?; + } + seq.end() + } + + fn deserialize(deserializer: D) -> Result<[T; $len], D::Error> + where + D: Deserializer<'de>, + { + struct ArrayVisitor { + element: PhantomData, + } + + impl<'de, T> Visitor<'de> for ArrayVisitor + where + T: Default + Copy + Deserialize<'de>, + { + type Value = [T; $len]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(concat!("an array of length ", $len)) + } + + fn visit_seq(self, mut seq: A) -> Result<[T; $len], A::Error> + where + A: SeqAccess<'de>, + { + let mut arr = [T::default(); $len]; + for i in 0..$len { + arr[i] = seq + .next_element()? + .ok_or_else(|| Error::invalid_length(i, &self))?; + } + Ok(arr) + } + } + + let visitor = ArrayVisitor { + element: PhantomData, + }; + deserializer.deserialize_tuple($len, visitor) + } + } + }; +} + +/// Construct hash bytes +#[macro_export] +macro_rules! construct_hash_bytes { + ( $(#[$attr:meta])* $visibility:vis struct $name:ident ( $len:tt ); ) => { + array!($len); + + doc_comment!{ + concat!("The ", stringify!($len), "-bit hash type."), + $(#[$attr])* + #[derive(Decode, Encode, Serialize, Deserialize)] + $visibility struct $name ( + #[serde(with = "BigArray")] + pub [u8; $len] + ); + } + + impl Display for $name { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + f.write_str(&hex!(self.0.as_ref())) + } + } + + impl Debug for $name { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + f.debug_list().entries(self.0.iter()).finish() + } + } + + impl Default for $name { + fn default() -> $name { + $name([0; $len]) + } + } + + impl PartialEq for $name { + fn eq(&self, other: &Self) -> bool { + for i in 0..self.0.len() { + if self.0[i] != other.0[i] { + return false; + } + } + true + } + } + + impl Eq for $name {} + }; +} diff --git a/src/chain/eth/ethash_proof.rs b/src/chain/eth/ethash_proof.rs new file mode 100644 index 00000000..6354fa9d --- /dev/null +++ b/src/chain/eth/ethash_proof.rs @@ -0,0 +1,56 @@ +#![allow(dead_code)] +use crate::{ + chain::array::{H128, H512}, + hex, +}; +use scale::{Decode, Encode}; + +/// Ethash proof +#[derive(Encode, Decode, Debug, PartialEq, Eq, Deserialize, Serialize, Default)] +pub struct EthashProof { + /// Dag nodes + pub dag_nodes: [H512; 2], + /// Merkle Proofs + pub proof: Vec, +} + +impl EthashProof { + /// Generate EthashProof from hex array + pub fn from_tuple(dag_nodes: [&str; 2], proof: [&str; 23]) -> EthashProof { + EthashProof { + dag_nodes: [ + H512(bytes!(dag_nodes[0], 64)), + H512(bytes!(dag_nodes[1], 64)), + ], + proof: proof + .iter() + .map(|s| H128(bytes!(*s, 16))) + .collect::>(), + } + } +} + +/// Json string format of `EthashProof` +#[derive(Serialize)] +pub struct EthashProofJson { + dag_nodes: Vec, + proof: Vec, +} + +impl From<&EthashProof> for EthashProofJson { + fn from(e: &EthashProof) -> EthashProofJson { + EthashProofJson { + dag_nodes: e + .dag_nodes + .as_ref() + .iter() + .map(|n| format!("0x{}", hex!(n.0.to_vec()))) + .collect(), + proof: e + .proof + .iter() + .map(|p| format!("0x{}", hex!(p.0.to_vec()))) + .collect(), + } + } +} diff --git a/src/chain/eth/header.rs b/src/chain/eth/header.rs new file mode 100644 index 00000000..62c3e2a1 --- /dev/null +++ b/src/chain/eth/header.rs @@ -0,0 +1,170 @@ +use crate::{ + chain::array::{H1024, U256}, + hex, + result::Error, +}; +use reqwest::Client; +use scale::{Decode, Encode}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use std::{env, fmt::Debug, str::FromStr}; + +/// Ethereum JSON rpc response +#[derive(Serialize, Deserialize, Debug)] +pub struct EthHeaderRPCResp { + jsonrpc: String, + id: i32, + /// Header Result of RPC + pub result: RawEthHeader, +} + +impl EthHeaderRPCResp { + /// Get `EthHeader` by number + pub async fn get(client: &Client, block: u64) -> Result { + let map: Value = serde_json::from_str(&format! { + "{{{}}}", vec![ + r#""jsonrpc":"2.0","#, + r#""method":"eth_getBlockByNumber","#, + &format!(r#""params":["{:#X}", false],"#, block), + r#""id": 1"#, + ].concat(), + })?; + + Ok(client + .post(&env::var("ETHEREUM_RPC").unwrap_or(crate::conf::DEFAULT_ETHEREUM_RPC.into())) + .json(&map) + .send() + .await? + .json() + .await?) + } +} + +/// Raw EthHeader from Ethereum rpc +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct RawEthHeader { + difficulty: String, + extra_data: String, + gas_limit: String, + gas_used: String, + /// Ethereum header hash + pub hash: String, + logs_bloom: String, + miner: String, + mix_hash: String, + nonce: String, + number: String, + parent_hash: String, + receipts_root: String, + sha3_uncles: String, + size: String, + state_root: String, + timestamp: String, + total_difficulty: String, + transactions: Vec, + transactions_root: String, + uncles: Vec, +} + +impl Into for RawEthHeader { + fn into(self) -> EthHeader { + let seal: Vec> = vec![ + rlp::encode(&bytes!(self.mix_hash.as_str())), + rlp::encode(&bytes!(self.nonce.as_str())), + ]; + EthHeader { + parent_hash: bytes!(self.parent_hash.as_str(), 32), + timestamp: u64::from_str_radix(&self.timestamp.as_str()[2..], 16).unwrap_or_default(), + number: u64::from_str_radix(&self.number.as_str()[2..], 16).unwrap_or_default(), + author: bytes!(self.miner.as_str(), 20), + transactions_root: bytes!(self.transactions_root.as_str(), 32), + uncles_hash: bytes!(self.sha3_uncles.as_str(), 32), + extra_data: bytes!(self.extra_data.as_str()), + state_root: bytes!(self.state_root.as_str(), 32), + receipts_root: bytes!(self.receipts_root.as_str(), 32), + log_bloom: H1024(bytes!(self.logs_bloom.as_str(), 256)), + gas_used: U256::from_str(&self.gas_used[2..]).unwrap_or_default(), + gas_limit: U256::from_str(&self.gas_limit[2..]).unwrap_or_default(), + difficulty: U256::from_str(&self.difficulty[2..]).unwrap_or_default(), + seal: seal, + hash: match self.hash.is_empty() { + true => None, + false => Some(bytes!(self.hash.as_str(), 32)), + }, + } + } +} + +/// Darwinia Eth header +#[derive(Decode, Encode, Debug, PartialEq, Eq, Serialize, Deserialize, Default)] +pub struct EthHeader { + parent_hash: [u8; 32], + timestamp: u64, + number: u64, + author: [u8; 20], + transactions_root: [u8; 32], + uncles_hash: [u8; 32], + extra_data: Vec, + state_root: [u8; 32], + receipts_root: [u8; 32], + log_bloom: H1024, + gas_used: U256, + gas_limit: U256, + difficulty: U256, + seal: Vec>, + hash: Option<[u8; 32]>, +} + +impl EthHeader { + /// Get header + pub async fn get(client: &Client, block: u64) -> Result { + Ok(EthHeaderRPCResp::get(client, block).await?.result.into()) + } +} + +/// Darwinia Eth header Json foramt +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)] +pub struct EthHeaderJson { + parent_hash: String, + timestamp: u64, + number: u64, + author: String, + transactions_root: String, + uncles_hash: String, + extra_data: String, + state_root: String, + receipts_root: String, + log_bloom: String, + gas_used: u128, + gas_limit: u128, + difficulty: u128, + seal: Vec, + hash: String, +} + +impl From for EthHeaderJson { + fn from(e: EthHeader) -> EthHeaderJson { + EthHeaderJson { + parent_hash: format!("0x{}", hex!(e.parent_hash.to_vec())), + timestamp: e.timestamp, + number: e.number, + author: format!("0x{}", hex!(e.author.to_vec())), + transactions_root: format!("0x{}", hex!(e.transactions_root.to_vec())), + uncles_hash: format!("0x{}", hex!(e.uncles_hash.to_vec())), + extra_data: format!("0x{}", hex!(e.extra_data.to_vec())), + state_root: format!("0x{}", hex!(e.state_root.to_vec())), + receipts_root: format!("0x{}", hex!(e.receipts_root.to_vec())), + log_bloom: format!("0x{}", hex!(e.log_bloom.0.to_vec())), + gas_used: e.gas_used.as_u128(), + gas_limit: e.gas_limit.as_u128(), + difficulty: e.difficulty.as_u128(), + seal: e + .seal + .iter() + .map(|s| format!("0x{}", hex!(s.to_vec()))) + .collect(), + hash: format!("0x{}", hex!(e.hash.unwrap_or_default().to_vec())), + } + } +} diff --git a/mmr/bridge/relay.rs b/src/chain/eth/mod.rs similarity index 50% rename from mmr/bridge/relay.rs rename to src/chain/eth/mod.rs index 131f30b0..d5c2f2fa 100644 --- a/mmr/bridge/relay.rs +++ b/src/chain/eth/mod.rs @@ -1,12 +1,19 @@ -//! Relay primitives -use super::{DoubleNodeWithMerkleProof, EthHeader}; +//! ethereum use scale::{Decode, Encode}; +mod ethash_proof; +mod header; + /// Darwinia eth relay header thing #[derive(Decode, Encode, Default)] pub struct HeaderThing { eth_header: EthHeader, - ethash_proof: Vec, + ethash_proof: Vec, mmr_root: [u8; 32], mmr_proof: Vec<[u8; 32]>, } + +pub use self::{ + ethash_proof::{EthashProof, EthashProofJson}, + header::{EthHeader, EthHeaderJson, EthHeaderRPCResp}, +}; diff --git a/src/chain/mod.rs b/src/chain/mod.rs new file mode 100644 index 00000000..c7dc8d1d --- /dev/null +++ b/src/chain/mod.rs @@ -0,0 +1,8 @@ +//! Relayable chains +// macros +mod byte; + +// modules +mod array; +pub mod eth; +pub mod req; diff --git a/src/chain/req.rs b/src/chain/req.rs new file mode 100644 index 00000000..5236fd7a --- /dev/null +++ b/src/chain/req.rs @@ -0,0 +1 @@ +//! Http client diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs new file mode 100644 index 00000000..a0c7c571 --- /dev/null +++ b/src/cmd/mod.rs @@ -0,0 +1,63 @@ +//! `shadow` command +use crate::{api, mmr::helper, pool, result::Error, Runner}; +use structopt::{clap::AppSettings, StructOpt}; + +#[derive(StructOpt)] +#[structopt(setting = AppSettings::InferSubcommands)] +enum Opt { + /// Start shadow service + Run { + /// Http server port + #[structopt(short, long, default_value = "3000")] + port: u16, + /// Verbose mode + #[structopt(short, long)] + verbose: bool, + }, + /// Current block height in mmr store + Count, + /// Trim mmr from target leaf + Trim { + /// The target leaf + #[structopt(short, long)] + leaf: u64, + }, +} + +/// Exec `shadow` binary +pub async fn exec() -> Result<(), Error> { + let conn = pool::conn(None); + let mut runner = Runner::with(conn); + + match Opt::from_args() { + Opt::Run { port, verbose } => { + if let Err(_) = std::env::var("RUST_LOG") { + if verbose { + std::env::set_var("RUST_LOG", "info,shadow"); + } else { + std::env::set_var("RUST_LOG", "info"); + } + } + env_logger::init(); + let (mr, ar) = futures::join!(runner.start(), api::serve(port)); + mr?; + ar?; + } + Opt::Count => { + println!( + "Current best block: {}", + helper::mmr_size_to_last_leaf(runner.mmr_count()?) + ); + } + Opt::Trim { leaf } => { + runner.trim(leaf).unwrap(); + println!("Trimed leaves greater and equal than {}", leaf); + println!( + "Current best block: {}", + helper::mmr_size_to_last_leaf(runner.mmr_count()?) + ); + } + }; + + Ok::<(), Error>(()) +} diff --git a/src/conf.rs b/src/conf.rs new file mode 100644 index 00000000..b2d62657 --- /dev/null +++ b/src/conf.rs @@ -0,0 +1,3 @@ +/// Default Ethereum RPC +pub const DEFAULT_ETHEREUM_RPC: &str = + r#"https://mainnet.infura.io/v3/0bfb9acbb13c426097aabb1d81a9d016"#; diff --git a/src/db/mod.rs b/src/db/mod.rs new file mode 100644 index 00000000..07ed7783 --- /dev/null +++ b/src/db/mod.rs @@ -0,0 +1,4 @@ +pub mod model; +pub mod pool; +pub mod schema; +pub mod sql; diff --git a/mmr/model.rs b/src/db/model.rs similarity index 59% rename from mmr/model.rs rename to src/db/model.rs index 02a6cb33..8d92b5d9 100644 --- a/mmr/model.rs +++ b/src/db/model.rs @@ -20,15 +20,3 @@ impl Header { } } } - -/// MMR Store Result -#[derive(AsChangeset, Clone, Insertable, Queryable, Debug, Default)] -#[table_name = "eth_header_with_proof_caches"] -pub struct Cache { - /// MMR Cache Hash - pub hash: String, - /// MMR Result Number - pub number: i64, - /// MMR Result Root - pub root: Option, -} diff --git a/mmr/pool.rs b/src/db/pool.rs similarity index 95% rename from mmr/pool.rs rename to src/db/pool.rs index d4f5bc6a..070effa2 100644 --- a/mmr/pool.rs +++ b/src/db/pool.rs @@ -30,7 +30,7 @@ pub fn conn(p: Option) -> ConnPool { } } - info!("Connecting database {:?}...", &path); + // info!("Connecting database {:?}...", &path); Builder::new() .max_size(100) .build(ConnectionManager::::new( diff --git a/src/db/schema.rs b/src/db/schema.rs new file mode 100644 index 00000000..0bffef0e --- /dev/null +++ b/src/db/schema.rs @@ -0,0 +1,9 @@ +//! Data schemas +#![allow(missing_docs)] + +table! { + mmr_store(pos) { + elem -> Text, + pos -> BigInt, + } +} diff --git a/mmr/sql.rs b/src/db/sql.rs similarity index 100% rename from mmr/sql.rs rename to src/db/sql.rs diff --git a/mmr/lib.rs b/src/lib.rs similarity index 61% rename from mmr/lib.rs rename to src/lib.rs index 0ba5d17a..6d0de288 100644 --- a/mmr/lib.rs +++ b/src/lib.rs @@ -10,18 +10,18 @@ extern crate diesel; #[macro_use] extern crate log; +#[macro_use] +extern crate serde; -mod ffi; -mod model; +mod conf; +mod db; +mod mmr; mod result; -mod runner; -mod schema; -mod sql; - -pub mod bridge; -pub mod hash; -pub mod helper; -pub mod pool; -pub mod store; -pub use runner::Runner; +pub mod api; +pub mod chain; +pub mod cmd; +pub use self::{ + db::{model, pool, schema, sql}, + mmr::{hash, helper, runner::Runner, store}, +}; diff --git a/mmr/hash.rs b/src/mmr/hash.rs similarity index 100% rename from mmr/hash.rs rename to src/mmr/hash.rs diff --git a/mmr/helper.rs b/src/mmr/helper.rs similarity index 99% rename from mmr/helper.rs rename to src/mmr/helper.rs index 557d8a5d..e8743b69 100644 --- a/mmr/helper.rs +++ b/src/mmr/helper.rs @@ -1,5 +1,4 @@ //! Helper fns - use std::cmp::Ordering; fn log2_floor(mut num: i64) -> i64 { diff --git a/src/mmr/mod.rs b/src/mmr/mod.rs new file mode 100644 index 00000000..16f4b031 --- /dev/null +++ b/src/mmr/mod.rs @@ -0,0 +1,4 @@ +pub mod hash; +pub mod helper; +pub mod runner; +pub mod store; diff --git a/src/mmr/runner.rs b/src/mmr/runner.rs new file mode 100644 index 00000000..bdd38d71 --- /dev/null +++ b/src/mmr/runner.rs @@ -0,0 +1,112 @@ +//! MMR Runner +use crate::{ + chain::eth::EthHeaderRPCResp, + hash::{MergeHash, H256}, + helper, + pool::{ConnPool, PooledConn}, + result::Error, + schema::mmr_store::dsl::*, + store::Store, +}; +use cmmr::MMR; +use diesel::{dsl::count, prelude::*}; +use reqwest::Client; +use std::time; + +/// MMR Runner +#[derive(Clone)] +pub struct Runner { + store: Store, + pool: ConnPool, + client: Client, +} + +impl Runner { + /// Get Pooled connection + pub fn conn(&self) -> Result { + let cfp = self.pool.get(); + if cfp.is_err() { + return Err(Error::Custom("Connect to database failed".into())); + } + + Ok(cfp.unwrap()) + } + + /// Start with sqlite3 conn + pub fn with(pool: ConnPool) -> Runner { + let store = Store::with(pool.clone()); + Runner { + store, + pool, + client: Client::new(), + } + } + + /// Start the runner + pub async fn start(&mut self) -> Result<(), Error> { + let mut ptr = { + let last_leaf = helper::mmr_size_to_last_leaf(self.mmr_count()?); + if last_leaf == 0 { + 0 + } else { + last_leaf + 1 + } + }; + + loop { + if let Err(e) = self.push(ptr).await { + error!("Push block to mmr_store failed: {:?}", e); + trace!("MMR service restarting after 10s..."); + async_std::task::sleep(time::Duration::from_secs(10)).await; + } else { + ptr += 1; + } + } + } + + /// Get block hash by number + pub async fn get_hash(&mut self, block: i64) -> Result { + Ok(EthHeaderRPCResp::get(&self.client, block as u64) + .await? + .result + .hash) + } + + /// Trim mmr + pub fn trim(&mut self, leaf: u64) -> Result<(), Error> { + let mpos = cmmr::leaf_index_to_pos(leaf); + let conn = self.conn()?; + diesel::delete(mmr_store.filter(pos.ge(mpos as i64))).execute(&conn)?; + Ok(()) + } + + /// Push new header hash into storage + pub async fn push(&mut self, pnumber: i64) -> Result<(), Error> { + let mut mmr = MMR::<_, MergeHash, _>::new( + cmmr::leaf_index_to_mmr_size((pnumber - 1) as u64), + &self.store, + ); + if let Err(e) = mmr.push(H256::from( + &EthHeaderRPCResp::get(&self.client, pnumber as u64) + .await? + .result + .hash, + )) { + return Err(Error::MMR(e)); + } + + mmr.commit()?; + Ok(()) + } + + /// Get the count of mmr store + pub fn mmr_count(&self) -> Result { + let conn = self.conn()?; + let res = mmr_store.select(count(elem)).first::(&conn); + if let Err(e) = res { + Err(Error::Diesel(e)) + } else { + Ok(res?) + } + } +} diff --git a/mmr/store.rs b/src/mmr/store.rs similarity index 95% rename from mmr/store.rs rename to src/mmr/store.rs index 6dc43f90..124ddf44 100644 --- a/mmr/store.rs +++ b/src/mmr/store.rs @@ -1,5 +1,5 @@ //! MMR store -use super::{hash::H256, model::*, pool::ConnPool, schema::mmr_store::dsl::*, sql::*}; +use crate::{hash::H256, model::*, pool::ConnPool, schema::mmr_store::dsl::*, sql::*}; use cmmr::{Error, MMRStore, Result as MMRResult}; use diesel::{dsl::count, prelude::*}; @@ -24,7 +24,7 @@ impl Store { } } -impl MMRStore for Store +impl MMRStore for &Store where H: H256, { diff --git a/src/result.rs b/src/result.rs new file mode 100644 index 00000000..f30cf637 --- /dev/null +++ b/src/result.rs @@ -0,0 +1,53 @@ +//! MMR Errors +use cmmr::Error as MMRError; +use diesel::result::Error as DieselError; +use reqwest::Error as ReqwestError; +use serde_json::Error as SerdeJSONError; +use std::io::Error as IoError; + +/// MMR Errors +#[derive(Debug)] +pub enum Error { + /// Diesel Error + Diesel(DieselError), + /// Io Error + Io(IoError), + /// MMR Error + MMR(MMRError), + /// Reqwest Error + Reqwest(ReqwestError), + /// Reqwest Error + SerdeJSON(SerdeJSONError), + /// Custom + Custom(String), +} + +impl From for Error { + fn from(e: MMRError) -> Error { + Error::MMR(e) + } +} + +impl From for Error { + fn from(e: IoError) -> Error { + Error::Io(e) + } +} + +impl From for Error { + fn from(e: DieselError) -> Error { + Error::Diesel(e) + } +} + +impl From for Error { + fn from(e: ReqwestError) -> Error { + Error::Reqwest(e) + } +} + +impl From for Error { + fn from(e: SerdeJSONError) -> Error { + Error::SerdeJSON(e) + } +} diff --git a/tests/mmr.rs b/tests/mmr.rs index 69bfde0f..68f40c30 100644 --- a/tests/mmr.rs +++ b/tests/mmr.rs @@ -1,5 +1,5 @@ use cmmr::{Merge, MMR}; -use mmr::{ +use shadow::{ hash::{MergeHash, H256}, helper, pool, store::Store, @@ -51,12 +51,12 @@ const HEADERS_N_ROOTS: [(&str, &str); 10] = [ fn gen_mmr(db: &PathBuf, f: F) where - F: Fn(MMR<[u8; 32], MergeHash, Store>, Vec), + F: Fn(MMR<[u8; 32], MergeHash, &Store>, Vec), { let db = env::temp_dir().join(db); let conn = pool::conn(Some(db)); let store = Store::with(conn); - let mut mmr = MMR::<_, MergeHash, _>::new(0, store); + let mut mmr = MMR::<_, MergeHash, _>::new(0, &store); let pos: Vec = (0..10) .map(|h| { mmr.push(<[u8; 32] as H256>::from(HEADERS_N_ROOTS[h].0)) diff --git a/tests/mock/mod.rs b/tests/mock/mod.rs index 028fd67d..46c1efdd 100644 --- a/tests/mock/mod.rs +++ b/tests/mock/mod.rs @@ -11,9 +11,11 @@ pub use hash::HASHES; pub use header::HEADER; pub use header_thing::ETH_HEADER_THING; pub use mock_header_19::MOCK_HEADER_19; +use scale::Decode; -use mmr::{ - bridge::{DoubleNodeWithMerkleProof, EthHeader}, +use shadow::{ + bytes, + chain::eth::{EthHeader, EthashProof}, hash::H256, }; @@ -26,27 +28,10 @@ pub fn ha() -> [[u8; 32]; 10] { /// Block Number ffi ports pub fn header() -> EthHeader { - EthHeader::from_go_ffi( - "0x0000000000000000000000000000000000000000000000000000000000000000", - 0, - 0, - "0x0000000000000000000000000000000000000000", - "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", - "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544", - "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "0", - "5000", - "17179869184", - "0xa00000000000000000000000000000000000000000000000000000000000000000", - "0x880000000000000042", - "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", - ) + EthHeader::decode(&mut bytes!("0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4211dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493478011bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fad7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f054456e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000881300000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000884a000000000000000000000000000000000000000000000000000000000000000002488000000000000004201d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3").as_ref()).unwrap() } /// Generate DoubleNodeWithMerkleProof -pub fn proof() -> DoubleNodeWithMerkleProof { - DoubleNodeWithMerkleProof::from_tuple(DAG_NODES, PROOF) +pub fn proof() -> EthashProof { + EthashProof::from_tuple(DAG_NODES, PROOF) } diff --git a/tests/scale.rs b/tests/scale.rs index 2853ecaf..53a181af 100644 --- a/tests/scale.rs +++ b/tests/scale.rs @@ -1,11 +1,12 @@ mod mock; -use mmr::{ - bridge::{DoubleNodeWithMerkleProof, EthHeader, HeaderThing}, - bytes, hex, -}; use mock::{ha, header, proof, ETHASH_PROOF_CODEC, ETH_HEADER_THING, HEADER, MOCK_HEADER_19}; use scale::{Decode, Encode}; +use shadow::{ + bytes, + chain::eth::{EthHeader, EthashProof, HeaderThing}, + hex, +}; /// the scale codec of hash is its hex string #[test] @@ -62,8 +63,7 @@ fn decode_mmr_proof() { #[test] fn eth_hash_proof() { - let block = - >::decode(&mut bytes!(ETHASH_PROOF_CODEC).as_ref()).unwrap(); + let block = >::decode(&mut bytes!(ETHASH_PROOF_CODEC).as_ref()).unwrap(); assert_eq!(block[block.len() - 1], proof()); } From 744e8c563f3b77075534b5b09df28392e811cbbc Mon Sep 17 00:00:00 2001 From: clearloop Date: Thu, 27 Aug 2020 13:58:55 +0800 Subject: [PATCH 02/36] feat(eth): supports default ropsten rpc --- pkg/internal/config.go | 11 ++++++----- src/chain/eth/header.rs | 8 +++++++- src/conf.rs | 4 ++++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/pkg/internal/config.go b/pkg/internal/config.go index f515352f..c406e4d8 100644 --- a/pkg/internal/config.go +++ b/pkg/internal/config.go @@ -9,10 +9,11 @@ import ( ) const ( - ETHEREUM_RPC = "ETHEREUM_RPC" - SHADOW_GENESIS = "SHADOW_GENESIS" - GETH_DATADIR = "GETH_DATADIR" - DEFAULT_ETHEREUM_RPC = "https://mainnet.infura.io/v3/0bfb9acbb13c426097aabb1d81a9d016" + ETHEREUM_ROPSTEN string = "ETHEREUM_ROPSTEN" + ETHEREUM_RPC string = "ETHEREUM_RPC" + SHADOW_GENESIS string = "SHADOW_GENESIS" + GETH_DATADIR string = "GETH_DATADIR" + DEFAULT_ETHEREUM_RPC string = "https://mainnet.infura.io/v3/0bfb9acbb13c426097aabb1d81a9d016" ) type RawConfig struct { @@ -48,7 +49,7 @@ func (c *Config) Load() error { // Load api from env c.Api = os.Getenv(ETHEREUM_RPC) - if c.Api == "" { + if c.Api == "" && os.Getenv(ETHEREUM_ROPSTEN) == "" { c.Api = DEFAULT_ETHEREUM_RPC } diff --git a/src/chain/eth/header.rs b/src/chain/eth/header.rs index 62c3e2a1..836cff4e 100644 --- a/src/chain/eth/header.rs +++ b/src/chain/eth/header.rs @@ -31,7 +31,13 @@ impl EthHeaderRPCResp { })?; Ok(client - .post(&env::var("ETHEREUM_RPC").unwrap_or(crate::conf::DEFAULT_ETHEREUM_RPC.into())) + .post(&env::var("ETHEREUM_RPC").unwrap_or_else(|_| { + if env::var("ETHEREUM_ROPSTEN").is_ok() { + crate::conf::DEFAULT_ETHEREUM_ROPSTEN_RPC.into() + } else { + crate::conf::DEFAULT_ETHEREUM_RPC.into() + } + })) .json(&map) .send() .await? diff --git a/src/conf.rs b/src/conf.rs index b2d62657..083424b3 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -1,3 +1,7 @@ /// Default Ethereum RPC pub const DEFAULT_ETHEREUM_RPC: &str = r#"https://mainnet.infura.io/v3/0bfb9acbb13c426097aabb1d81a9d016"#; + +/// Default Ethereum Ropsten RPC +pub const DEFAULT_ETHEREUM_ROPSTEN_RPC: &str = + r#"https://ropsten.infura.io/v3/0bfb9acbb13c426097aabb1d81a9d016"#; From 8255db7f89875280637e88d74936c3ff562f7382 Mon Sep 17 00:00:00 2001 From: clearloop Date: Thu, 27 Aug 2020 14:08:06 +0800 Subject: [PATCH 03/36] chore(tests): remove optional deps --- Cargo.toml | 9 --------- tests/scale.rs | 29 ----------------------------- 2 files changed, 38 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 46275b3e..c2d86fd9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,12 +38,3 @@ features = ["derive"] [dependencies.diesel] version = "1.4.4" features = ["r2d2", "sqlite"] - -[dependencies.eth] -git = "https://github.com/darwinia-network/darwinia-common.git" -package = "ethereum-primitives" -optional = true - -[features] -darwinia = [ "eth" ] -default = [] \ No newline at end of file diff --git a/tests/scale.rs b/tests/scale.rs index 53a181af..0fd808b0 100644 --- a/tests/scale.rs +++ b/tests/scale.rs @@ -66,32 +66,3 @@ fn eth_hash_proof() { let block = >::decode(&mut bytes!(ETHASH_PROOF_CODEC).as_ref()).unwrap(); assert_eq!(block[block.len() - 1], proof()); } - -#[test] -#[cfg(feature = "darwinia")] -fn darwinia_eth_header() { - use eth::header::EthHeader as DEthHeader; - - let header = header(); - let encoded = format!("0x{}", hex!(header.encode())); - - assert_eq!(HEADER, encoded); - assert_eq!( - EthHeader::default().encode(), - DEthHeader::default().encode() - ); - - assert_eq!( - header, - EthHeader::decode(&mut bytes!(encoded.as_str()).as_ref()).unwrap() - ); - - assert_eq!( - EthHeader::decode(&mut bytes!(encoded.as_str()).as_ref()) - .unwrap() - .encode(), - DEthHeader::decode(&mut bytes!(encoded.as_str()).as_ref()) - .unwrap() - .encode() - ); -} From 5e86fec7b85f7e5f3f774e108f4f05f10e9f1158 Mon Sep 17 00:00:00 2001 From: clearloop Date: Thu, 27 Aug 2020 14:14:54 +0800 Subject: [PATCH 04/36] chore(crate): renamme package name to darwinia-shadow --- Cargo.toml | 4 ++-- examples/doctor.rs | 2 +- examples/header.rs | 2 +- examples/runner.rs | 4 ++-- examples/uncle.rs | 2 +- src/bin/shadow.rs | 2 +- tests/mmr.rs | 2 +- tests/mock/mod.rs | 2 +- tests/scale.rs | 6 +++--- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c2d86fd9..bf974b3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "shadow" -version = "0.1.0" +name = "darwinia-shadow" +version = "0.0.1" authors = ["clearloop "] edition = "2018" diff --git a/examples/doctor.rs b/examples/doctor.rs index 3b6a8b37..9264fc20 100644 --- a/examples/doctor.rs +++ b/examples/doctor.rs @@ -1,6 +1,6 @@ //! Mock the uncle block use cmmr::{leaf_index_to_mmr_size, MMR}; -use shadow::{ +use darwinia_shadow::{ hash::{MergeHash, H256}, pool, store::Store, diff --git a/examples/header.rs b/examples/header.rs index 377426ab..12239a35 100644 --- a/examples/header.rs +++ b/examples/header.rs @@ -1,4 +1,4 @@ -use shadow::chain::eth::{EthHeader, EthHeaderRPCResp}; +use darwinia_shadow::chain::eth::{EthHeader, EthHeaderRPCResp}; fn main() { let client = reqwest::Client::new(); diff --git a/examples/runner.rs b/examples/runner.rs index effebad0..6cb61b67 100644 --- a/examples/runner.rs +++ b/examples/runner.rs @@ -1,8 +1,8 @@ -use shadow::Runner; +use darwinia_shadow::{pool, Runner}; fn main() { env_logger::init(); - let conn = shadow::pool::conn(None); + let conn = pool::conn(None); let mut runner = Runner::with(conn); async_std::task::block_on(runner.start()).unwrap(); } diff --git a/examples/uncle.rs b/examples/uncle.rs index 780e31e2..045f999c 100644 --- a/examples/uncle.rs +++ b/examples/uncle.rs @@ -1,6 +1,6 @@ //! Mock the uncle block use cmmr::MMR; -use shadow::{ +use darwinia_shadow::{ hash::{MergeHash, H256}, pool, store::Store, diff --git a/src/bin/shadow.rs b/src/bin/shadow.rs index 0658e90e..8d18a6df 100644 --- a/src/bin/shadow.rs +++ b/src/bin/shadow.rs @@ -1,4 +1,4 @@ #[actix_rt::main] async fn main() { - shadow::cmd::exec().await.unwrap(); + darwinia_shadow::cmd::exec().await.unwrap(); } diff --git a/tests/mmr.rs b/tests/mmr.rs index 68f40c30..d64cb50c 100644 --- a/tests/mmr.rs +++ b/tests/mmr.rs @@ -1,5 +1,5 @@ use cmmr::{Merge, MMR}; -use shadow::{ +use darwinia_shadow::{ hash::{MergeHash, H256}, helper, pool, store::Store, diff --git a/tests/mock/mod.rs b/tests/mock/mod.rs index 46c1efdd..62e7789e 100644 --- a/tests/mock/mod.rs +++ b/tests/mock/mod.rs @@ -13,7 +13,7 @@ pub use header_thing::ETH_HEADER_THING; pub use mock_header_19::MOCK_HEADER_19; use scale::Decode; -use shadow::{ +use darwinia_shadow::{ bytes, chain::eth::{EthHeader, EthashProof}, hash::H256, diff --git a/tests/scale.rs b/tests/scale.rs index 0fd808b0..a6634707 100644 --- a/tests/scale.rs +++ b/tests/scale.rs @@ -1,12 +1,12 @@ mod mock; -use mock::{ha, header, proof, ETHASH_PROOF_CODEC, ETH_HEADER_THING, HEADER, MOCK_HEADER_19}; -use scale::{Decode, Encode}; -use shadow::{ +use darwinia_shadow::{ bytes, chain::eth::{EthHeader, EthashProof, HeaderThing}, hex, }; +use mock::{ha, header, proof, ETHASH_PROOF_CODEC, ETH_HEADER_THING, HEADER, MOCK_HEADER_19}; +use scale::{Decode, Encode}; /// the scale codec of hash is its hex string #[test] From a3b2f49b9b5a0a29a4f0e9c58ea666c313ee0750 Mon Sep 17 00:00:00 2001 From: clearloop Date: Thu, 27 Aug 2020 14:16:59 +0800 Subject: [PATCH 05/36] feat(lib): add readme to lib.rs --- Cargo.toml | 14 +++++++++++++ build.rs | 21 +++++++++++-------- src/lib.rs | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 86 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bf974b3b..31332d3c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,20 @@ name = "darwinia-shadow" version = "0.0.1" authors = ["clearloop "] edition = "2018" +description = "The shadow service for relayers and verify workers to retrieve header data and generate proof. Shadow will index the data it needs from blockchain nodes, such as Ethereum and Darwinia." +repository = "https://github.com/darwinia-network/shadow" +license = "GPL" +documentation = "https://docs.rs/darwinia-shadow" +homepage = "https://github.com/darwinia-network/shadow" +include = [ + "build.rs", + "pkg/**/*", + "src/**/*", + "Cargo.toml", + "./README.md", +] +keywords = ["darwinia", "substrate", "service"] +readme = './README.md' [[bin]] name = "shadow" diff --git a/build.rs b/build.rs index 2f30ea77..d57c4b74 100644 --- a/build.rs +++ b/build.rs @@ -1,6 +1,11 @@ -use std::process::Command; +use std::{env, process::Command}; fn main() { + // pre-check + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=path/to/Cargo.lock"); + + // main let os = Command::new("uname").output().unwrap(); let ext = match String::from_utf8_lossy(os.stdout.as_slice()) .into_owned() @@ -11,12 +16,11 @@ fn main() { _ => "so", }; - let profile = match std::env::var("PROFILE").unwrap().as_str() { - "release" => "release", - _ => "debug", - }; - - let lib = format!("target/{}/libeth.{}", profile, ext); + let out_dir = env::var_os("OUT_DIR") + .unwrap() + .to_string_lossy() + .to_string(); + let lib = format!("{}/libeth.{}", out_dir, ext); Command::new("go") .args(&[ "build", @@ -28,5 +32,6 @@ fn main() { .status() .unwrap(); - println!(r"cargo:rustc-link-search=target/debug"); + // post-check + println!("cargo:rustc-link-search={}", out_dir); } diff --git a/src/lib.rs b/src/lib.rs index 6d0de288..d293cc9d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,62 @@ -//! Darwinia MMR Implementation +//! # Shadow +//! +//! [![Golang CI][workflow-badge]][github] +//! +//! The shadow service for relayers and verify workers to retrieve header data and generate proof. Shadow will index the data it needs from blockchain nodes, such as Ethereum and Darwinia. +//! +//! ## Usage +//! +//! ```text +//! shadow 0.1.0 +//! +//! USAGE: +//! shadow +//! +//! FLAGS: +//! -h, --help Prints help information +//! -V, --version Prints version information +//! +//! SUBCOMMANDS: +//! count Current block height in mmr store +//! help Prints this message or the help of the given subcommand(s) +//! run Start shadow service +//! trim Trim mmr from target leaf +//! ``` +//! +//! ## Contribute and Build +//! +//! Downloads shadow service +//! +//! ```text +//! git clone https://github.com/darwinia-network/shadow.git +//! ``` +//! +//! Starts shadow service: +//! +//! ```text +//! # Starts shadow serives at port 3000 +//! $ cargo run -p 3000 +//! +//! # If you have fast eth node: +//! $ ETHEREUM_RPC= cargo run -p 3000 +//! ``` +//! +//! ## Trouble Shooting +//! +//! Everytime you run `proof` in error, please delete `~/.ethashproof` and `~/.ethash` +//! and retry. +//! +//! ## LICENSE +//! +//! GPL-3.0 +//! +//! +//! [infura]: https://infura.io +//! [github]: https://github.com/darwinia-network/shadow +//! [spec]: https://github.com/darwinia-network/darwinia/wiki/Darwinia-offchain-worker-shadow-service-spec +//! [workflow-badge]: https://github.com/darwinia-network/shadow/workflows/Golang%20CI/badge.svg +//! [api]: https://darwinia-network.github.io/shadow + #![warn(missing_docs)] #![allow(clippy::transmute_ptr_to_ptr)] #![allow(clippy::ptr_offset_with_cast)] From c6e20048136e7b00f1ac59f7e35b148ec1f79ff9 Mon Sep 17 00:00:00 2001 From: clearloop Date: Thu, 27 Aug 2020 15:26:51 +0800 Subject: [PATCH 06/36] fix(go): rename internal pkg to shadow --- .github/workflows/mmr.yml | 2 +- Cargo.toml | 2 +- README.md | 25 ++++++------------ build.rs | 3 ++- pkg/{internal => shadow}/config.go | 4 +-- pkg/{internal => shadow}/eth/api.go | 0 pkg/{internal => shadow}/eth/header.go | 6 ++--- pkg/{internal => shadow}/eth/mock.go | 2 +- pkg/{internal => shadow}/eth/proof.go | 18 ++++++------- pkg/{internal => shadow}/eth/receipt.go | 6 ++--- pkg/{internal => shadow}/eth/scale.go | 0 pkg/{internal => shadow}/eth/types.go | 0 pkg/{internal => shadow}/ffi/mod.go | 6 ++--- pkg/{internal => shadow}/lock.go | 2 +- pkg/{internal => shadow}/log/mod.go | 0 pkg/{internal => shadow}/util/assert.go | 2 +- pkg/{internal => shadow}/util/collection.go | 0 pkg/{internal => shadow}/util/encode.go | 0 src/lib.rs | 28 +++++++-------------- 19 files changed, 44 insertions(+), 62 deletions(-) rename pkg/{internal => shadow}/config.go (94%) rename pkg/{internal => shadow}/eth/api.go (100%) rename pkg/{internal => shadow}/eth/header.go (93%) rename pkg/{internal => shadow}/eth/mock.go (94%) rename pkg/{internal => shadow}/eth/proof.go (89%) rename pkg/{internal => shadow}/eth/receipt.go (97%) rename pkg/{internal => shadow}/eth/scale.go (100%) rename pkg/{internal => shadow}/eth/types.go (100%) rename pkg/{internal => shadow}/ffi/mod.go (80%) rename pkg/{internal => shadow}/lock.go (98%) rename pkg/{internal => shadow}/log/mod.go (100%) rename pkg/{internal => shadow}/util/assert.go (89%) rename pkg/{internal => shadow}/util/collection.go (100%) rename pkg/{internal => shadow}/util/encode.go (100%) diff --git a/.github/workflows/mmr.yml b/.github/workflows/mmr.yml index 51eed335..67c5e850 100644 --- a/.github/workflows/mmr.yml +++ b/.github/workflows/mmr.yml @@ -1,4 +1,4 @@ -name: Rust MMR +name: shadow on: push: diff --git a/Cargo.toml b/Cargo.toml index 31332d3c..934d19dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ authors = ["clearloop "] edition = "2018" description = "The shadow service for relayers and verify workers to retrieve header data and generate proof. Shadow will index the data it needs from blockchain nodes, such as Ethereum and Darwinia." repository = "https://github.com/darwinia-network/shadow" -license = "GPL" +license = "GPL-3.0-or-later" documentation = "https://docs.rs/darwinia-shadow" homepage = "https://github.com/darwinia-network/shadow" include = [ diff --git a/README.md b/README.md index 7a86ad64..5219602f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Shadow -[![Golang CI][workflow-badge]][github] +[![Shadow][workflow-badge]][github] The shadow service for relayers and verify workers to retrieve header data and generate proof. Shadow will index the data it needs from blockchain nodes, such as Ethereum and Darwinia. @@ -23,23 +23,17 @@ SUBCOMMANDS: trim Trim mmr from target leaf ``` -## Contribute and Build +## Download -Downloads shadow service - -``` -git clone https://github.com/darwinia-network/shadow.git +```sh +$ cargo install darwinia-shadow ``` -Starts shadow service: +### Note -``` -# Starts shadow serives at port 3000 -$ cargo run -p 3000 ++ Please make sure you have golang installed in your machine ++ Please make sure you have installed the sqlite3 library in your machine -# If you have fast eth node: -$ ETHEREUM_RPC= cargo run -p 3000 -``` ## Trouble Shooting @@ -51,8 +45,5 @@ and retry. GPL-3.0 -[infura]: https://infura.io [github]: https://github.com/darwinia-network/shadow -[spec]: https://github.com/darwinia-network/darwinia/wiki/Darwinia-offchain-worker-shadow-service-spec -[workflow-badge]: https://github.com/darwinia-network/shadow/workflows/Golang%20CI/badge.svg -[api]: https://darwinia-network.github.io/shadow +[workflow-badge]: https://github.com/darwinia-network/shadow/workflows/shadow/badge.svg diff --git a/build.rs b/build.rs index d57c4b74..4a403fcc 100644 --- a/build.rs +++ b/build.rs @@ -27,11 +27,12 @@ fn main() { "-o", &lib, "-buildmode=c-shared", - "pkg/internal/ffi/mod.go", + "pkg/shadow/ffi/mod.go", ]) .status() .unwrap(); // post-check + println!("cargo:rustc-link-lib=eth"); println!("cargo:rustc-link-search={}", out_dir); } diff --git a/pkg/internal/config.go b/pkg/shadow/config.go similarity index 94% rename from pkg/internal/config.go rename to pkg/shadow/config.go index c406e4d8..8ab47cd5 100644 --- a/pkg/internal/config.go +++ b/pkg/shadow/config.go @@ -1,11 +1,11 @@ -package internal +package shadow import ( "os" "path/filepath" "strconv" - "github.com/darwinia-network/shadow/pkg/internal/util" + "github.com/darwinia-network/shadow/pkg/shadow/util" ) const ( diff --git a/pkg/internal/eth/api.go b/pkg/shadow/eth/api.go similarity index 100% rename from pkg/internal/eth/api.go rename to pkg/shadow/eth/api.go diff --git a/pkg/internal/eth/header.go b/pkg/shadow/eth/header.go similarity index 93% rename from pkg/internal/eth/header.go rename to pkg/shadow/eth/header.go index f29623df..09e180d0 100644 --- a/pkg/internal/eth/header.go +++ b/pkg/shadow/eth/header.go @@ -7,7 +7,7 @@ import ( "net/http" "strings" - "github.com/darwinia-network/shadow/pkg/internal" + "github.com/darwinia-network/shadow/pkg/shadow" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" @@ -30,7 +30,7 @@ func Header(block uint64, api string) (types.Header, error) { if err != nil { if !strings.Contains(api, "infura") { - return Header(block, internal.DEFAULT_ETHEREUM_RPC) + return Header(block, shadow.DEFAULT_ETHEREUM_RPC) } return infuraResp.Result, err } @@ -40,7 +40,7 @@ func Header(block uint64, api string) (types.Header, error) { err = json.NewDecoder(resp.Body).Decode(&infuraResp) if err != nil { if !strings.Contains(api, "infura") { - return Header(block, internal.DEFAULT_ETHEREUM_RPC) + return Header(block, shadow.DEFAULT_ETHEREUM_RPC) } return infuraResp.Result, err } diff --git a/pkg/internal/eth/mock.go b/pkg/shadow/eth/mock.go similarity index 94% rename from pkg/internal/eth/mock.go rename to pkg/shadow/eth/mock.go index bbfd4e3f..157bcac2 100644 --- a/pkg/internal/eth/mock.go +++ b/pkg/shadow/eth/mock.go @@ -7,7 +7,7 @@ import ( "reflect" "strings" - "github.com/darwinia-network/shadow/pkg/internal/log" + "github.com/darwinia-network/shadow/pkg/shadow/log" "github.com/ethereum/go-ethereum/core/types" ) diff --git a/pkg/internal/eth/proof.go b/pkg/shadow/eth/proof.go similarity index 89% rename from pkg/internal/eth/proof.go rename to pkg/shadow/eth/proof.go index d3da4a04..7018360a 100644 --- a/pkg/internal/eth/proof.go +++ b/pkg/shadow/eth/proof.go @@ -10,8 +10,8 @@ import ( "github.com/darwinia-network/shadow/pkg/ethashproof" "github.com/darwinia-network/shadow/pkg/ethashproof/ethash" "github.com/darwinia-network/shadow/pkg/ethashproof/mtree" - "github.com/darwinia-network/shadow/pkg/internal" - "github.com/darwinia-network/shadow/pkg/internal/util" + "github.com/darwinia-network/shadow/pkg/shadow" + "github.com/darwinia-network/shadow/pkg/shadow/util" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" ) @@ -65,15 +65,15 @@ func (o *ProofOutput) Format() []DoubleNodeWithMerkleProof { } // Epoch in background -func bgEpoch(epoch uint64, config *internal.Config) { +func bgEpoch(epoch uint64, config *shadow.Config) { _, _ = ethashproof.CalculateDatasetMerkleRoot(epoch, true) - _ = config.RemoveLock(internal.EPOCH_LOCK) + _ = config.RemoveLock(shadow.EPOCH_LOCK) } // Check if need epoch -func epochGently(epoch uint64, config *internal.Config) error { +func epochGently(epoch uint64, config *shadow.Config) error { // Check if is epoching - if config.CheckLock(internal.EPOCH_LOCK) { + if config.CheckLock(shadow.EPOCH_LOCK) { return nil } @@ -99,7 +99,7 @@ func epochGently(epoch uint64, config *internal.Config) error { } // Create epoch lock - err = config.CreateLock(internal.EPOCH_LOCK) + err = config.CreateLock(shadow.EPOCH_LOCK) if err != nil { return err } @@ -113,7 +113,7 @@ func epochGently(epoch uint64, config *internal.Config) error { } // Proof eth blockheader -func Proof(header *types.Header, config *internal.Config) (ProofOutput, error) { +func Proof(header *types.Header, config *shadow.Config) (ProofOutput, error) { blockno := header.Number.Uint64() epoch := blockno / 30000 output := &ProofOutput{} @@ -121,7 +121,7 @@ func Proof(header *types.Header, config *internal.Config) (ProofOutput, error) { // Get proof from cache cache, err := ethashproof.LoadCache(int(epoch)) if err != nil { - err = config.RemoveLock(internal.EPOCH_LOCK) + err = config.RemoveLock(shadow.EPOCH_LOCK) if err != nil { return *output, err } diff --git a/pkg/internal/eth/receipt.go b/pkg/shadow/eth/receipt.go similarity index 97% rename from pkg/internal/eth/receipt.go rename to pkg/shadow/eth/receipt.go index b3844fd8..8b9bd168 100644 --- a/pkg/internal/eth/receipt.go +++ b/pkg/shadow/eth/receipt.go @@ -8,8 +8,8 @@ import ( "strings" "sync" - "github.com/darwinia-network/shadow/pkg/internal" - "github.com/darwinia-network/shadow/pkg/internal/util" + "github.com/darwinia-network/shadow/pkg/shadow" + "github.com/darwinia-network/shadow/pkg/shadow/util" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" @@ -28,7 +28,7 @@ var ( ) func init() { - conf := new(internal.Config) + conf := new(shadow.Config) _ = conf.Load() API = conf.Api } diff --git a/pkg/internal/eth/scale.go b/pkg/shadow/eth/scale.go similarity index 100% rename from pkg/internal/eth/scale.go rename to pkg/shadow/eth/scale.go diff --git a/pkg/internal/eth/types.go b/pkg/shadow/eth/types.go similarity index 100% rename from pkg/internal/eth/types.go rename to pkg/shadow/eth/types.go diff --git a/pkg/internal/ffi/mod.go b/pkg/shadow/ffi/mod.go similarity index 80% rename from pkg/internal/ffi/mod.go rename to pkg/shadow/ffi/mod.go index 5595ef90..26bd2239 100644 --- a/pkg/internal/ffi/mod.go +++ b/pkg/shadow/ffi/mod.go @@ -2,12 +2,12 @@ package main import "C" import ( - "github.com/darwinia-network/shadow/pkg/internal" - "github.com/darwinia-network/shadow/pkg/internal/eth" + "github.com/darwinia-network/shadow/pkg/shadow" + "github.com/darwinia-network/shadow/pkg/shadow/eth" ) var ( - CONFIG internal.Config = internal.Config{} + CONFIG shadow.Config = shadow.Config{} ) func init() { diff --git a/pkg/internal/lock.go b/pkg/shadow/lock.go similarity index 98% rename from pkg/internal/lock.go rename to pkg/shadow/lock.go index 71ade50e..ac985132 100644 --- a/pkg/internal/lock.go +++ b/pkg/shadow/lock.go @@ -1,4 +1,4 @@ -package internal +package shadow import ( "io/ioutil" diff --git a/pkg/internal/log/mod.go b/pkg/shadow/log/mod.go similarity index 100% rename from pkg/internal/log/mod.go rename to pkg/shadow/log/mod.go diff --git a/pkg/internal/util/assert.go b/pkg/shadow/util/assert.go similarity index 89% rename from pkg/internal/util/assert.go rename to pkg/shadow/util/assert.go index 8a88b77b..16838460 100644 --- a/pkg/internal/util/assert.go +++ b/pkg/shadow/util/assert.go @@ -4,7 +4,7 @@ import ( "os" "reflect" - "github.com/darwinia-network/shadow/pkg/internal/log" + "github.com/darwinia-network/shadow/pkg/shadow/log" ) // Check if is empty diff --git a/pkg/internal/util/collection.go b/pkg/shadow/util/collection.go similarity index 100% rename from pkg/internal/util/collection.go rename to pkg/shadow/util/collection.go diff --git a/pkg/internal/util/encode.go b/pkg/shadow/util/encode.go similarity index 100% rename from pkg/internal/util/encode.go rename to pkg/shadow/util/encode.go diff --git a/src/lib.rs b/src/lib.rs index d293cc9d..514699d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,12 @@ //! # Shadow //! -//! [![Golang CI][workflow-badge]][github] +//! [![Shadow][workflow-badge]][github] //! //! The shadow service for relayers and verify workers to retrieve header data and generate proof. Shadow will index the data it needs from blockchain nodes, such as Ethereum and Darwinia. //! //! ## Usage //! -//! ```text +//! ```sh //! shadow 0.1.0 //! //! USAGE: @@ -23,23 +23,17 @@ //! trim Trim mmr from target leaf //! ``` //! -//! ## Contribute and Build +//! ## Download //! -//! Downloads shadow service -//! -//! ```text -//! git clone https://github.com/darwinia-network/shadow.git +//! ```sh +//! $ cargo install darwinia-shadow //! ``` //! -//! Starts shadow service: +//! ### Note //! -//! ```text -//! # Starts shadow serives at port 3000 -//! $ cargo run -p 3000 +//! + Please make sure you have golang installed in your machine +//! + Please make sure you have installed the sqlite3 library in your machine //! -//! # If you have fast eth node: -//! $ ETHEREUM_RPC= cargo run -p 3000 -//! ``` //! //! ## Trouble Shooting //! @@ -51,12 +45,8 @@ //! GPL-3.0 //! //! -//! [infura]: https://infura.io //! [github]: https://github.com/darwinia-network/shadow -//! [spec]: https://github.com/darwinia-network/darwinia/wiki/Darwinia-offchain-worker-shadow-service-spec -//! [workflow-badge]: https://github.com/darwinia-network/shadow/workflows/Golang%20CI/badge.svg -//! [api]: https://darwinia-network.github.io/shadow - +//! [workflow-badge]: https://github.com/darwinia-network/shadow/workflows/shadow/badge.svg #![warn(missing_docs)] #![allow(clippy::transmute_ptr_to_ptr)] #![allow(clippy::ptr_offset_with_cast)] From 64be82859d21d403c8f9649f6afc94e6d270522d Mon Sep 17 00:00:00 2001 From: clearloop Date: Thu, 27 Aug 2020 17:28:48 +0800 Subject: [PATCH 07/36] fix(lint): optimize code style --- .github/workflows/{mmr.yml => shaodw.yml} | 0 Dockerfile | 21 +++++---------------- build.rs | 2 +- src/api/eth/proposal.rs | 2 +- src/chain/eth/header.rs | 2 +- src/cmd/mod.rs | 2 +- src/mmr/runner.rs | 7 +++---- 7 files changed, 12 insertions(+), 24 deletions(-) rename .github/workflows/{mmr.yml => shaodw.yml} (100%) diff --git a/.github/workflows/mmr.yml b/.github/workflows/shaodw.yml similarity index 100% rename from .github/workflows/mmr.yml rename to .github/workflows/shaodw.yml diff --git a/Dockerfile b/Dockerfile index 200ceb9f..1d312a69 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,25 +1,14 @@ -# Build MMR in a stock rust builder container -FROM rust:alpine as mmr +# Build Shadow in a stock rust builder container +FROM rust:alpine as shadow ARG DEBIAN_FRONTEND=noninteractive ENV TZ=America/Los_Angeles COPY . shadow -RUN apk add --no-cache sqlite-dev bash musl-dev \ +RUN apk add --no-cache openssl-dev sqlite-dev gcc go musl-dev\ && cd shadow \ && cargo build --release -# Build Shadow in a stock Go builder container -FROM golang:1.14-alpine as shadow -ARG DEBIAN_FRONTEND=noninteractive -ENV TZ=America/Los_Angeles -COPY --from=mmr /shadow/target/release/libmmr.a /usr/local/lib/ -COPY . shadow -RUN apk add --no-cache sqlite-dev sqlite-libs musl-dev gcc bash \ - && mkdir /outputs \ - && cd shadow \ - && go build -o /usr/local/bin/shadow -v bin/main.go - -# Pull Geth and Shadow into a third stage deploy alpine container +# Pull Shadow into a second stage deploy alpine container FROM alpine:latest -COPY --from=shadow /usr/local/bin/shadow /usr/local/bin/shadow +COPY --from=shadow /shadow/target/release/shadow /usr/local/bin/shadow EXPOSE 3000 ENTRYPOINT ["shadow"] diff --git a/build.rs b/build.rs index 4a403fcc..86c0af1f 100644 --- a/build.rs +++ b/build.rs @@ -26,7 +26,7 @@ fn main() { "build", "-o", &lib, - "-buildmode=c-shared", + "-buildmode=c-archive", "pkg/shadow/ffi/mod.go", ]) .status() diff --git a/src/api/eth/proposal.rs b/src/api/eth/proposal.rs index ffdd04f8..09bbcb15 100644 --- a/src/api/eth/proposal.rs +++ b/src/api/eth/proposal.rs @@ -36,7 +36,7 @@ impl ProposalReq { >::decode(&mut bytes!(proof.as_str()).as_ref()) .unwrap_or_default() .iter() - .map(|p| Into::::into(p)) + .map(Into::::into) .collect() } } diff --git a/src/chain/eth/header.rs b/src/chain/eth/header.rs index 836cff4e..4f3cc7b1 100644 --- a/src/chain/eth/header.rs +++ b/src/chain/eth/header.rs @@ -93,7 +93,7 @@ impl Into for RawEthHeader { gas_used: U256::from_str(&self.gas_used[2..]).unwrap_or_default(), gas_limit: U256::from_str(&self.gas_limit[2..]).unwrap_or_default(), difficulty: U256::from_str(&self.difficulty[2..]).unwrap_or_default(), - seal: seal, + seal, hash: match self.hash.is_empty() { true => None, false => Some(bytes!(self.hash.as_str(), 32)), diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs index a0c7c571..b4e63e05 100644 --- a/src/cmd/mod.rs +++ b/src/cmd/mod.rs @@ -31,7 +31,7 @@ pub async fn exec() -> Result<(), Error> { match Opt::from_args() { Opt::Run { port, verbose } => { - if let Err(_) = std::env::var("RUST_LOG") { + if std::env::var("RUST_LOG").is_err() { if verbose { std::env::set_var("RUST_LOG", "info,shadow"); } else { diff --git a/src/mmr/runner.rs b/src/mmr/runner.rs index bdd38d71..0b751fc6 100644 --- a/src/mmr/runner.rs +++ b/src/mmr/runner.rs @@ -86,14 +86,13 @@ impl Runner { cmmr::leaf_index_to_mmr_size((pnumber - 1) as u64), &self.store, ); - if let Err(e) = mmr.push(H256::from( + + mmr.push(H256::from( &EthHeaderRPCResp::get(&self.client, pnumber as u64) .await? .result .hash, - )) { - return Err(Error::MMR(e)); - } + ))?; mmr.commit()?; Ok(()) From dcdcb818f40009f3ab0c79ecc09d44e8a2a2f008 Mon Sep 17 00:00:00 2001 From: clearloop Date: Thu, 27 Aug 2020 17:31:03 +0800 Subject: [PATCH 08/36] chore(docker): update dockerfile and docker-compose.yml --- docker-compose.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 8269ed74..29b2d609 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,13 +16,6 @@ services: - data:/root depends_on: - geth - mmr: - image: quay.io/darwinia-network/shadow:next - command: run -vm --no-fetch --no-api - volumes: - - data:/root - depends_on: - - fetcher volumes: data: From a4d92cf757f0afcb39ef6f8241c839a834a115b5 Mon Sep 17 00:00:00 2001 From: clearloop Date: Thu, 27 Aug 2020 19:24:43 +0800 Subject: [PATCH 09/36] fix(mmr): fix the genesis mmr size --- build.rs | 14 ++------------ examples/proof.rs | 4 +++- src/mmr/runner.rs | 11 ++++++----- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/build.rs b/build.rs index 86c0af1f..92605586 100644 --- a/build.rs +++ b/build.rs @@ -5,22 +5,12 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=path/to/Cargo.lock"); - // main - let os = Command::new("uname").output().unwrap(); - let ext = match String::from_utf8_lossy(os.stdout.as_slice()) - .into_owned() - .trim_end() - .as_ref() - { - "Darwin" => "dylib", - _ => "so", - }; - + // build libeth.a let out_dir = env::var_os("OUT_DIR") .unwrap() .to_string_lossy() .to_string(); - let lib = format!("{}/libeth.{}", out_dir, ext); + let lib = format!("{}/libeth.a", out_dir); Command::new("go") .args(&[ "build", diff --git a/examples/proof.rs b/examples/proof.rs index e3d98495..6dc7f0dd 100644 --- a/examples/proof.rs +++ b/examples/proof.rs @@ -6,5 +6,7 @@ extern "C" { } fn main() { - println!("{:?}", unsafe { CStr::from_ptr(Proof(1)) }); + println!("{:?}", unsafe { + CStr::from_ptr(Proof(1)).to_string_lossy().to_string() + }); } diff --git a/src/mmr/runner.rs b/src/mmr/runner.rs index 0b751fc6..18eaf090 100644 --- a/src/mmr/runner.rs +++ b/src/mmr/runner.rs @@ -82,11 +82,12 @@ impl Runner { /// Push new header hash into storage pub async fn push(&mut self, pnumber: i64) -> Result<(), Error> { - let mut mmr = MMR::<_, MergeHash, _>::new( - cmmr::leaf_index_to_mmr_size((pnumber - 1) as u64), - &self.store, - ); - + let mmr_size = if pnumber == 0 { + 0 + } else { + cmmr::leaf_index_to_mmr_size((pnumber - 1) as u64) + } as u64; + let mut mmr = MMR::<_, MergeHash, _>::new(mmr_size, &self.store); mmr.push(H256::from( &EthHeaderRPCResp::get(&self.client, pnumber as u64) .await? From 95a37da269de728a8ac0c2f7e872964ea47e03bd Mon Sep 17 00:00:00 2001 From: clearloop Date: Thu, 27 Aug 2020 19:50:26 +0800 Subject: [PATCH 10/36] fix(linker): declare links in Cargo.toml --- Cargo.toml | 5 +++-- build.rs | 4 ++-- src/api/eth/proposal.rs | 2 +- src/api/eth/receipt.rs | 2 +- src/mmr/runner.rs | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 934d19dc..ecf55a49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "darwinia-shadow" -version = "0.0.1" +version = "0.0.2" authors = ["clearloop "] edition = "2018" -description = "The shadow service for relayers and verify workers to retrieve header data and generate proof. Shadow will index the data it needs from blockchain nodes, such as Ethereum and Darwinia." +description = "The shadow service for relayers and verify workers to retrieve header data and generate proof." repository = "https://github.com/darwinia-network/shadow" license = "GPL-3.0-or-later" documentation = "https://docs.rs/darwinia-shadow" @@ -17,6 +17,7 @@ include = [ ] keywords = ["darwinia", "substrate", "service"] readme = './README.md' +links = "darwinia_shadow" [[bin]] name = "shadow" diff --git a/build.rs b/build.rs index 92605586..45c50b6b 100644 --- a/build.rs +++ b/build.rs @@ -10,7 +10,7 @@ fn main() { .unwrap() .to_string_lossy() .to_string(); - let lib = format!("{}/libeth.a", out_dir); + let lib = format!("{}/libdarwinia_shadow.a", out_dir); Command::new("go") .args(&[ "build", @@ -23,6 +23,6 @@ fn main() { .unwrap(); // post-check - println!("cargo:rustc-link-lib=eth"); + println!("cargo:rustc-link-lib=static=darwinia_shadow"); println!("cargo:rustc-link-search={}", out_dir); } diff --git a/src/api/eth/proposal.rs b/src/api/eth/proposal.rs index 09bbcb15..ac76c09a 100644 --- a/src/api/eth/proposal.rs +++ b/src/api/eth/proposal.rs @@ -102,7 +102,7 @@ pub async fn handle(req: web::Json) -> impl Responder { web::Json(req.0.headers().await) } -#[link(name = "eth")] +#[link(name = "darwinia_shadow")] extern "C" { fn Proof(input: libc::c_uint) -> *const c_char; } diff --git a/src/api/eth/receipt.rs b/src/api/eth/receipt.rs index 96c277ba..9d8a80d2 100644 --- a/src/api/eth/receipt.rs +++ b/src/api/eth/receipt.rs @@ -20,7 +20,7 @@ pub async fn handle(tx: web::Path) -> impl Responder { } // FFI -#[link(name = "eth")] +#[link(name = "darwinia_shadow")] extern "C" { fn Receipt(input: GoString) -> GoTuple; } diff --git a/src/mmr/runner.rs b/src/mmr/runner.rs index 18eaf090..04256d4e 100644 --- a/src/mmr/runner.rs +++ b/src/mmr/runner.rs @@ -55,7 +55,7 @@ impl Runner { loop { if let Err(e) = self.push(ptr).await { - error!("Push block to mmr_store failed: {:?}", e); + trace!("Push block to mmr_store failed: {:?}", e); trace!("MMR service restarting after 10s..."); async_std::task::sleep(time::Duration::from_secs(10)).await; } else { From fcbd96f038dafbb867ec4b94a27c9a67933d11d8 Mon Sep 17 00:00:00 2001 From: clearloop Date: Thu, 27 Aug 2020 19:53:03 +0800 Subject: [PATCH 11/36] fix(example): the linker in proof example --- examples/proof.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/proof.rs b/examples/proof.rs index 6dc7f0dd..4c82b4e1 100644 --- a/examples/proof.rs +++ b/examples/proof.rs @@ -1,6 +1,6 @@ use std::{ffi::CStr, os::raw::c_char}; -#[link(name = "eth")] +#[link(name = "darwinia_shadow")] extern "C" { fn Proof(input: libc::c_uint) -> *const c_char; } From d3007c2152cfc037a27b73ee3ea8e833d8f62d81 Mon Sep 17 00:00:00 2001 From: clearloop Date: Thu, 27 Aug 2020 21:37:55 +0800 Subject: [PATCH 12/36] perf(linker): supports dynamic link in examples --- build.rs | 40 ++++++++++++++++++++++++++++------------ examples/receipt.rs | 2 +- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/build.rs b/build.rs index 45c50b6b..730948cc 100644 --- a/build.rs +++ b/build.rs @@ -5,22 +5,38 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=path/to/Cargo.lock"); - // build libeth.a + // build libdarwinia_shadow + let os = Command::new("uname").output().unwrap(); + let ext = match String::from_utf8_lossy(os.stdout.as_slice()) + .into_owned() + .trim_end() + .as_ref() + { + "Darwin" => "dylib", + _ => "so", + }; + + // get out dir let out_dir = env::var_os("OUT_DIR") .unwrap() .to_string_lossy() .to_string(); - let lib = format!("{}/libdarwinia_shadow.a", out_dir); - Command::new("go") - .args(&[ - "build", - "-o", - &lib, - "-buildmode=c-archive", - "pkg/shadow/ffi/mod.go", - ]) - .status() - .unwrap(); + + // build libraries + vec![("a", "archive"), (ext, "shared")] + .iter() + .for_each(|lib| { + Command::new("go") + .args(&[ + "build", + "-o", + &format!("{}/libdarwinia_shadow.{}", out_dir, lib.0), + &format!("-buildmode=c-{}", lib.1), + "pkg/shadow/ffi/mod.go", + ]) + .status() + .unwrap(); + }); // post-check println!("cargo:rustc-link-lib=static=darwinia_shadow"); diff --git a/examples/receipt.rs b/examples/receipt.rs index 4bd3ee16..d4639d66 100644 --- a/examples/receipt.rs +++ b/examples/receipt.rs @@ -17,7 +17,7 @@ struct GoTuple { hash: *const c_char, } -#[link(name = "eth")] +#[link(name = "darwinia_shadow")] extern "C" { fn Receipt(input: GoString) -> GoTuple; } From 5e658870baebdfe951c51e100fe2a2be754f6ef1 Mon Sep 17 00:00:00 2001 From: clearloop Date: Thu, 27 Aug 2020 22:23:25 +0800 Subject: [PATCH 13/36] fix(example): exports ffi for test usages --- build.rs | 36 +++++++------------------ examples/proof.rs | 11 +------- examples/receipt.rs | 39 +++------------------------ src/api/eth/ffi.rs | 58 +++++++++++++++++++++++++++++++++++++++++ src/api/eth/mod.rs | 1 + src/api/eth/proposal.rs | 23 +++++----------- src/api/eth/receipt.rs | 56 +++++++-------------------------------- src/api/mod.rs | 2 +- 8 files changed, 91 insertions(+), 135 deletions(-) create mode 100644 src/api/eth/ffi.rs diff --git a/build.rs b/build.rs index 730948cc..8feb21a2 100644 --- a/build.rs +++ b/build.rs @@ -6,37 +6,21 @@ fn main() { println!("cargo:rerun-if-changed=path/to/Cargo.lock"); // build libdarwinia_shadow - let os = Command::new("uname").output().unwrap(); - let ext = match String::from_utf8_lossy(os.stdout.as_slice()) - .into_owned() - .trim_end() - .as_ref() - { - "Darwin" => "dylib", - _ => "so", - }; - - // get out dir let out_dir = env::var_os("OUT_DIR") .unwrap() .to_string_lossy() .to_string(); - // build libraries - vec![("a", "archive"), (ext, "shared")] - .iter() - .for_each(|lib| { - Command::new("go") - .args(&[ - "build", - "-o", - &format!("{}/libdarwinia_shadow.{}", out_dir, lib.0), - &format!("-buildmode=c-{}", lib.1), - "pkg/shadow/ffi/mod.go", - ]) - .status() - .unwrap(); - }); + Command::new("go") + .args(&[ + "build", + "-o", + &format!("{}/libdarwinia_shadow.a", out_dir), + "-buildmode=c-archive", + "pkg/shadow/ffi/mod.go", + ]) + .status() + .unwrap(); // post-check println!("cargo:rustc-link-lib=static=darwinia_shadow"); diff --git a/examples/proof.rs b/examples/proof.rs index 4c82b4e1..543a00c2 100644 --- a/examples/proof.rs +++ b/examples/proof.rs @@ -1,12 +1,3 @@ -use std::{ffi::CStr, os::raw::c_char}; - -#[link(name = "darwinia_shadow")] -extern "C" { - fn Proof(input: libc::c_uint) -> *const c_char; -} - fn main() { - println!("{:?}", unsafe { - CStr::from_ptr(Proof(1)).to_string_lossy().to_string() - }); + darwinia_shadow::api::eth::ffi::proof(1); } diff --git a/examples/receipt.rs b/examples/receipt.rs index d4639d66..2c164eeb 100644 --- a/examples/receipt.rs +++ b/examples/receipt.rs @@ -1,38 +1,5 @@ -use std::{ - ffi::{CStr, CString}, - os::raw::c_char, -}; - -const TX: &str = "0x3b82a55f5e752c23359d5c3c4c3360455ce0e485ed37e1faabe9ea10d5db3e7a"; - -#[repr(C)] -struct GoString { - a: *const c_char, - b: i64, -} - -#[repr(C)] -struct GoTuple { - proof: *const c_char, - hash: *const c_char, -} - -#[link(name = "darwinia_shadow")] -extern "C" { - fn Receipt(input: GoString) -> GoTuple; -} - fn main() { - let c_tx = CString::new(TX).expect("CString::new failed"); - let ptr = c_tx.as_ptr(); - let tx = GoString { - a: ptr, - b: c_tx.as_bytes().len() as i64, - }; - - unsafe { - let gt = Receipt(tx); - println!("{:?}", CStr::from_ptr(gt.proof)); - println!("{:?}", CStr::from_ptr(gt.hash)); - } + darwinia_shadow::api::eth::ffi::receipt( + "0x3b82a55f5e752c23359d5c3c4c3360455ce0e485ed37e1faabe9ea10d5db3e7a".to_string(), + ); } diff --git a/src/api/eth/ffi.rs b/src/api/eth/ffi.rs new file mode 100644 index 00000000..18d45318 --- /dev/null +++ b/src/api/eth/ffi.rs @@ -0,0 +1,58 @@ +//! Ethereum ffi bindgen +use std::{ + ffi::{CStr, CString}, + os::raw::c_char, +}; + +#[repr(C)] +struct GoString { + a: *const c_char, + b: i64, +} + +impl From for GoString { + fn from(s: String) -> GoString { + let c_tx = CString::new(s).expect("CString::new failed"); + GoString { + a: c_tx.as_ptr(), + b: c_tx.as_bytes().len() as i64, + } + } +} + +#[repr(C)] +struct GoTuple { + proof: *const c_char, + hash: *const c_char, +} + +#[link(name = "darwinia_shadow")] +extern "C" { + fn Proof(input: libc::c_uint) -> *const c_char; + fn Receipt(input: GoString) -> GoTuple; +} + +/// Proof eth header by number +pub fn proof(block: u64) -> String { + unsafe { + CStr::from_ptr(Proof(block as u32)) + .to_string_lossy() + .to_string() + } +} + +/// Get receipt by tx hash +pub fn receipt(tx: String) -> (String, String) { + unsafe { + let c_tx = CString::new(tx).expect("CString::new failed"); + let receipt = Receipt(GoString { + a: c_tx.as_ptr(), + b: c_tx.as_bytes().len() as i64, + }); + + ( + CStr::from_ptr(receipt.proof).to_string_lossy().to_string(), + CStr::from_ptr(receipt.hash).to_string_lossy().to_string(), + ) + } +} diff --git a/src/api/eth/mod.rs b/src/api/eth/mod.rs index e44518e5..c2ee101e 100644 --- a/src/api/eth/mod.rs +++ b/src/api/eth/mod.rs @@ -1,4 +1,5 @@ //! Ethereum API +pub mod ffi; mod proposal; mod receipt; diff --git a/src/api/eth/proposal.rs b/src/api/eth/proposal.rs index ac76c09a..52994948 100644 --- a/src/api/eth/proposal.rs +++ b/src/api/eth/proposal.rs @@ -9,7 +9,6 @@ use actix_web::{web, Responder}; use cmmr::MMR; use reqwest::Client; use scale::Decode; -use std::{ffi::CStr, os::raw::c_char}; /// Proposal post req #[derive(Deserialize)] @@ -29,16 +28,12 @@ impl ProposalReq { /// Get `EtHashProof` fn ethash_proof(block: u64) -> Vec { - unsafe { - let proof = CStr::from_ptr(Proof(block as u32)) - .to_string_lossy() - .to_string(); - >::decode(&mut bytes!(proof.as_str()).as_ref()) - .unwrap_or_default() - .iter() - .map(Into::::into) - .collect() - } + let proof = super::ffi::proof(block); + >::decode(&mut bytes!(proof.as_str()).as_ref()) + .unwrap_or_default() + .iter() + .map(Into::::into) + .collect() } // Get mmr root @@ -98,11 +93,7 @@ pub struct ProposalHeader { mmr_proof: Vec, } +/// Proposal Handler pub async fn handle(req: web::Json) -> impl Responder { web::Json(req.0.headers().await) } - -#[link(name = "darwinia_shadow")] -extern "C" { - fn Proof(input: libc::c_uint) -> *const c_char; -} diff --git a/src/api/eth/receipt.rs b/src/api/eth/receipt.rs index 9d8a80d2..af458344 100644 --- a/src/api/eth/receipt.rs +++ b/src/api/eth/receipt.rs @@ -1,8 +1,4 @@ use actix_web::{web, Responder}; -use std::{ - ffi::{CStr, CString}, - os::raw::c_char, -}; #[derive(Serialize)] struct ReceiptResp { @@ -10,50 +6,18 @@ struct ReceiptResp { hash: String, } -/// Receipt Handler -pub async fn handle(tx: web::Path) -> impl Responder { - unsafe { - web::Json(Into::::into(Receipt(GoString::from( - tx.to_string(), - )))) - } -} - -// FFI -#[link(name = "darwinia_shadow")] -extern "C" { - fn Receipt(input: GoString) -> GoTuple; -} - -#[repr(C)] -struct GoString { - a: *const c_char, - b: i64, -} - -impl From for GoString { - fn from(s: String) -> GoString { - let c_tx = CString::new(s).expect("CString::new failed"); - GoString { - a: c_tx.as_ptr(), - b: c_tx.as_bytes().len() as i64, +impl From<(String, String)> for ReceiptResp { + fn from(t: (String, String)) -> ReceiptResp { + ReceiptResp { + proof: t.0, + hash: t.1, } } } -#[repr(C)] -struct GoTuple { - proof: *const c_char, - hash: *const c_char, -} - -impl Into for GoTuple { - fn into(self) -> ReceiptResp { - unsafe { - ReceiptResp { - proof: format!("{:?}", CStr::from_ptr(self.proof)), - hash: format!("{:?}", CStr::from_ptr(self.hash)), - } - } - } +/// Receipt Handler +pub async fn handle(tx: web::Path) -> impl Responder { + web::Json(Into::::into(super::ffi::receipt( + tx.to_string(), + ))) } diff --git a/src/api/mod.rs b/src/api/mod.rs index 5067108b..1411604b 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,7 +1,7 @@ //! The API server of Shadow use actix_web::{middleware, web, App, HttpServer}; -mod eth; +pub mod eth; /// Run HTTP Server pub async fn serve(port: u16) -> std::io::Result<()> { From 61b1319301158ab0f8a2770dffd4bea5c492bef2 Mon Sep 17 00:00:00 2001 From: clearloop Date: Thu, 27 Aug 2020 22:45:43 +0800 Subject: [PATCH 14/36] perf(ffi): move tests into module --- examples/proof.rs | 3 --- examples/receipt.rs | 5 ----- src/api/eth/ffi.rs | 15 +++++++++++++++ src/api/eth/mod.rs | 2 +- src/api/mod.rs | 2 +- 5 files changed, 17 insertions(+), 10 deletions(-) delete mode 100644 examples/proof.rs delete mode 100644 examples/receipt.rs diff --git a/examples/proof.rs b/examples/proof.rs deleted file mode 100644 index 543a00c2..00000000 --- a/examples/proof.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - darwinia_shadow::api::eth::ffi::proof(1); -} diff --git a/examples/receipt.rs b/examples/receipt.rs deleted file mode 100644 index 2c164eeb..00000000 --- a/examples/receipt.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - darwinia_shadow::api::eth::ffi::receipt( - "0x3b82a55f5e752c23359d5c3c4c3360455ce0e485ed37e1faabe9ea10d5db3e7a".to_string(), - ); -} diff --git a/src/api/eth/ffi.rs b/src/api/eth/ffi.rs index 18d45318..0b51b888 100644 --- a/src/api/eth/ffi.rs +++ b/src/api/eth/ffi.rs @@ -56,3 +56,18 @@ pub fn receipt(tx: String) -> (String, String) { ) } } + +#[cfg(test)] +mod test { + #[test] + fn test_proof() { + super::proof(1); + } + + #[test] + fn test_receipt() { + super::receipt( + "0x3b82a55f5e752c23359d5c3c4c3360455ce0e485ed37e1faabe9ea10d5db3e7a".to_string(), + ); + } +} diff --git a/src/api/eth/mod.rs b/src/api/eth/mod.rs index c2ee101e..56bc9b17 100644 --- a/src/api/eth/mod.rs +++ b/src/api/eth/mod.rs @@ -1,5 +1,5 @@ //! Ethereum API -pub mod ffi; +mod ffi; mod proposal; mod receipt; diff --git a/src/api/mod.rs b/src/api/mod.rs index 1411604b..5067108b 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,7 +1,7 @@ //! The API server of Shadow use actix_web::{middleware, web, App, HttpServer}; -pub mod eth; +mod eth; /// Run HTTP Server pub async fn serve(port: u16) -> std::io::Result<()> { From 32f75ae33b4ccd161fe4ca788d8e6f8eb0dff94e Mon Sep 17 00:00:00 2001 From: clearloop Date: Fri, 28 Aug 2020 09:45:07 +0800 Subject: [PATCH 15/36] perf(build): add go.mod and go.sum into manifest --- Cargo.toml | 6 ++++-- build.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ecf55a49..d8534b93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "darwinia-shadow" -version = "0.0.2" +version = "0.0.3" authors = ["clearloop "] edition = "2018" description = "The shadow service for relayers and verify workers to retrieve header data and generate proof." @@ -9,13 +9,15 @@ license = "GPL-3.0-or-later" documentation = "https://docs.rs/darwinia-shadow" homepage = "https://github.com/darwinia-network/shadow" include = [ + "go.mod", + "go.sum", "build.rs", "pkg/**/*", "src/**/*", "Cargo.toml", "./README.md", ] -keywords = ["darwinia", "substrate", "service"] +keywords = ["darwinia", "substrate", "ethereum", "service"] readme = './README.md' links = "darwinia_shadow" diff --git a/build.rs b/build.rs index 8feb21a2..fbc7cf79 100644 --- a/build.rs +++ b/build.rs @@ -13,7 +13,7 @@ fn main() { Command::new("go") .args(&[ - "build", + "CGO_ENABLED=0 build", "-o", &format!("{}/libdarwinia_shadow.a", out_dir), "-buildmode=c-archive", From ce82847d676c8bed26664d6f0f49d0b2cbcc4560 Mon Sep 17 00:00:00 2001 From: clearloop Date: Fri, 28 Aug 2020 10:42:15 +0800 Subject: [PATCH 16/36] fix(pkg): remove the missing internal pkg --- pkg/internal/config.go | 78 -------- pkg/internal/eth/api.go | 9 - pkg/internal/eth/header.go | 110 ------------ pkg/internal/eth/mock.go | 52 ------ pkg/internal/eth/proof.go | 211 ---------------------- pkg/internal/eth/receipt.go | 253 -------------------------- pkg/internal/eth/scale.go | 48 ----- pkg/internal/eth/types.go | 106 ----------- pkg/internal/ffi/mod.go | 43 ----- pkg/internal/lock.go | 93 ---------- pkg/internal/log/mod.go | 76 -------- pkg/internal/util/assert.go | 35 ---- pkg/internal/util/collection.go | 21 --- pkg/internal/util/encode.go | 303 -------------------------------- 14 files changed, 1438 deletions(-) delete mode 100644 pkg/internal/config.go delete mode 100644 pkg/internal/eth/api.go delete mode 100644 pkg/internal/eth/header.go delete mode 100644 pkg/internal/eth/mock.go delete mode 100644 pkg/internal/eth/proof.go delete mode 100644 pkg/internal/eth/receipt.go delete mode 100644 pkg/internal/eth/scale.go delete mode 100644 pkg/internal/eth/types.go delete mode 100644 pkg/internal/ffi/mod.go delete mode 100644 pkg/internal/lock.go delete mode 100644 pkg/internal/log/mod.go delete mode 100644 pkg/internal/util/assert.go delete mode 100644 pkg/internal/util/collection.go delete mode 100644 pkg/internal/util/encode.go diff --git a/pkg/internal/config.go b/pkg/internal/config.go deleted file mode 100644 index af655eb6..00000000 --- a/pkg/internal/config.go +++ /dev/null @@ -1,78 +0,0 @@ -package shadow - -import ( - "os" - "path/filepath" - "strconv" - -<<<<<<< HEAD:pkg/shadow/config.go - "github.com/darwinia-network/shadow/pkg/shadow/util" -======= - "github.com/darwinia-network/shadow/pkg/internal/util" ->>>>>>> next:pkg/internal/config.go -) - -const ( - ETHEREUM_ROPSTEN string = "ETHEREUM_ROPSTEN" - ETHEREUM_RPC string = "ETHEREUM_RPC" - SHADOW_GENESIS string = "SHADOW_GENESIS" - GETH_DATADIR string = "GETH_DATADIR" - DEFAULT_ETHEREUM_RPC string = "https://mainnet.infura.io/v3/0bfb9acbb13c426097aabb1d81a9d016" -) - -type RawConfig struct { - Eth Config `json:"eth"` -} - -type Config struct { - Api string `json:"api"` - Genesis uint64 `json:"genesis"` - Root string `json:"root"` -} - -// Common load config -func (c *Config) Load() error { - // Init root directory - var err error - c.Root, err = RootDir() - if err != nil { - return err - } - - // Load infura key - gen := os.Getenv(SHADOW_GENESIS) - if gen == "" { - gen = "0" - } - - // Construct shadow genesis - c.Genesis, err = strconv.ParseUint(gen, 10, 64) - if err != nil { - return err - } - - // Load api from env - c.Api = os.Getenv(ETHEREUM_RPC) - if c.Api == "" && os.Getenv(ETHEREUM_ROPSTEN) == "" { - c.Api = DEFAULT_ETHEREUM_RPC - } - - return nil -} - -// Get darwinia config root directory -func RootDir() (string, error) { - home, err := os.UserHomeDir() - util.Assert(err) - - // Create root dir if not exist - root := filepath.Join(home, ".darwinia") - if _, err := os.Stat(root); os.IsNotExist(err) { - err = os.Mkdir(root, 0700) - if err != nil { - return "", err - } - } - - return root, nil -} diff --git a/pkg/internal/eth/api.go b/pkg/internal/eth/api.go deleted file mode 100644 index 1d94eeb2..00000000 --- a/pkg/internal/eth/api.go +++ /dev/null @@ -1,9 +0,0 @@ -package eth - -// The post api of fetching eth header -const ( - GETBLOCK = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getBlockByNumber\",\"params\": [\"0x%x\", false],\"id\":1}\n" - GETBLOCK_BYHASH = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getBlockByHash\",\"params\": [\"%s\", false],\"id\":1}\n" - // uncle block - GET_UNCLE_BLOCK = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getUncleByBlockNumberAndIndex\",\"params\": [\"0x%x\", \"0x0\"],\"id\":1}\n" -) diff --git a/pkg/internal/eth/header.go b/pkg/internal/eth/header.go deleted file mode 100644 index 5185d7f1..00000000 --- a/pkg/internal/eth/header.go +++ /dev/null @@ -1,110 +0,0 @@ -package eth - -import ( - "encoding/hex" - "encoding/json" - "fmt" - "net/http" - "strings" - -<<<<<<< HEAD:pkg/shadow/eth/header.go - "github.com/darwinia-network/shadow/pkg/shadow" -======= - "github.com/darwinia-network/shadow/pkg/internal" ->>>>>>> next:pkg/internal/eth/header.go - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/rlp" -) - -// Get ethereum header by block number -func Header(block uint64, api string) (types.Header, error) { - // Get header from infura - var ( - resp *http.Response - err error - infuraResp InfuraResponse - ) - - resp, err = http.Post( - api, - "application/json", - strings.NewReader(fmt.Sprintf(GETBLOCK, block)), - ) - - if err != nil { - if !strings.Contains(api, "infura") { - return Header(block, shadow.DEFAULT_ETHEREUM_RPC) - } - return infuraResp.Result, err - } - - // Decode resp to json - defer resp.Body.Close() - err = json.NewDecoder(resp.Body).Decode(&infuraResp) - if err != nil { - if !strings.Contains(api, "infura") { - return Header(block, shadow.DEFAULT_ETHEREUM_RPC) - } - return infuraResp.Result, err - } - - // Return eth header - return infuraResp.Result, nil -} - -func (h *DarwiniaEthHeader) HexFormat() DarwiniaEthHeaderHexFormat { - return DarwiniaEthHeaderHexFormat{ - h.ParentHash, - hexutil.EncodeUint64(h.TimeStamp), - hexutil.EncodeUint64(h.Number), - h.Author, - h.TransactionsRoot, - h.UnclesHash, - h.ExtraData, - h.StateRoot, - h.ReceiptsRoot, - h.LogBloom, - hexutil.EncodeUint64(h.GasUsed), - hexutil.EncodeUint64(h.GasLimited), - hexutil.EncodeUint64(h.Difficulty), - h.Seal, - h.Hash, - } -} - -// Convert EthHeader to Darwinia Eth Block -func IntoDarwiniaEthHeader(e *types.Header) (DarwiniaEthHeader, error) { - h := DarwiniaEthHeader{} - mixh, err := rlp.EncodeToBytes(e.MixDigest) - if err != nil { - return h, err - } - - nonce, err := rlp.EncodeToBytes(e.Nonce) - if err != nil { - return h, err - } - - h.Seal = []string{ - "0x" + hex.EncodeToString(mixh), - "0x" + hex.EncodeToString(nonce), - } - - h.ParentHash = e.ParentHash.Hex() - h.TimeStamp = e.Time - h.Number = e.Number.Uint64() - h.Author = strings.ToLower(e.Coinbase.Hex()) - h.TransactionsRoot = e.TxHash.Hex() - h.UnclesHash = e.UncleHash.Hex() - h.ExtraData = "0x" + hex.EncodeToString(e.Extra) - h.StateRoot = e.Root.Hex() - h.ReceiptsRoot = e.ReceiptHash.Hex() - h.LogBloom = "0x" + hex.EncodeToString(e.Bloom.Bytes()) - h.GasUsed = e.GasUsed - h.GasLimited = e.GasLimit - h.Difficulty = e.Difficulty.Uint64() - h.Hash = e.Hash().Hex() - - return h, nil -} diff --git a/pkg/internal/eth/mock.go b/pkg/internal/eth/mock.go deleted file mode 100644 index 4017f8b8..00000000 --- a/pkg/internal/eth/mock.go +++ /dev/null @@ -1,52 +0,0 @@ -package eth - -import ( - "encoding/json" - "fmt" - "net/http" - "reflect" - "strings" - -<<<<<<< HEAD:pkg/shadow/eth/mock.go - "github.com/darwinia-network/shadow/pkg/shadow/log" -======= - "github.com/darwinia-network/shadow/pkg/internal/log" ->>>>>>> next:pkg/internal/eth/mock.go - "github.com/ethereum/go-ethereum/core/types" -) - -// Get uncle block by number -func UncleBlock(number uint64, api string) (types.Header, error) { - // Get header from infura - var ( - resp *http.Response - err error - infuraResp InfuraResponse - ) - - resp, err = http.Post( - api, - "application/json", - strings.NewReader(fmt.Sprintf(GET_UNCLE_BLOCK, number)), - ) - - if err != nil { - log.Error("%v", err) - return infuraResp.Result, err - } - - err = json.NewDecoder(resp.Body).Decode(&infuraResp) - if err != nil { - log.Error("%v", err) - return infuraResp.Result, err - } - - // Empty result - if reflect.DeepEqual(types.Header{}, infuraResp.Result) { - log.Error("%v", err) - return infuraResp.Result, fmt.Errorf("The requesting block does not exist") - } - - // Return eth header - return infuraResp.Result, nil -} diff --git a/pkg/internal/eth/proof.go b/pkg/internal/eth/proof.go deleted file mode 100644 index cac11cfc..00000000 --- a/pkg/internal/eth/proof.go +++ /dev/null @@ -1,211 +0,0 @@ -package eth - -import ( - "fmt" - "io/ioutil" - "math/big" - "os" - "path/filepath" - - "github.com/darwinia-network/shadow/pkg/ethashproof" - "github.com/darwinia-network/shadow/pkg/ethashproof/ethash" - "github.com/darwinia-network/shadow/pkg/ethashproof/mtree" -<<<<<<< HEAD:pkg/shadow/eth/proof.go - "github.com/darwinia-network/shadow/pkg/shadow" - "github.com/darwinia-network/shadow/pkg/shadow/util" -======= - "github.com/darwinia-network/shadow/pkg/internal" - "github.com/darwinia-network/shadow/pkg/internal/util" ->>>>>>> next:pkg/internal/eth/proof.go - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/types" -) - -// Constants -const ETHASHPROOF_CACHE = ".ethashproof" - -// Final outputs of ethashproof -type DoubleNodeWithMerkleProof struct { - DagNodes []string `json:"dag_nodes"` - Proof []string `json:"proof"` -} - -// This struct is used for process interaction -type ProofOutput struct { - HeaderRLP string `json:"header_rlp"` - MerkleRoot string `json:"merkle_root"` - Elements []string `json:"elements"` - MerkleProofs []string `json:"merkle_proofs"` - ProofLength uint64 `json:"proof_length"` -} - -// Format ProofOutput to double node with merkle proofs -func (o *ProofOutput) Format() []DoubleNodeWithMerkleProof { - h512s := util.Filter(o.Elements, func(i int, _ string) bool { - return i%2 == 0 - }) - - h512s = util.Map(h512s, func(i int, v string) string { - return fmt.Sprintf("0x%064s%064s", v[2:], o.Elements[(i*2)+1][2:]) - }) - - dnmps := []DoubleNodeWithMerkleProof{} - sh512s := util.Filter(h512s, func(i int, _ string) bool { - return i%2 == 0 - }) - util.Map(sh512s, func(i int, v string) string { - dnmps = append(dnmps, DoubleNodeWithMerkleProof{ - []string{v, h512s[i*2+1]}, - util.Map( - o.MerkleProofs[uint64(i)*o.ProofLength:(uint64(i)+1)*o.ProofLength], - func(_ int, v string) string { - return fmt.Sprintf("0x%032s", v[2:]) - }, - ), - }) - return v - }) - - return dnmps -} - -// Epoch in background -<<<<<<< HEAD:pkg/shadow/eth/proof.go -func bgEpoch(epoch uint64, config *shadow.Config) { -======= -func bgEpoch(epoch uint64, config *internal.Config) { ->>>>>>> next:pkg/internal/eth/proof.go - _, _ = ethashproof.CalculateDatasetMerkleRoot(epoch, true) - _ = config.RemoveLock(shadow.EPOCH_LOCK) -} - -// Check if need epoch -<<<<<<< HEAD:pkg/shadow/eth/proof.go -func epochGently(epoch uint64, config *shadow.Config) error { -======= -func epochGently(epoch uint64, config *internal.Config) error { ->>>>>>> next:pkg/internal/eth/proof.go - // Check if is epoching - if config.CheckLock(shadow.EPOCH_LOCK) { - return nil - } - - // Get home dir - home, err := os.UserHomeDir() - if err != nil { - return err - } - - // Find ethashproof cache - cache := filepath.Join(home, ETHASHPROOF_CACHE) - fs, err := ioutil.ReadDir(cache) - if err != nil { - return err - } - - // Check if has epoched - hasEpoched := false - for _, f := range fs { - if f.Name() == fmt.Sprintf("%v.json", epoch) { - hasEpoched = true - } - } - - // Create epoch lock - err = config.CreateLock(shadow.EPOCH_LOCK) - if err != nil { - return err - } - - // Run epoch - if !hasEpoched { - go bgEpoch(epoch, config) - } - - return nil -} - -// Proof eth blockheader -<<<<<<< HEAD:pkg/shadow/eth/proof.go -func Proof(header *types.Header, config *shadow.Config) (ProofOutput, error) { -======= -func Proof(header *types.Header, config *internal.Config) (ProofOutput, error) { ->>>>>>> next:pkg/internal/eth/proof.go - blockno := header.Number.Uint64() - epoch := blockno / 30000 - output := &ProofOutput{} - - // Get proof from cache - cache, err := ethashproof.LoadCache(int(epoch)) - if err != nil { - err = config.RemoveLock(shadow.EPOCH_LOCK) - if err != nil { - return *output, err - } - - _, err = ethashproof.CalculateDatasetMerkleRoot(epoch, true) - if err != nil { - return *output, err - } - - cache, err = ethashproof.LoadCache(int(epoch)) - if err != nil { - return *output, err - } - } - - rlpheader, err := ethashproof.RLPHeader(header) - if err != nil { - return *output, err - } - - // init output - output = &ProofOutput{ - HeaderRLP: hexutil.Encode(rlpheader), - MerkleRoot: cache.RootHash.Hex(), - Elements: []string{}, - MerkleProofs: []string{}, - ProofLength: cache.ProofLength, - } - - // get verification indices - indices := ethash.Instance.GetVerificationIndices( - blockno, - ethash.Instance.SealHash(header), - header.Nonce.Uint64(), - ) - - // fill output - for _, index := range indices { - // calculate proofs - element, proof, err := ethashproof.CalculateProof(blockno, index, cache) - if err != nil { - return *output, err - } - - es := element.ToUint256Array() - for _, e := range es { - output.Elements = append(output.Elements, hexutil.EncodeBig(e)) - } - - // append proofs - allProofs := []*big.Int{} - for _, be := range mtree.HashesToBranchesArray(proof) { - allProofs = append(allProofs, be.Big()) - } - - for _, pr := range allProofs { - output.MerkleProofs = append(output.MerkleProofs, hexutil.EncodeBig(pr)) - } - } - - // Check if need pre-epoch - if blockno%30000 > 15000 { - err := epochGently(epoch, config) - if err != nil { - return *output, err - } - } - - return *output, nil -} diff --git a/pkg/internal/eth/receipt.go b/pkg/internal/eth/receipt.go deleted file mode 100644 index 95f9bf87..00000000 --- a/pkg/internal/eth/receipt.go +++ /dev/null @@ -1,253 +0,0 @@ -package eth - -import ( - "bytes" - "context" - "errors" - "math" - "strings" - "sync" - -<<<<<<< HEAD:pkg/shadow/eth/receipt.go - "github.com/darwinia-network/shadow/pkg/shadow" - "github.com/darwinia-network/shadow/pkg/shadow/util" -======= - "github.com/darwinia-network/shadow/pkg/internal" - "github.com/darwinia-network/shadow/pkg/internal/util" ->>>>>>> next:pkg/internal/eth/receipt.go - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/ethdb/memorydb" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/trie" - "github.com/mitchellh/mapstructure" - cmap "github.com/orcaman/concurrent-map" - "github.com/panjf2000/ants" - "github.com/regcostajr/go-web3/dto" - "github.com/regcostajr/go-web3/providers" -) - -var ( - API string -) - -func init() { - conf := new(shadow.Config) - _ = conf.Load() - API = conf.Api -} - -func GetChainBlockInfo(blockNum int64) (*BlockResult, error) { - params := []interface{}{util.IntToHex(blockNum), true} - if result, err := RPC("eth_getBlockByNumber", params); err != nil { - return nil, err - } else { - var block BlockResult - err := mapstructure.Decode(result.Result, &block) - return &block, err - } -} - -func RPC(method string, params interface{}) (*dto.RequestResult, error) { - provider := providers.NewHTTPProvider(strings.ReplaceAll(API, "https://", ""), 10, true) - pointer := &dto.RequestResult{} - err := provider.SendRequest(pointer, method, params) - if err != nil { - return nil, err - } - - return pointer, nil -} - -func GetReceiptLog(tx string) (*Receipts, error) { - params := make([]interface{}, 1) - params[0] = tx - var receipt Receipts - if receiptResult, err := RPC("eth_getTransactionReceipt", params); err != nil { - return nil, err - } else { - err := mapstructure.Decode(receiptResult.Result, &receipt) - if err != nil { - return nil, err - } - receipt.ChainSource = "Eth" - receipt.Solidity = true - return &receipt, err - } -} - -type EthHeader struct { - ParentHash string `json:"parent_hash"` - Timestamp int64 `json:"timestamp"` - Number int64 `json:"number"` - Auth string `json:"auth"` - TransactionRoot string `json:"transaction_root"` - UnclesHash string `json:"uncles_hash"` - ExtraData string `json:"extra_data"` - StateRoot string `json:"state_root"` - ReceiptsRoot string `json:"receipts_root"` - LogBloom string `json:"log_bloom"` - GasUsed string `json:"gas_used"` - GasLimit string `json:"gas_limit"` - Difficulty string `json:"difficulty"` - Seal []string `json:"seal"` - Hash string `json:"hash"` -} - -type EthReceiptLog struct { - Address string `json:"address"` - Topics []string `json:"topics"` - Data []byte `json:"data"` -} - -type EthReceipt struct { - GasUsed int64 `json:"gas_used"` - LogBloom string `json:"log_bloom"` - Logs []EthReceiptLog `json:"logs"` - Outcome int `json:"outcome"` -} - -type ProofRecord struct { - Index string `json:"index"` - Proof string `json:"proof"` - HeaderHash string `json:"header_hash"` -} - -type RedeemFor struct { - Ring *ProofRecord `json:"ring,omitempty"` - Kton *ProofRecord `json:"kton,omitempty"` - Deposit *ProofRecord `json:"deposit,omitempty"` -} - -func GetReceipt(tx string) (ProofRecord, string, error) { - r, err := GetReceiptLog(tx) - if err != nil || r == nil { - return ProofRecord{}, "", err - } - - return BuildProofRecord(r) -} - -func BuildProofRecord(r *Receipts) (ProofRecord, string, error) { - proofRecord := ProofRecord{ - Index: r.TransactionIndex, - HeaderHash: r.BlockHash, - } - block, err := GetChainBlockInfo(util.U256(r.BlockNumber).Int64()) - if err != nil { - return ProofRecord{}, "", err - } - receiptsMap := cmap.New() - - var wg sync.WaitGroup - p, _ := ants.NewPoolWithFunc(10, func(i interface{}) { - hash := i.([]string) - func(hash []string) { - b, err := GetReceiptRlpEncode(hash[1]) - if err == nil { - receiptsMap.Set(hash[0], b) - } - }(hash) - wg.Done() - }) - defer p.Release() - - for index, transaction := range block.Transactions { - wg.Add(1) - _ = p.Invoke([]string{util.IntToString(index), transaction.Hash}) - } - wg.Wait() - if receiptsMap.Count() != len(block.Transactions) { - return ProofRecord{}, block.Hash, errors.New("get receipt Rlp errors") - } - tr, err := trieFromReceipts(receiptsMap.Items()) - if err != nil { - return ProofRecord{}, block.Hash, err - } - proof := memorydb.New() - buf := new(bytes.Buffer) - _ = rlp.Encode(buf, uint(util.U256(r.TransactionIndex).Uint64())) - key := buf.Bytes() - proofs := make([]interface{}, 0) - _ = tr.Prove(key, 0, proof) - if it := trie.NewIterator(tr.NodeIterator(key)); it.Next() && bytes.Equal(key, it.Key) { - for _, p := range it.Prove() { - proofs = append(proofs, p) - } - } - buf.Reset() - _ = rlp.Encode(buf, proofs) - length := rlpLength(len(buf.Bytes()), 0xc0) - ProofRlpBytes := append(length[:], buf.Bytes()...) - proofRecord.Proof = util.AddHex(util.BytesToHex(ProofRlpBytes)) - return proofRecord, block.Hash, nil -} - -func GetReceiptRlpEncode(tx string) (*types.Receipt, error) { - client, err := ethclient.Dial(API) - if err != nil { - return nil, err - } - r, err := client.TransactionReceipt(context.Background(), common.HexToHash(tx)) - if err != nil { - return nil, err - } - return r, nil -} - -func trieFromReceipts(receipts map[string]interface{}) (*trie.Trie, error) { - tr := new(trie.Trie) - - for i, r := range receipts { - path, err := rlp.EncodeToBytes(uint(util.StringToInt(i))) - if err != nil { - return nil, err - } - - rawReceipt, err := encodeReceipt(r.(*types.Receipt)) - if err != nil { - return nil, err - } - - tr.Update(path, rawReceipt) - } - - return tr, nil -} - -func encodeReceipt(r *types.Receipt) ([]byte, error) { - buf := new(bytes.Buffer) - if err := r.EncodeRLP(buf); err != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -func rlpLength(dataLen int, offset byte) []byte { - if dataLen < 56 { - return []byte{byte(dataLen) + offset} - } else if dataLen < math.MaxInt32 { - var output []byte - b := toBinary(dataLen) - output = append(output, byte(len(b)+int(offset)+55)) - return append(output, b...) - } else { - return []byte{} - } -} - -func toBinary(d int) []byte { - var b []byte - for d > 0 { - b = append([]byte{byte(d % 256)}, b...) - d /= 256 - } - return b -} - -func RlpEncode(hexStr string) string { - prefix := rlpLength(len(util.HexToBytes(hexStr)), 0x80) - return util.BytesToHex(prefix) + util.TrimHex(hexStr) -} diff --git a/pkg/internal/eth/scale.go b/pkg/internal/eth/scale.go deleted file mode 100644 index 61193d76..00000000 --- a/pkg/internal/eth/scale.go +++ /dev/null @@ -1,48 +0,0 @@ -package eth - -import ( - "encoding/hex" -) - -func lenToBytes(b []uint8, len int) ([]uint8, int) { - if len < 255 { - b = append(b, uint8(len)) - len = 0 - return b, len - } - - b = append(b, uint8(len/0xff)) - len = len % 0xff - return lenToBytes(b, len) -} - -func LenToHex(len int) string { - b, _ := lenToBytes([]uint8{}, len*4) - return hex.EncodeToString(b) -} - -// Pack encode proof -func EncodeProofArray(arr []DoubleNodeWithMerkleProof) string { - hex := "0x" + LenToHex(len(arr)) - for _, v := range arr { - hex += EncodeProof(v) - } - - return hex -} - -// Encode proof to hex with exist hex -func EncodeProof(dnmp DoubleNodeWithMerkleProof) string { - hex := "" - for _, v := range dnmp.DagNodes { - hex += v[2:] - } - - // pad the length - hex += LenToHex(len(dnmp.Proof)) - for _, v := range dnmp.Proof { - hex += v[2:] - } - - return hex -} diff --git a/pkg/internal/eth/types.go b/pkg/internal/eth/types.go deleted file mode 100644 index a94170c9..00000000 --- a/pkg/internal/eth/types.go +++ /dev/null @@ -1,106 +0,0 @@ -package eth - -import ( - "encoding/json" - - "github.com/ethereum/go-ethereum/core/types" -) - -// The response of etherscan api -type InfuraResponse struct { - JsonRPC string `json:"jsonrpc"` - Id uint32 `json:"id"` - Result types.Header `json:"result"` -} - -// Darwinia block -type DarwiniaEthHeader struct { - ParentHash string `json:"parent_hash"` - TimeStamp uint64 `json:"timestamp"` - Number uint64 `json:"number"` - Author string `json:"author"` - TransactionsRoot string `json:"transactions_root"` - UnclesHash string `json:"uncles_hash"` - ExtraData string `json:"extra_data"` - StateRoot string `json:"state_root"` - ReceiptsRoot string `json:"receipts_root"` - LogBloom string `json:"log_bloom"` - GasUsed uint64 `json:"gas_used"` - GasLimited uint64 `json:"gas_limit"` - Difficulty uint64 `json:"difficulty"` - Seal []string `json:"seal"` - Hash string `json:"hash"` -} - -func (d *DarwiniaEthHeader) ToString() (string, error) { - bytes, err := json.Marshal(d) - if err != nil { - return "", err - } - return string(bytes), nil -} - -type DarwiniaEthHeaderHexFormat struct { - ParentHash string `json:"parent_hash"` - TimeStamp string `json:"timestamp"` - Number string `json:"number"` - Author string `json:"author"` - TransactionsRoot string `json:"transactions_root"` - UnclesHash string `json:"uncles_hash"` - ExtraData string `json:"extra_data"` - StateRoot string `json:"state_root"` - ReceiptsRoot string `json:"receipts_root"` - LogBloom string `json:"log_bloom"` - GasUsed string `json:"gas_used"` - GasLimited string `json:"gas_limit"` - Difficulty string `json:"difficulty"` - Seal []string `json:"seal"` - Hash string `json:"hash"` -} - -type Receipts struct { - BlockNumber string `json:"block_number"` - Logs []Log `json:"logs"` - Status string `json:"status"` - ChainSource string `json:"chainSource"` - GasUsed string `json:"gasUsed"` - LogsBloom string `json:"logsBloom"` - Solidity bool `json:"solidity"` - TransactionIndex string `json:"transactionIndex"` - BlockHash string `json:"blockHash"` -} - -type Log struct { - Topics []string `json:"topics"` - Data string `json:"data"` - Address string `json:"address"` -} - -type BlockResult struct { - Difficulty string `json:"difficulty"` - ExtraData string `json:"extraData"` - GasLimit string `json:"gasLimit"` - GasUsed string `json:"gasUsed"` - Hash string `json:"hash"` - LogsBloom string `json:"logs_bloom"` - Miner string `json:"miner"` - MixHash string `json:"mixHash"` - Nonce string `json:"nonce"` - Number string `json:"number"` - ParentHash string `json:"parentHash"` - ReceiptsRoot string `json:"receiptsRoot"` - Sha3Uncles string `json:"sha3Uncles"` - StateRoot string `json:"stateRoot"` - Timestamp string `json:"timestamp"` - TotalDifficulty string `json:"totalDifficulty"` - Transactions []Transaction `json:"transactions"` - TransactionsRoot string `json:"transactionsRoot"` -} - -type Transaction struct { - Hash string `json:"hash"` - From string `json:"from"` - Input string `json:"input"` - To string `json:"to"` - Value string `json:"value"` -} diff --git a/pkg/internal/ffi/mod.go b/pkg/internal/ffi/mod.go deleted file mode 100644 index 5595ef90..00000000 --- a/pkg/internal/ffi/mod.go +++ /dev/null @@ -1,43 +0,0 @@ -package main - -import "C" -import ( - "github.com/darwinia-network/shadow/pkg/internal" - "github.com/darwinia-network/shadow/pkg/internal/eth" -) - -var ( - CONFIG internal.Config = internal.Config{} -) - -func init() { - _ = CONFIG.Load() -} - -//export Proof -func Proof(number uint64) *C.char { - header, err := eth.Header(number, CONFIG.Api) - if err != nil { - return C.CString("") - } - - proof, err := eth.Proof(&header, &CONFIG) - if err != nil { - return C.CString("") - } - - return C.CString(eth.EncodeProofArray(proof.Format())) -} - -//export Receipt -func Receipt(tx string) (*C.char, *C.char) { - tx = "0x" + tx[2:] - proof, hash, err := eth.GetReceipt(tx) - if err != nil { - return C.CString(""), C.CString("") - } - - return C.CString(proof.Proof), C.CString(hash) -} - -func main() {} diff --git a/pkg/internal/lock.go b/pkg/internal/lock.go deleted file mode 100644 index ac985132..00000000 --- a/pkg/internal/lock.go +++ /dev/null @@ -1,93 +0,0 @@ -package shadow - -import ( - "io/ioutil" - "os" - "path/filepath" - "strings" - "time" -) - -// Lock enum -type Lock string - -const ( - PROOF_LOCK Lock = "proof.lock" - EPOCH_LOCK Lock = "epoch.lock" -) - -func (l *Lock) toString() string { - return string(*l) -} - -// Check if lock exists -func (c *Config) CheckLock(lock Lock) bool { - p := filepath.Join(c.Root, lock.toString()) - if stat, err := os.Stat(p); os.IsNotExist(err) { - return false - } else if time.Since(stat.ModTime()).Minutes() > 30 { - if err = c.RemoveLock(lock); err != nil { - return true - } - } - - return true - -} - -// Create lock -func (c *Config) CreateLock(lock Lock) error { - p := filepath.Join(c.Root, lock.toString()) - if _, err := os.Stat(p); os.IsNotExist(err) { - _, err = os.Create(p) - if err != nil { - return err - } - - err = ioutil.WriteFile(p, []byte(""), 0600) - if err != nil { - return err - } - } - - return nil -} - -// Remove lock -func (c *Config) removeLockByString(lock string) error { - p := filepath.Join(c.Root, lock) - _, err := os.Stat(p) - if err == nil { - err = os.Remove(p) - if err != nil { - return err - } - } - - return nil -} - -// Remove lock -func (c *Config) RemoveLock(lock Lock) error { - return c.removeLockByString(lock.toString()) -} - -// Remove all locks -func (c *Config) RemoveAllLocks() (err error) { - files, err := ioutil.ReadDir(c.Root) - if err != nil { - return - } - - for _, f := range files { - name := f.Name() - if strings.HasSuffix(name, ".lock") { - err = c.removeLockByString(name) - if err != nil { - return - } - } - } - - return -} diff --git a/pkg/internal/log/mod.go b/pkg/internal/log/mod.go deleted file mode 100644 index 9e4937b2..00000000 --- a/pkg/internal/log/mod.go +++ /dev/null @@ -1,76 +0,0 @@ -package log - -import ( - "fmt" - l "log" - "os" - "runtime" - "strings" - "time" - - "github.com/fatih/color" -) - -const ( - GO_LOG = "GO_LOG" -) - -func emit(label string, ctx string) { - l.SetFlags(0) - - // get time - t := time.Now().UTC().Format(time.RFC3339) - - // get file - _, file, _, _ := runtime.Caller(2) - file = file[:len(file)-3] - file = strings.ReplaceAll(file, "/", "::") - - // prints log - l.Println(fmt.Sprintf( - "%s%s %v %s%s %s", - color.New(color.FgHiBlack).Sprintf("["), - t, - label, - strings.SplitAfter(file, "shadow::")[1], - color.New(color.FgHiBlack).Sprintf("]"), - ctx, - )) -} - -func checkMode(modes []string) bool { - for _, m := range modes { - if strings.Contains(strings.ToLower(os.Getenv(GO_LOG)), strings.ToLower(m)) { - return true - } - } - - return false -} - -// Info logs -func Info(ctx string, a ...interface{}) { - if checkMode([]string{"INFO", "ALL"}) { - emit(color.GreenString("INFO "), fmt.Sprintf(ctx, a...)) - } - -} - -// Trace Logs -func Trace(ctx string, a ...interface{}) { - if checkMode([]string{"TRACE", "ALL"}) { - emit(color.New(color.FgHiBlack).Sprintf("TRACE"), fmt.Sprintf(ctx, a...)) - } -} - -// Warn Logs -func Warn(ctx string, a ...interface{}) { - if checkMode([]string{"WARN", "ALL"}) { - emit(color.YellowString("WARN "), fmt.Sprintf(ctx, a...)) - } -} - -// Warn Logs -func Error(ctx string, a ...interface{}) { - emit(color.RedString("ERROR"), fmt.Sprintf(ctx, a...)) -} diff --git a/pkg/internal/util/assert.go b/pkg/internal/util/assert.go deleted file mode 100644 index 8748d8f3..00000000 --- a/pkg/internal/util/assert.go +++ /dev/null @@ -1,35 +0,0 @@ -package util - -import ( - "os" - "reflect" - -<<<<<<< HEAD:pkg/shadow/util/assert.go - "github.com/darwinia-network/shadow/pkg/shadow/log" -======= - "github.com/darwinia-network/shadow/pkg/internal/log" ->>>>>>> next:pkg/internal/util/assert.go -) - -// Check if is empty -func IsEmpty(x interface{}) bool { - if x == nil { - return true - } - return reflect.DeepEqual(x, reflect.Zero(reflect.TypeOf(x)).Interface()) -} - -// Assert error and exit process -func Assert(err error) { - if err != nil { - log.Error("%v", err) - os.Exit(1) - } -} - -// Assert error and exit process -func AssertEmpty(v interface{}) { - if IsEmpty(v) { - log.Error("Empty interface") - } -} diff --git a/pkg/internal/util/collection.go b/pkg/internal/util/collection.go deleted file mode 100644 index 3f8ab696..00000000 --- a/pkg/internal/util/collection.go +++ /dev/null @@ -1,21 +0,0 @@ -package util - -// Filter string array -func Filter(vs []string, f func(int, string) bool) []string { - vsf := make([]string, 0) - for i, v := range vs { - if f(i, v) { - vsf = append(vsf, v) - } - } - return vsf -} - -// Map string array -func Map(vs []string, f func(int, string) string) []string { - vsm := make([]string, len(vs)) - for i, v := range vs { - vsm[i] = f(i, v) - } - return vsm -} diff --git a/pkg/internal/util/encode.go b/pkg/internal/util/encode.go deleted file mode 100644 index 8e5c2351..00000000 --- a/pkg/internal/util/encode.go +++ /dev/null @@ -1,303 +0,0 @@ -package util - -import ( - "encoding/hex" - "fmt" - "math/big" - "path/filepath" - "sort" - "strconv" - "strings" - - gmath "github.com/ethereum/go-ethereum/common/math" - "github.com/huandu/xstrings" - "github.com/shopspring/decimal" - "github.com/ttacon/libphonenumber" - "github.com/tuvistavie/securerandom" -) - -func NumberOrString(ns interface{}) (interface{}, error) { - switch t := ns.(type) { - case uint64: - return t, nil - case string: - r, err := strconv.ParseUint(t, 10, 64) - if err != nil { - return t, nil - } - return r, nil - default: - return "", fmt.Errorf("Parse %v failed", t) - } -} - -func RandStr(length int) string { - str, _ := securerandom.Hex(length) - return str -} - -func SnakeString(s string) string { - return strings.ToLower(xstrings.ToSnakeCase(s)) -} - -func CamelString(s string) string { - return xstrings.ToCamelCase(s) -} - -func Padding(str string) string { - str = strings.TrimPrefix(str, "0x") - return xstrings.RightJustify(str, 64, "0") -} - -func PaddingF(str string) string { - str = strings.TrimPrefix(str, "0x") - return xstrings.RightJustify(str, 64, "f") -} - -func StringInSlice(a string, list []string) bool { - for _, b := range list { - if b == a { - return true - } - } - return false -} - -func IntInSlice(a int, list []int) bool { - for _, b := range list { - if b == a { - return true - } - } - return false -} - -func ToWei(v int64) *big.Int { - return big.NewInt(v).Mul(big.NewInt(v), big.NewInt(int64(10)).Exp(big.NewInt(int64(10)), big.NewInt(int64(18)), nil)) -} -func EthToWei(v decimal.Decimal) *big.Int { - decimalStr := v.Mul(decimal.NewFromFloat(1e18)).String() - wei, _ := new(big.Int).SetString(decimalStr, 10) - return wei -} - -func BigToDecimal(v *big.Int) decimal.Decimal { - return decimal.NewFromBigInt(v, 0).Div(decimal.NewFromFloat(1e18)) -} - -func AddHex(s string, chain ...string) string { - prefix := "0x" - addr := s - if len(chain) > 0 { - switch chain[0] { - case "Tron": - prefix = "41" - case "Eth": - prefix = "0x" - case "PChain": - prefix = "0p" - } - } - if strings.HasPrefix(addr, prefix) { - return addr - } - return strings.ToLower(prefix + addr) -} - -func U256(v string) *big.Int { - v = strings.TrimPrefix(v, "0x") - bn := new(big.Int) - bn.SetString(v, 16) - return gmath.U256(bn) -} - -func DecodeInputU256(i *big.Int) string { - if i.Sign() == -1 { - pow := BigIntLog(new(big.Int).Abs(i), big.NewInt(16)) - newHex := big.NewInt(16).Exp(big.NewInt(16), pow, nil) - newHex = newHex.Add(newHex, i) - return PaddingF(fmt.Sprintf("%x", newHex)) - } else { - return fmt.Sprintf("%064s", fmt.Sprintf("%x", i)) - } -} - -func IntToString(i int) string { - return strconv.Itoa(i) -} - -func StringToInt(s string) int { - if i, err := strconv.Atoi(s); err != nil { - return 0 - } else { - return i - } - -} - -func StringToInt64(s string) int64 { - if i, err := strconv.ParseInt(s, 10, 64); err != nil { - return 0 - } else { - return i - } -} - -func IntToHex(i interface{}) string { - return fmt.Sprintf("0x%x", i) -} - -func BigIntLog(i *big.Int, n *big.Int) *big.Int { - c := big.NewInt(1) - for { - quotient := new(big.Int).Quo(i, n) - if quotient.Sign() != 1 { // quot >= n - break - } else { - c = c.Add(c, big.NewInt(1)) - i = quotient - } - } - return c - -} - -func DealNegU256(s string) *big.Int { - index := strings.IndexFunc(s, isSlash) - fis := new(big.Int) - exp := 0 - if index != -1 { - fis = U256(s[index:]) - exp = len(s) - index - } - pos := new(big.Int).Exp(big.NewInt(16), big.NewInt(int64(exp)), nil) - return new(big.Int).Sub(fis, pos) -} - -func EncodeU256(s string) *big.Int { - if s[0] == 'f' { - return DealNegU256(s) - } else { - return U256(s) - } -} -func ResourceDecode(r string) []int { - var resource []int - resourceEnum := [5]int{0, 1, 2, 3, 4} - for _, index := range resourceEnum { - b := EncodeU256(r) - fs := new(big.Int).Lsh(big.NewInt(65535), uint(16*index)) - ss := new(big.Int).And(b, fs) - ts := new(big.Int).Rsh(ss, uint(16*index)) - resource = append(resource, int(ts.Int64())) - } - return resource -} - -func isSlash(r rune) bool { - return r != 'f' -} - -func GetFileType(uploadFilePath string) string { - fileType := strings.TrimPrefix(filepath.Ext(uploadFilePath), ".") - return fileType -} - -func AppendIfMissing(slice []string, i string) []string { - for _, ele := range slice { - if ele == i { - return slice - } - } - return append(slice, i) -} - -// mobile like +86 151 8888 9998 -func BlurryMobile(mobile string) string { - mobileSlice := strings.Split(mobile, " ") - mobile = strings.Join(mobileSlice[1:], "") - return mobile[0:3] + "*****" + mobile[len(mobile)-3:] -} - -func AnalysisMobile(mobile, region string) string { - if mobile == "" { - return "" - } - if region == "" { - region = "CN" - } - num, err := libphonenumber.Parse(mobile, region) - if err != nil { - return mobile - } - return libphonenumber.Format(num, libphonenumber.INTERNATIONAL) -} - -func TrimHex(s string) string { - return strings.TrimPrefix(s, "0x") -} -func TrimTronHex(s string) string { - return strings.TrimPrefix(s, "41") -} - -type Pair struct { - Key string - Value int -} - -type PairList []Pair - -func (p PairList) Len() int { return len(p) } -func (p PairList) Less(i, j int) bool { return p[i].Value < p[j].Value } -func (p PairList) Swap(i, j int) { p[i], p[j] = p[j], p[i] } - -func RankByWordCount(wordFrequencies map[string]int) PairList { - pl := make(PairList, len(wordFrequencies)) - i := 0 - for k, v := range wordFrequencies { - pl[i] = Pair{k, v} - i++ - } - sort.Sort(sort.Reverse(pl)) - return pl -} - -func StringsIntersection(a []string, b []string) []string { - var refresh []string - for _, v := range a { - if StringInSlice(v, b) { - refresh = append(refresh, v) - } - } - return refresh -} - -func StringsExclude(a []string, b []string) []string { - var refresh []string - for _, v := range a { - if !StringInSlice(v, b) { - refresh = append(refresh, v) - } - } - return refresh -} - -func BoolToString(b bool) string { - if b { - return "true" - } - return "false" -} - -func HexToBytes(s string) []byte { - s = strings.TrimPrefix(s, "0x") - c := make([]byte, hex.DecodedLen(len(s))) - _, _ = hex.Decode(c, []byte(s)) - return c -} - -func BytesToHex(b []byte) string { - c := make([]byte, hex.EncodedLen(len(b))) - hex.Encode(c, b) - return string(c) -} From d6e5c5b319c3ddac9e9b5f8ff8ecd026f92afc30 Mon Sep 17 00:00:00 2001 From: clearloop Date: Fri, 28 Aug 2020 11:40:49 +0800 Subject: [PATCH 17/36] fix(cgo): enable cgo mod and add libc6-compat to alpine --- Dockerfile | 2 +- build.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1d312a69..cf092935 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM rust:alpine as shadow ARG DEBIAN_FRONTEND=noninteractive ENV TZ=America/Los_Angeles COPY . shadow -RUN apk add --no-cache openssl-dev sqlite-dev gcc go musl-dev\ +RUN apk add --no-cache openssl-dev sqlite-dev gcc go libc6-compat musl-dev\ && cd shadow \ && cargo build --release diff --git a/build.rs b/build.rs index b15e506c..39ad5408 100644 --- a/build.rs +++ b/build.rs @@ -11,13 +11,15 @@ fn main() { .to_string_lossy() .to_string(); - env::set_var("CGO_ENABLED", "0"); + // env::set_var("CGO_ENABLED", "0"); + // env::set_var("GO111MODULE", "on"); Command::new("go") .args(&[ "build", "-o", &format!("{}/libdarwinia_shadow.a", out_dir), "-buildmode=c-archive", + "-v", "pkg/shadow/ffi/mod.go", ]) .status() From 57034e507cf5e10589937b64a6f158403a20ae9e Mon Sep 17 00:00:00 2001 From: clearloop Date: Fri, 28 Aug 2020 16:54:36 +0800 Subject: [PATCH 18/36] perf(linker): use dynamic linker to invoke diesel libraries in musl --- .github/workflows/shadow.yml | 6 ++++-- build.rs | 27 +++++++++++++++------------ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/.github/workflows/shadow.yml b/.github/workflows/shadow.yml index 99fbef33..d16a0930 100644 --- a/.github/workflows/shadow.yml +++ b/.github/workflows/shadow.yml @@ -33,6 +33,8 @@ jobs: path: ./target key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./Cargo.lock') }} - name: Build - run: cargo build -vv + run: cargo build --release -vv + - name: Check Binary + run: ./target/release/shadow version - name: Run tests - run: cargo test -vv + run: cargo test --release -vv diff --git a/build.rs b/build.rs index 39ad5408..8b8a95d4 100644 --- a/build.rs +++ b/build.rs @@ -1,4 +1,4 @@ -use std::{env, process::Command}; +use std::process::Command; fn main() { // pre-check @@ -6,26 +6,29 @@ fn main() { println!("cargo:rerun-if-changed=path/to/Cargo.lock"); // build libdarwinia_shadow - let out_dir = env::var_os("OUT_DIR") - .unwrap() - .to_string_lossy() - .to_string(); + let ext = + match String::from_utf8_lossy(Command::new("uname").output().unwrap().stdout.as_slice()) + .into_owned() + .trim_end() + .as_ref() + { + "Darwin" => "dylib", + _ => "so", + }; - // env::set_var("CGO_ENABLED", "0"); - // env::set_var("GO111MODULE", "on"); + let lib = format!("/usr/local/lib/libdarwinia_shadow.{}", ext); Command::new("go") .args(&[ "build", "-o", - &format!("{}/libdarwinia_shadow.a", out_dir), - "-buildmode=c-archive", + &lib, + "-buildmode=c-shared", "-v", "pkg/shadow/ffi/mod.go", ]) .status() .unwrap(); - // post-check - println!("cargo:rustc-link-lib=static=darwinia_shadow"); - println!("cargo:rustc-link-search={}", out_dir); + // link to dynamic library + println!("cargo:rustc-link-lib=darwinia_shadow"); } From e325bd09990ef3e955a80091a960603efd77364d Mon Sep 17 00:00:00 2001 From: clearloop Date: Fri, 28 Aug 2020 17:51:01 +0800 Subject: [PATCH 19/36] feat(docker): complete the dockerfile of alpine --- .github/workflows/shadow.yml | 2 +- Cargo.toml | 1 - Dockerfile | 21 +++++++++++++++++++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/.github/workflows/shadow.yml b/.github/workflows/shadow.yml index d16a0930..c84d7a2d 100644 --- a/.github/workflows/shadow.yml +++ b/.github/workflows/shadow.yml @@ -35,6 +35,6 @@ jobs: - name: Build run: cargo build --release -vv - name: Check Binary - run: ./target/release/shadow version + run: ./target/release/shadow --version - name: Run tests run: cargo test --release -vv diff --git a/Cargo.toml b/Cargo.toml index 7bc4966e..d8534b93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,6 @@ links = "darwinia_shadow" name = "shadow" path = "src/bin/shadow.rs" - [lib] path = "src/lib.rs" diff --git a/Dockerfile b/Dockerfile index cf092935..ef382c23 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,12 +3,29 @@ FROM rust:alpine as shadow ARG DEBIAN_FRONTEND=noninteractive ENV TZ=America/Los_Angeles COPY . shadow + +# Required dynamic libraries +# +# libdarwinia_shadow.so => /usr/local/lib/libdarwinia_shadow.so (0x7fd26af02000) +# libssl.so.1.1 => /lib/libssl.so.1.1 (0x7fd26ae81000) +# libcrypto.so.1.1 => /lib/libcrypto.so.1.1 (0x7fd26ac02000) +# libsqlite3.so.0 => /usr/lib/libsqlite3.so.0 (0x7fd26ab1a000) +# libc.musl-x86_64.so.1 => /lib/ld64.so.1 (0x7fd26bebb000) RUN apk add --no-cache openssl-dev sqlite-dev gcc go libc6-compat musl-dev\ + # && cp /lib/ld-musl-x86_64.so.1 /lib/ld64.so.1 \ && cd shadow \ - && cargo build --release + && cargo build --release \ + && mkdir /include \ + && cp target/release/shadow /include/ \ + && cp /lib/libssl.so.1.1 /include/ \ + && cp /lib/libcrypto.so.1.1 /include/ \ + && cp /lib//usr/lib/libsqlite3.so.0 /include/libsqlite3.so.0 \ + && cp /libc.musl-x86_64.so.1 /include/ld64.so.1 # Pull Shadow into a second stage deploy alpine container FROM alpine:latest -COPY --from=shadow /shadow/target/release/shadow /usr/local/bin/shadow +COPY --from=shadow /include /include +RUN mv /include/shadow /usr/local/bin/shadow \ + && mv /include/* /usr/local/lib/ EXPOSE 3000 ENTRYPOINT ["shadow"] From 73325eaa24535e82910c86c3ea8ac9b1c63e3c01 Mon Sep 17 00:00:00 2001 From: clearloop Date: Fri, 28 Aug 2020 18:56:20 +0800 Subject: [PATCH 20/36] chore(bump): bump versions to v.0.2.0 --- Cargo.toml | 2 +- Dockerfile | 5 ++-- README.md | 9 ++++-- examples/doctor.rs | 5 ++-- examples/runner.rs | 2 +- examples/uncle.rs | 5 ++-- src/api/eth/mod.rs | 6 ++-- src/api/eth/proposal.rs | 22 +++++++++++---- src/api/eth/receipt.rs | 10 +++++++ src/api/mod.rs | 2 +- src/chain/byte.rs | 8 +++--- src/cmd/mod.rs | 7 ++++- src/db/mod.rs | 1 + src/lib.rs | 61 ++++++++++++++++++++++++++++++++++++----- src/mmr/mod.rs | 14 ++++++++-- src/mmr/runner.rs | 14 ++++++---- src/mmr/store.rs | 5 +++- tests/mmr.rs | 5 ++-- tests/mock/mod.rs | 2 +- 19 files changed, 138 insertions(+), 47 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d8534b93..7c0066d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "darwinia-shadow" -version = "0.0.3" +version = "0.2.0" authors = ["clearloop "] edition = "2018" description = "The shadow service for relayers and verify workers to retrieve header data and generate proof." diff --git a/Dockerfile b/Dockerfile index ef382c23..4e96cac3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,14 +12,13 @@ COPY . shadow # libsqlite3.so.0 => /usr/lib/libsqlite3.so.0 (0x7fd26ab1a000) # libc.musl-x86_64.so.1 => /lib/ld64.so.1 (0x7fd26bebb000) RUN apk add --no-cache openssl-dev sqlite-dev gcc go libc6-compat musl-dev\ - # && cp /lib/ld-musl-x86_64.so.1 /lib/ld64.so.1 \ && cd shadow \ - && cargo build --release \ + && cargo build --release -vv\ && mkdir /include \ && cp target/release/shadow /include/ \ && cp /lib/libssl.so.1.1 /include/ \ && cp /lib/libcrypto.so.1.1 /include/ \ - && cp /lib//usr/lib/libsqlite3.so.0 /include/libsqlite3.so.0 \ + && cp /usr/lib/libsqlite3.so.0 /include/libsqlite3.so.0 \ && cp /libc.musl-x86_64.so.1 /include/ld64.so.1 # Pull Shadow into a second stage deploy alpine container diff --git a/README.md b/README.md index 5219602f..70f09568 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,16 @@ # Shadow [![Shadow][workflow-badge]][github] +[![crate](https://img.shields.io/crates/v/darwinia-shadow.svg)](https://crates.io/crates/elvis) +[![doc](https://img.shields.io/badge/current-docs-brightgreen.svg)](https://docs.rs/darwinia_shadow/) +[![LICENSE](https://img.shields.io/crates/l/darwinia-shadow.svg)](https://choosealicense.com/licenses/gpl-3.0/) The shadow service for relayers and verify workers to retrieve header data and generate proof. Shadow will index the data it needs from blockchain nodes, such as Ethereum and Darwinia. ## Usage ```sh -shadow 0.1.0 +shadow 0.2.0 USAGE: shadow @@ -31,8 +34,8 @@ $ cargo install darwinia-shadow ### Note -+ Please make sure you have golang installed in your machine -+ Please make sure you have installed the sqlite3 library in your machine ++ Please make sure you have `golang` installed in your machine ++ Please make sure you have `sqlite3` installed in your machine ## Trouble Shooting diff --git a/examples/doctor.rs b/examples/doctor.rs index 9264fc20..d10e9862 100644 --- a/examples/doctor.rs +++ b/examples/doctor.rs @@ -1,9 +1,8 @@ //! Mock the uncle block use cmmr::{leaf_index_to_mmr_size, MMR}; use darwinia_shadow::{ - hash::{MergeHash, H256}, - pool, - store::Store, + db::pool, + mmr::{MergeHash, Store, H256}, }; fn main() { diff --git a/examples/runner.rs b/examples/runner.rs index 6cb61b67..e4c0bb6f 100644 --- a/examples/runner.rs +++ b/examples/runner.rs @@ -1,4 +1,4 @@ -use darwinia_shadow::{pool, Runner}; +use darwinia_shadow::{db::pool, mmr::Runner}; fn main() { env_logger::init(); diff --git a/examples/uncle.rs b/examples/uncle.rs index 045f999c..5d1e9362 100644 --- a/examples/uncle.rs +++ b/examples/uncle.rs @@ -1,9 +1,8 @@ //! Mock the uncle block use cmmr::MMR; use darwinia_shadow::{ - hash::{MergeHash, H256}, - pool, - store::Store, + db::pool, + mmr::{MergeHash, Store, H256}, }; use std::env; diff --git a/src/api/eth/mod.rs b/src/api/eth/mod.rs index 56bc9b17..ee31c99e 100644 --- a/src/api/eth/mod.rs +++ b/src/api/eth/mod.rs @@ -3,5 +3,7 @@ mod ffi; mod proposal; mod receipt; -pub use proposal::handle as proposal; -pub use receipt::handle as receipt; +pub use self::{ + proposal::{handle as proposal, ProposalReq}, + receipt::handle as receipt, +}; diff --git a/src/api/eth/proposal.rs b/src/api/eth/proposal.rs index 52994948..77193838 100644 --- a/src/api/eth/proposal.rs +++ b/src/api/eth/proposal.rs @@ -1,9 +1,8 @@ use crate::{ bytes, chain::eth::{EthHeader, EthHeaderJson, EthashProof, EthashProofJson}, - hash::{MergeHash, H256}, - pool, - store::Store, + db::pool, + mmr::{MergeHash, Store, H256}, }; use actix_web::{web, Responder}; use cmmr::MMR; @@ -13,8 +12,10 @@ use scale::Decode; /// Proposal post req #[derive(Deserialize)] pub struct ProposalReq { - members: Vec, - last_leaf: u64, + /// MMR members + pub members: Vec, + /// The last leaf of mmr proof + pub last_leaf: u64, } impl ProposalReq { @@ -94,6 +95,17 @@ pub struct ProposalHeader { } /// Proposal Handler +/// +/// ``` +/// use darwinia_shadow::api::eth; +/// use actix_web::web; +/// +/// // POST `/eth/proposal` +/// eth::proposal(web::Json(eth::ProposalReq{ +/// members: vec![19], +/// last_leaf: 19, +/// })); +/// ``` pub async fn handle(req: web::Json) -> impl Responder { web::Json(req.0.headers().await) } diff --git a/src/api/eth/receipt.rs b/src/api/eth/receipt.rs index af458344..076b9fcc 100644 --- a/src/api/eth/receipt.rs +++ b/src/api/eth/receipt.rs @@ -16,6 +16,16 @@ impl From<(String, String)> for ReceiptResp { } /// Receipt Handler +/// +/// ``` +/// use darwinia_shadow::api::eth; +/// use actix_web::web; +/// +/// // GET `/eth/receipt/0x3b82a55f5e752c23359d5c3c4c3360455ce0e485ed37e1faabe9ea10d5db3e7a` +/// eth::receipt(web::Path::from( +/// "0x3b82a55f5e752c23359d5c3c4c3360455ce0e485ed37e1faabe9ea10d5db3e7a".to_string(), +/// )); +/// ``` pub async fn handle(tx: web::Path) -> impl Responder { web::Json(Into::::into(super::ffi::receipt( tx.to_string(), diff --git a/src/api/mod.rs b/src/api/mod.rs index 5067108b..1411604b 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,7 +1,7 @@ //! The API server of Shadow use actix_web::{middleware, web, App, HttpServer}; -mod eth; +pub mod eth; /// Run HTTP Server pub async fn serve(port: u16) -> std::io::Result<()> { diff --git a/src/chain/byte.rs b/src/chain/byte.rs index 1e42c9d8..ec66095a 100644 --- a/src/chain/byte.rs +++ b/src/chain/byte.rs @@ -21,7 +21,7 @@ macro_rules! hex { }}; } -/// Convert hext to `Vec` or `[u8; n]` +/// Convert hex string to `Vec` or `[u8; n]` #[macro_export] macro_rules! bytes { // Convert hex to Vec @@ -46,9 +46,9 @@ macro_rules! bytes { }}; } -/// Serde for big array +/// Implement serde for big array #[macro_export] -macro_rules! array { +macro_rules! serde_array { ($len:expr) => { impl<'de, T> BigArray<'de> for [T; $len] where @@ -110,7 +110,7 @@ macro_rules! array { #[macro_export] macro_rules! construct_hash_bytes { ( $(#[$attr:meta])* $visibility:vis struct $name:ident ( $len:tt ); ) => { - array!($len); + serde_array!($len); doc_comment!{ concat!("The ", stringify!($len), "-bit hash type."), diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs index b4e63e05..7bbf5a71 100644 --- a/src/cmd/mod.rs +++ b/src/cmd/mod.rs @@ -1,5 +1,10 @@ //! `shadow` command -use crate::{api, mmr::helper, pool, result::Error, Runner}; +use crate::{ + api, + db::pool, + mmr::{helper, Runner}, + result::Error, +}; use structopt::{clap::AppSettings, StructOpt}; #[derive(StructOpt)] diff --git a/src/db/mod.rs b/src/db/mod.rs index 07ed7783..6a3ae8be 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1,3 +1,4 @@ +//! The database of shadow service pub mod model; pub mod pool; pub mod schema; diff --git a/src/lib.rs b/src/lib.rs index 6d0de288..58399d5c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,55 @@ -//! Darwinia MMR Implementation +//! # Shadow +//! +//! [![Shadow][workflow-badge]][github] +//! [![crate](https://img.shields.io/crates/v/darwinia-shadow.svg)](https://crates.io/crates/elvis) +//! [![doc](https://img.shields.io/badge/current-docs-brightgreen.svg)](https://docs.rs/darwinia_shadow/) +//! [![LICENSE](https://img.shields.io/crates/l/darwinia-shadow.svg)](https://choosealicense.com/licenses/gpl-3.0/) +//! +//! The shadow service for relayers and verify workers to retrieve header data and generate proof. Shadow will index the data it needs from blockchain nodes, such as Ethereum and Darwinia. +//! +//! ## Usage +//! +//! ```sh +//! shadow 0.2.0 +//! +//! USAGE: +//! shadow +//! +//! FLAGS: +//! -h, --help Prints help information +//! -V, --version Prints version information +//! +//! SUBCOMMANDS: +//! count Current block height in mmr store +//! help Prints this message or the help of the given subcommand(s) +//! run Start shadow service +//! trim Trim mmr from target leaf +//! ``` +//! +//! ## Download +//! +//! ```sh +//! $ cargo install darwinia-shadow +//! ``` +//! +//! ### Note +//! +//! + Please make sure you have `golang` installed in your machine +//! + Please make sure you have `sqlite3` installed in your machine +//! +//! +//! ## Trouble Shooting +//! +//! Everytime you run `proof` in error, please delete `~/.ethashproof` and `~/.ethash` +//! and retry. +//! +//! ## LICENSE +//! +//! GPL-3.0 +//! +//! +//! [github]: https://github.com/darwinia-network/shadow +//! [workflow-badge]: https://github.com/darwinia-network/shadow/workflows/shadow/badge.svg #![warn(missing_docs)] #![allow(clippy::transmute_ptr_to_ptr)] #![allow(clippy::ptr_offset_with_cast)] @@ -14,14 +65,10 @@ extern crate log; extern crate serde; mod conf; -mod db; -mod mmr; mod result; pub mod api; pub mod chain; pub mod cmd; -pub use self::{ - db::{model, pool, schema, sql}, - mmr::{hash, helper, runner::Runner, store}, -}; +pub mod db; +pub mod mmr; diff --git a/src/mmr/mod.rs b/src/mmr/mod.rs index 16f4b031..37da46ff 100644 --- a/src/mmr/mod.rs +++ b/src/mmr/mod.rs @@ -1,4 +1,12 @@ -pub mod hash; +//! Shdaow service mmr implementation pub mod helper; -pub mod runner; -pub mod store; + +mod hash; +mod runner; +mod store; + +pub use self::{ + hash::{MergeHash, H256}, + runner::Runner, + store::Store, +}; diff --git a/src/mmr/runner.rs b/src/mmr/runner.rs index 04256d4e..ef1953ef 100644 --- a/src/mmr/runner.rs +++ b/src/mmr/runner.rs @@ -1,12 +1,16 @@ //! MMR Runner use crate::{ chain::eth::EthHeaderRPCResp, - hash::{MergeHash, H256}, - helper, - pool::{ConnPool, PooledConn}, + db::{ + pool::{ConnPool, PooledConn}, + schema::mmr_store::dsl::*, + }, + mmr::{ + hash::{MergeHash, H256}, + helper, + store::Store, + }, result::Error, - schema::mmr_store::dsl::*, - store::Store, }; use cmmr::MMR; use diesel::{dsl::count, prelude::*}; diff --git a/src/mmr/store.rs b/src/mmr/store.rs index 124ddf44..b0d04c3a 100644 --- a/src/mmr/store.rs +++ b/src/mmr/store.rs @@ -1,5 +1,8 @@ //! MMR store -use crate::{hash::H256, model::*, pool::ConnPool, schema::mmr_store::dsl::*, sql::*}; +use crate::{ + db::{model::*, pool::ConnPool, schema::mmr_store::dsl::*, sql::*}, + mmr::hash::H256, +}; use cmmr::{Error, MMRStore, Result as MMRResult}; use diesel::{dsl::count, prelude::*}; diff --git a/tests/mmr.rs b/tests/mmr.rs index d64cb50c..bb538c5a 100644 --- a/tests/mmr.rs +++ b/tests/mmr.rs @@ -1,8 +1,7 @@ use cmmr::{Merge, MMR}; use darwinia_shadow::{ - hash::{MergeHash, H256}, - helper, pool, - store::Store, + db::pool, + mmr::{helper, MergeHash, Store, H256}, }; use std::{env, fs, path::PathBuf}; diff --git a/tests/mock/mod.rs b/tests/mock/mod.rs index 62e7789e..32d9bbe8 100644 --- a/tests/mock/mod.rs +++ b/tests/mock/mod.rs @@ -16,7 +16,7 @@ use scale::Decode; use darwinia_shadow::{ bytes, chain::eth::{EthHeader, EthashProof}, - hash::H256, + mmr::H256, }; /// Hash array for tests From b22930b1bb61961fb2862ba46e27415e44abeea5 Mon Sep 17 00:00:00 2001 From: clearloop Date: Fri, 28 Aug 2020 19:12:02 +0800 Subject: [PATCH 21/36] fix(ci): update LD_LIBRARY_PATH for ubuntu --- .github/workflows/shadow.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/shadow.yml b/.github/workflows/shadow.yml index c84d7a2d..ef2789bf 100644 --- a/.github/workflows/shadow.yml +++ b/.github/workflows/shadow.yml @@ -23,6 +23,7 @@ jobs: else sudo apt-get update -y sudo apt-get install -y libsqlite3-dev libdbus-1-dev + export LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib fi # Cache MMR Library - name: Cache MMR Library From dd9ee1969f1dc85a00f01bc5f3c0fe2d69ab49a9 Mon Sep 17 00:00:00 2001 From: clearloop Date: Fri, 28 Aug 2020 20:10:24 +0800 Subject: [PATCH 22/36] fix(linker): use rustc-link-search to find libdarwinia_shadow in ubuntu --- Dockerfile | 21 +++++++++++---------- build.rs | 4 ++-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4e96cac3..ea3e760e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,20 +11,21 @@ COPY . shadow # libcrypto.so.1.1 => /lib/libcrypto.so.1.1 (0x7fd26ac02000) # libsqlite3.so.0 => /usr/lib/libsqlite3.so.0 (0x7fd26ab1a000) # libc.musl-x86_64.so.1 => /lib/ld64.so.1 (0x7fd26bebb000) -RUN apk add --no-cache openssl-dev sqlite-dev gcc go libc6-compat musl-dev\ +RUN apk add --no-cache openssl-dev sqlite-dev gcc go \ && cd shadow \ && cargo build --release -vv\ - && mkdir /include \ - && cp target/release/shadow /include/ \ - && cp /lib/libssl.so.1.1 /include/ \ - && cp /lib/libcrypto.so.1.1 /include/ \ - && cp /usr/lib/libsqlite3.so.0 /include/libsqlite3.so.0 \ - && cp /libc.musl-x86_64.so.1 /include/ld64.so.1 + && mkdir /target \ + && cp target/release/shadow /target/ \ + && cp /usr/lib/libsqlite3.so.0 /target/libsqlite3.so.0 \ + && cp /usr/local/lib/libdarwinia_shadow.so /target/libdarwinia_shadow.so # Pull Shadow into a second stage deploy alpine container FROM alpine:latest -COPY --from=shadow /include /include -RUN mv /include/shadow /usr/local/bin/shadow \ - && mv /include/* /usr/local/lib/ +COPY --from=shadow /target /target +RUN mv /target/shadow /usr/local/bin/shadow \ + && mv /target/libsqlite3.so.0 /usr/lib/libsqlite3.so.0 \ + && mv /target/libdarwinia_shadow.so /usr/local/lib/libdarwinia_shadow.so \ + && cp /lib/libc.musl-x86_64.so.1 /lib/ld64.so.1 \ + && rm -rf /target EXPOSE 3000 ENTRYPOINT ["shadow"] diff --git a/build.rs b/build.rs index 8b8a95d4..443539d1 100644 --- a/build.rs +++ b/build.rs @@ -15,7 +15,6 @@ fn main() { "Darwin" => "dylib", _ => "so", }; - let lib = format!("/usr/local/lib/libdarwinia_shadow.{}", ext); Command::new("go") .args(&[ @@ -29,6 +28,7 @@ fn main() { .status() .unwrap(); - // link to dynamic library + // link libdarwinia_shadow println!("cargo:rustc-link-lib=darwinia_shadow"); + println!("cargo:rustc-link-search=/usr/local/lib"); } From 0ee16e76870c9638590100b77a9815edd5afba8d Mon Sep 17 00:00:00 2001 From: clearloop Date: Fri, 28 Aug 2020 21:04:46 +0800 Subject: [PATCH 23/36] fix(ci): use OUT_DIR to customize the output of libdarwinia_shadow_ext --- Dockerfile | 4 ++-- build.rs | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index ea3e760e..e127e7bb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,9 +11,9 @@ COPY . shadow # libcrypto.so.1.1 => /lib/libcrypto.so.1.1 (0x7fd26ac02000) # libsqlite3.so.0 => /usr/lib/libsqlite3.so.0 (0x7fd26ab1a000) # libc.musl-x86_64.so.1 => /lib/ld64.so.1 (0x7fd26bebb000) -RUN apk add --no-cache openssl-dev sqlite-dev gcc go \ +RUN apk add --no-cache gcc go openssl-dev sqlite-dev\ && cd shadow \ - && cargo build --release -vv\ + && OUT_DIR=/usr/local/lib cargo build --release -vv\ && mkdir /target \ && cp target/release/shadow /target/ \ && cp /usr/lib/libsqlite3.so.0 /target/libsqlite3.so.0 \ diff --git a/build.rs b/build.rs index 443539d1..8b4fce9a 100644 --- a/build.rs +++ b/build.rs @@ -1,4 +1,4 @@ -use std::process::Command; +use std::{env, process::Command}; fn main() { // pre-check @@ -6,6 +6,7 @@ fn main() { println!("cargo:rerun-if-changed=path/to/Cargo.lock"); // build libdarwinia_shadow + let out_dir = env::var("OUT_DIR").unwrap(); let ext = match String::from_utf8_lossy(Command::new("uname").output().unwrap().stdout.as_slice()) .into_owned() @@ -15,7 +16,7 @@ fn main() { "Darwin" => "dylib", _ => "so", }; - let lib = format!("/usr/local/lib/libdarwinia_shadow.{}", ext); + let lib = format!("{}/libdarwinia_shadow.{}", out_dir, ext); Command::new("go") .args(&[ "build", @@ -30,5 +31,5 @@ fn main() { // link libdarwinia_shadow println!("cargo:rustc-link-lib=darwinia_shadow"); - println!("cargo:rustc-link-search=/usr/local/lib"); + println!("cargo:rustc-link-search={}", out_dir); } From a7146dab895c551d07c5c0cf24c857201425cace Mon Sep 17 00:00:00 2001 From: clearloop Date: Fri, 28 Aug 2020 22:58:55 +0800 Subject: [PATCH 24/36] fix(dylib): adapt the loading process of dynamic link for common linux --- Dockerfile | 3 ++- build.rs | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index e127e7bb..3a7e2e8f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,7 @@ # Build Shadow in a stock rust builder container FROM rust:alpine as shadow ARG DEBIAN_FRONTEND=noninteractive +ENV DARWINIA_SHADOW_LIBRARY=/usr/local/lib ENV TZ=America/Los_Angeles COPY . shadow @@ -13,7 +14,7 @@ COPY . shadow # libc.musl-x86_64.so.1 => /lib/ld64.so.1 (0x7fd26bebb000) RUN apk add --no-cache gcc go openssl-dev sqlite-dev\ && cd shadow \ - && OUT_DIR=/usr/local/lib cargo build --release -vv\ + && cargo build --release -vv --out-dir /usr/local/lib/\ && mkdir /target \ && cp target/release/shadow /target/ \ && cp /usr/lib/libsqlite3.so.0 /target/libsqlite3.so.0 \ diff --git a/build.rs b/build.rs index 8b4fce9a..e71b624f 100644 --- a/build.rs +++ b/build.rs @@ -5,8 +5,9 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=path/to/Cargo.lock"); - // build libdarwinia_shadow - let out_dir = env::var("OUT_DIR").unwrap(); + // Get build paths + let out_dir = + env::var("DARWINIA_SHADOW_LIBRARY").unwrap_or_else(|_| env::var("OUT_DIR").unwrap()); let ext = match String::from_utf8_lossy(Command::new("uname").output().unwrap().stdout.as_slice()) .into_owned() @@ -17,6 +18,8 @@ fn main() { _ => "so", }; let lib = format!("{}/libdarwinia_shadow.{}", out_dir, ext); + + // Build the dynamic library Command::new("go") .args(&[ "build", @@ -29,7 +32,15 @@ fn main() { .status() .unwrap(); - // link libdarwinia_shadow + // Load dynamic libdarwinia_shadow.so in common linux + if ext.contains("so") && Command::new("ldconfig").args(&[&out_dir]).status().is_err() { + Command::new("sudo") + .args(&["ldconfig", &out_dir]) + .status() + .unwrap(); + } + + // post-check println!("cargo:rustc-link-lib=darwinia_shadow"); println!("cargo:rustc-link-search={}", out_dir); } From 7fc680a5825738d9071ced51ed16b566b20aa79c Mon Sep 17 00:00:00 2001 From: clearloop Date: Fri, 28 Aug 2020 23:03:11 +0800 Subject: [PATCH 25/36] fix(docker): remove the --out-dir flag for building with stable version rustc --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 3a7e2e8f..2d106e23 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ COPY . shadow # libc.musl-x86_64.so.1 => /lib/ld64.so.1 (0x7fd26bebb000) RUN apk add --no-cache gcc go openssl-dev sqlite-dev\ && cd shadow \ - && cargo build --release -vv --out-dir /usr/local/lib/\ + && cargo build --release -vv \ && mkdir /target \ && cp target/release/shadow /target/ \ && cp /usr/lib/libsqlite3.so.0 /target/libsqlite3.so.0 \ From 311c253104ce5c9d3e858e93a716e4b980d3a357 Mon Sep 17 00:00:00 2001 From: clearloop Date: Fri, 28 Aug 2020 23:16:07 +0800 Subject: [PATCH 26/36] fix(dylib): adapt LD_LIBRARY_PATH for unix --- build.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/build.rs b/build.rs index e71b624f..5db25d4e 100644 --- a/build.rs +++ b/build.rs @@ -33,9 +33,13 @@ fn main() { .unwrap(); // Load dynamic libdarwinia_shadow.so in common linux - if ext.contains("so") && Command::new("ldconfig").args(&[&out_dir]).status().is_err() { + if Command::new("cp") + .args(&[&out_dir, "/usr/local/lib/"]) + .status() + .is_err() + { Command::new("sudo") - .args(&["ldconfig", &out_dir]) + .args(&["cp", &out_dir, "/usr/local/lib/"]) .status() .unwrap(); } From 7a6deb62ca810143a2ec9961f28274759d09417a Mon Sep 17 00:00:00 2001 From: clearloop Date: Fri, 28 Aug 2020 23:44:26 +0800 Subject: [PATCH 27/36] fix(dylib): force move and overwrite old libdarwinia_shadow_ext --- Dockerfile | 1 - build.rs | 11 +++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2d106e23..10deeebb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,6 @@ # Build Shadow in a stock rust builder container FROM rust:alpine as shadow ARG DEBIAN_FRONTEND=noninteractive -ENV DARWINIA_SHADOW_LIBRARY=/usr/local/lib ENV TZ=America/Los_Angeles COPY . shadow diff --git a/build.rs b/build.rs index 5db25d4e..d40a6c4d 100644 --- a/build.rs +++ b/build.rs @@ -6,8 +6,7 @@ fn main() { println!("cargo:rerun-if-changed=path/to/Cargo.lock"); // Get build paths - let out_dir = - env::var("DARWINIA_SHADOW_LIBRARY").unwrap_or_else(|_| env::var("OUT_DIR").unwrap()); + let out_dir = env::var("OUT_DIR").unwrap(); let ext = match String::from_utf8_lossy(Command::new("uname").output().unwrap().stdout.as_slice()) .into_owned() @@ -33,18 +32,18 @@ fn main() { .unwrap(); // Load dynamic libdarwinia_shadow.so in common linux - if Command::new("cp") - .args(&[&out_dir, "/usr/local/lib/"]) + if Command::new("mv") + .args(&[&lib, "/usr/local/lib/"]) .status() .is_err() { Command::new("sudo") - .args(&["cp", &out_dir, "/usr/local/lib/"]) + .args(&["mv", &lib, "/usr/local/lib/"]) .status() .unwrap(); } // post-check println!("cargo:rustc-link-lib=darwinia_shadow"); - println!("cargo:rustc-link-search={}", out_dir); + println!("cargo:rustc-link-search=/usr/local/lib"); } From 046bb8666fcfbc7a39586d3ec94d22d867e7d98e Mon Sep 17 00:00:00 2001 From: clearloop Date: Sat, 29 Aug 2020 00:11:41 +0800 Subject: [PATCH 28/36] chore(dylib): use sudo inside build.rs to try to fix perm in ubuntu --- build.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build.rs b/build.rs index d40a6c4d..18c47210 100644 --- a/build.rs +++ b/build.rs @@ -32,10 +32,11 @@ fn main() { .unwrap(); // Load dynamic libdarwinia_shadow.so in common linux - if Command::new("mv") + if !Command::new("mv") .args(&[&lib, "/usr/local/lib/"]) .status() - .is_err() + .unwrap() + .success() { Command::new("sudo") .args(&["mv", &lib, "/usr/local/lib/"]) From a88d807bab3ea9b1ce4edbe645a7cd2926b424ec Mon Sep 17 00:00:00 2001 From: clearloop Date: Sat, 29 Aug 2020 00:19:34 +0800 Subject: [PATCH 29/36] chore(dylib): use sudo inside build.rs to fix perm in ubuntu...again --- build.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/build.rs b/build.rs index 18c47210..c3dfa548 100644 --- a/build.rs +++ b/build.rs @@ -6,7 +6,8 @@ fn main() { println!("cargo:rerun-if-changed=path/to/Cargo.lock"); // Get build paths - let out_dir = env::var("OUT_DIR").unwrap(); + let out_dir = + env::var("DARWINIA_SHADOW_LIBRARY").unwrap_or_else(|_| env::var("OUT_DIR").unwrap()); let ext = match String::from_utf8_lossy(Command::new("uname").output().unwrap().stdout.as_slice()) .into_owned() @@ -37,11 +38,18 @@ fn main() { .status() .unwrap() .success() - { - Command::new("sudo") + && !Command::new("sudo") .args(&["mv", &lib, "/usr/local/lib/"]) .status() - .unwrap(); + .unwrap() + .success() + { + panic!( + "{}\n\n{}\n{}", + "It seems we don't have permission for moving our dynamic lib to `/usr/local/lib/`.", + "Please set `DARWINIA_SHADOW_LIBRARY` as an available link library path, and install", + "darwinia-shadow again~" + ) } // post-check From d45690fd571fa1e7b4d282cc92d0b3531119750a Mon Sep 17 00:00:00 2001 From: clearloop Date: Sat, 29 Aug 2020 09:16:56 +0800 Subject: [PATCH 30/36] fix(ci): ldconfig in ci after installing --- .github/workflows/shadow.yml | 8 ++++- README.md | 4 +++ build.rs | 66 +++++++++++++++++++----------------- 3 files changed, 45 insertions(+), 33 deletions(-) diff --git a/.github/workflows/shadow.yml b/.github/workflows/shadow.yml index ef2789bf..04025fee 100644 --- a/.github/workflows/shadow.yml +++ b/.github/workflows/shadow.yml @@ -36,6 +36,12 @@ jobs: - name: Build run: cargo build --release -vv - name: Check Binary - run: ./target/release/shadow --version + run: | + if [[ "$(uname)" == 'Darwin' ]]; then + sudo update_dyld_shared_cache + else + sudo ldconfig + fi + ./target/release/shadow --version - name: Run tests run: cargo test --release -vv diff --git a/README.md b/README.md index 70f09568..cd78ef3e 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,10 @@ $ cargo install darwinia-shadow + Please make sure you have `golang` installed in your machine + Please make sure you have `sqlite3` installed in your machine ++ If error like `No such file or directory` occurs when you launch your `shadow` + + Run `sudo update_dyld_shared_cache` in OSX + + Run `sudo ldconfig` in Linux + + Or set `LIBRARY_DARWINIA_SHADOW` as an avaiable path while compiling ## Trouble Shooting diff --git a/build.rs b/build.rs index c3dfa548..a5ad2590 100644 --- a/build.rs +++ b/build.rs @@ -1,13 +1,11 @@ -use std::{env, process::Command}; +use std::process::Command; fn main() { - // pre-check + // Pre-check println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=path/to/Cargo.lock"); - // Get build paths - let out_dir = - env::var("DARWINIA_SHADOW_LIBRARY").unwrap_or_else(|_| env::var("OUT_DIR").unwrap()); + // Declare build args let ext = match String::from_utf8_lossy(Command::new("uname").output().unwrap().stdout.as_slice()) .into_owned() @@ -17,42 +15,46 @@ fn main() { "Darwin" => "dylib", _ => "so", }; - let lib = format!("{}/libdarwinia_shadow.{}", out_dir, ext); + let lib = format!("/usr/local/lib/libdarwinia_shadow.{}", ext); + let args = vec![ + "build", + "-o", + &lib, + "-buildmode=c-shared", + "-v", + "pkg/shadow/ffi/mod.go", + ]; // Build the dynamic library - Command::new("go") - .args(&[ - "build", - "-o", - &lib, - "-buildmode=c-shared", - "-v", - "pkg/shadow/ffi/mod.go", - ]) - .status() - .unwrap(); - - // Load dynamic libdarwinia_shadow.so in common linux - if !Command::new("mv") - .args(&[&lib, "/usr/local/lib/"]) - .status() - .unwrap() - .success() + if !Command::new("go").args(&args).status().unwrap().success() && !Command::new("sudo") - .args(&["mv", &lib, "/usr/local/lib/"]) + .args(vec![vec!["go"], args].concat()) .status() .unwrap() .success() { panic!( - "{}\n\n{}\n{}", - "It seems we don't have permission for moving our dynamic lib to `/usr/local/lib/`.", - "Please set `DARWINIA_SHADOW_LIBRARY` as an available link library path, and install", - "darwinia-shadow again~" - ) + "{}{}", + "It seems we don't have permission to create our library at `/usr/local/lib`", + ", please get the permission and install darwinia-shadow again~" + ); + } + + if ext.contains("so") + && !Command::new("ldconfig") + .arg(&lib) + .status() + .unwrap() + .success() + && !Command::new("sudo") + .args(&["ldconfig", &lib]) + .status() + .unwrap() + .success() + { + panic!("Could update LD_LIBRARY_PATH"); } - // post-check + // Post-check println!("cargo:rustc-link-lib=darwinia_shadow"); - println!("cargo:rustc-link-search=/usr/local/lib"); } From 80d0e7e71ef75d6577d962afbeb95c870ea62bec Mon Sep 17 00:00:00 2001 From: clearloop Date: Sat, 29 Aug 2020 09:55:32 +0800 Subject: [PATCH 31/36] feat(eth): optimzie proof process and add dockerignore --- .dockerignore | 3 ++ pkg/shadow/eth/proof.go | 71 +++++++---------------------------------- 2 files changed, 14 insertions(+), 60 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..c7b6ab65 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +target +examples +tests \ No newline at end of file diff --git a/pkg/shadow/eth/proof.go b/pkg/shadow/eth/proof.go index 7018360a..e468aeb1 100644 --- a/pkg/shadow/eth/proof.go +++ b/pkg/shadow/eth/proof.go @@ -2,10 +2,7 @@ package eth import ( "fmt" - "io/ioutil" "math/big" - "os" - "path/filepath" "github.com/darwinia-network/shadow/pkg/ethashproof" "github.com/darwinia-network/shadow/pkg/ethashproof/ethash" @@ -64,64 +61,21 @@ func (o *ProofOutput) Format() []DoubleNodeWithMerkleProof { return dnmps } -// Epoch in background -func bgEpoch(epoch uint64, config *shadow.Config) { - _, _ = ethashproof.CalculateDatasetMerkleRoot(epoch, true) - _ = config.RemoveLock(shadow.EPOCH_LOCK) -} - -// Check if need epoch -func epochGently(epoch uint64, config *shadow.Config) error { - // Check if is epoching - if config.CheckLock(shadow.EPOCH_LOCK) { - return nil - } - - // Get home dir - home, err := os.UserHomeDir() - if err != nil { - return err - } - - // Find ethashproof cache - cache := filepath.Join(home, ETHASHPROOF_CACHE) - fs, err := ioutil.ReadDir(cache) - if err != nil { - return err - } - - // Check if has epoched - hasEpoched := false - for _, f := range fs { - if f.Name() == fmt.Sprintf("%v.json", epoch) { - hasEpoched = true - } - } - - // Create epoch lock - err = config.CreateLock(shadow.EPOCH_LOCK) - if err != nil { - return err - } - - // Run epoch - if !hasEpoched { - go bgEpoch(epoch, config) - } - - return nil -} - // Proof eth blockheader func Proof(header *types.Header, config *shadow.Config) (ProofOutput, error) { blockno := header.Number.Uint64() epoch := blockno / 30000 output := &ProofOutput{} + // Handle lock + if config.CheckLock(shadow.PROOF_LOCK) { + return *output, fmt.Errorf("ethashproof process is busy now") + } + // Get proof from cache cache, err := ethashproof.LoadCache(int(epoch)) if err != nil { - err = config.RemoveLock(shadow.EPOCH_LOCK) + err = config.CreateLock(shadow.PROOF_LOCK) if err != nil { return *output, err } @@ -135,6 +89,11 @@ func Proof(header *types.Header, config *shadow.Config) (ProofOutput, error) { if err != nil { return *output, err } + + err = config.RemoveLock(shadow.PROOF_LOCK) + if err != nil { + return *output, err + } } rlpheader, err := ethashproof.RLPHeader(header) @@ -182,13 +141,5 @@ func Proof(header *types.Header, config *shadow.Config) (ProofOutput, error) { } } - // Check if need pre-epoch - if blockno%30000 > 15000 { - err := epochGently(epoch, config) - if err != nil { - return *output, err - } - } - return *output, nil } From 28a4a1f41ead181e526f645ada8a1fdd2c0bc105 Mon Sep 17 00:00:00 2001 From: clearloop Date: Sat, 29 Aug 2020 10:18:02 +0800 Subject: [PATCH 32/36] chore(README): remove outdated lines --- README.md | 5 ++++- src/lib.rs | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cd78ef3e..76e833ca 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ The shadow service for relayers and verify workers to retrieve header data and generate proof. Shadow will index the data it needs from blockchain nodes, such as Ethereum and Darwinia. + ## Usage ```sh @@ -26,12 +27,14 @@ SUBCOMMANDS: trim Trim mmr from target leaf ``` + ## Download ```sh $ cargo install darwinia-shadow ``` + ### Note + Please make sure you have `golang` installed in your machine @@ -39,7 +42,6 @@ $ cargo install darwinia-shadow + If error like `No such file or directory` occurs when you launch your `shadow` + Run `sudo update_dyld_shared_cache` in OSX + Run `sudo ldconfig` in Linux - + Or set `LIBRARY_DARWINIA_SHADOW` as an avaiable path while compiling ## Trouble Shooting @@ -47,6 +49,7 @@ $ cargo install darwinia-shadow Everytime you run `proof` in error, please delete `~/.ethashproof` and `~/.ethash` and retry. + ## LICENSE GPL-3.0 diff --git a/src/lib.rs b/src/lib.rs index 58399d5c..8c2fce3d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,7 +36,9 @@ //! //! + Please make sure you have `golang` installed in your machine //! + Please make sure you have `sqlite3` installed in your machine -//! +//! + If error like `No such file or directory` occurs when you launch your `shadow` +//! + Run `sudo update_dyld_shared_cache` in OSX +//! + Run `sudo ldconfig` in Linux //! //! ## Trouble Shooting //! From ea86072311f1eb62b1cfcea4049bc70bf3f8438f Mon Sep 17 00:00:00 2001 From: clearloop Date: Sat, 29 Aug 2020 11:26:22 +0800 Subject: [PATCH 33/36] fix(docs.rs): removed all sudo commands, supports both dylink and static link for unix --- .github/workflows/shadow.yml | 8 +---- README.md | 3 -- build.rs | 65 +++++++++++++++--------------------- src/lib.rs | 3 -- 4 files changed, 28 insertions(+), 51 deletions(-) diff --git a/.github/workflows/shadow.yml b/.github/workflows/shadow.yml index 04025fee..ef2789bf 100644 --- a/.github/workflows/shadow.yml +++ b/.github/workflows/shadow.yml @@ -36,12 +36,6 @@ jobs: - name: Build run: cargo build --release -vv - name: Check Binary - run: | - if [[ "$(uname)" == 'Darwin' ]]; then - sudo update_dyld_shared_cache - else - sudo ldconfig - fi - ./target/release/shadow --version + run: ./target/release/shadow --version - name: Run tests run: cargo test --release -vv diff --git a/README.md b/README.md index 76e833ca..0eb2a2ef 100644 --- a/README.md +++ b/README.md @@ -39,9 +39,6 @@ $ cargo install darwinia-shadow + Please make sure you have `golang` installed in your machine + Please make sure you have `sqlite3` installed in your machine -+ If error like `No such file or directory` occurs when you launch your `shadow` - + Run `sudo update_dyld_shared_cache` in OSX - + Run `sudo ldconfig` in Linux ## Trouble Shooting diff --git a/build.rs b/build.rs index a5ad2590..6a419e6d 100644 --- a/build.rs +++ b/build.rs @@ -1,4 +1,4 @@ -use std::process::Command; +use std::{env, process::Command}; fn main() { // Pre-check @@ -6,7 +6,9 @@ fn main() { println!("cargo:rerun-if-changed=path/to/Cargo.lock"); // Declare build args - let ext = + let staticlib = format!("{}/libdarwinia_shadow.a", env::var("OUT_DIR").unwrap()); + let dylib = format!( + "/usr/local/lib/libdarwinia_shadow.{}", match String::from_utf8_lossy(Command::new("uname").output().unwrap().stdout.as_slice()) .into_owned() .trim_end() @@ -14,45 +16,32 @@ fn main() { { "Darwin" => "dylib", _ => "so", - }; - let lib = format!("/usr/local/lib/libdarwinia_shadow.{}", ext); - let args = vec![ - "build", - "-o", - &lib, - "-buildmode=c-shared", - "-v", - "pkg/shadow/ffi/mod.go", - ]; + } + ); - // Build the dynamic library - if !Command::new("go").args(&args).status().unwrap().success() - && !Command::new("sudo") - .args(vec![vec!["go"], args].concat()) - .status() - .unwrap() - .success() - { - panic!( - "{}{}", - "It seems we don't have permission to create our library at `/usr/local/lib`", - ", please get the permission and install darwinia-shadow again~" - ); - } + let args = |dynamic: bool| { + vec![ + "build", + "-o", + if dynamic { &dylib } else { &staticlib }, + if dynamic { + "-buildmode=c-shared" + } else { + "-buildmode=c-archived" + }, + "-v", + "pkg/shadow/ffi/mod.go", + ] + }; - if ext.contains("so") - && !Command::new("ldconfig") - .arg(&lib) - .status() - .unwrap() - .success() - && !Command::new("sudo") - .args(&["ldconfig", &lib]) - .status() - .unwrap() - .success() + // Build the link library + if !Command::new("go") + .args(&args(true)) + .status() + .unwrap() + .success() { - panic!("Could update LD_LIBRARY_PATH"); + Command::new("go").args(&args(false)).status().unwrap(); } // Post-check diff --git a/src/lib.rs b/src/lib.rs index 8c2fce3d..dd31fdfe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,9 +36,6 @@ //! //! + Please make sure you have `golang` installed in your machine //! + Please make sure you have `sqlite3` installed in your machine -//! + If error like `No such file or directory` occurs when you launch your `shadow` -//! + Run `sudo update_dyld_shared_cache` in OSX -//! + Run `sudo ldconfig` in Linux //! //! ## Trouble Shooting //! From d4047c1916d86f2d64058b70903a566741ef0f20 Mon Sep 17 00:00:00 2001 From: clearloop Date: Sat, 29 Aug 2020 11:34:00 +0800 Subject: [PATCH 34/36] chore(chains): remove outdated modules --- build.rs | 2 +- src/chain/mod.rs | 1 - src/chain/req.rs | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 src/chain/req.rs diff --git a/build.rs b/build.rs index 6a419e6d..0b20645e 100644 --- a/build.rs +++ b/build.rs @@ -27,7 +27,7 @@ fn main() { if dynamic { "-buildmode=c-shared" } else { - "-buildmode=c-archived" + "-buildmode=c-archive" }, "-v", "pkg/shadow/ffi/mod.go", diff --git a/src/chain/mod.rs b/src/chain/mod.rs index c7dc8d1d..cd02cff6 100644 --- a/src/chain/mod.rs +++ b/src/chain/mod.rs @@ -5,4 +5,3 @@ mod byte; // modules mod array; pub mod eth; -pub mod req; diff --git a/src/chain/req.rs b/src/chain/req.rs deleted file mode 100644 index 5236fd7a..00000000 --- a/src/chain/req.rs +++ /dev/null @@ -1 +0,0 @@ -//! Http client From 1f4237ea17b9a6e624b21185f7ffe296840229cd Mon Sep 17 00:00:00 2001 From: clearloop Date: Sat, 29 Aug 2020 12:14:59 +0800 Subject: [PATCH 35/36] fix(ci): force link-search out_dir while building static library --- build.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/build.rs b/build.rs index 0b20645e..858fb08c 100644 --- a/build.rs +++ b/build.rs @@ -6,7 +6,9 @@ fn main() { println!("cargo:rerun-if-changed=path/to/Cargo.lock"); // Declare build args - let staticlib = format!("{}/libdarwinia_shadow.a", env::var("OUT_DIR").unwrap()); + let mut dynamic = true; + let out_dir = env::var("OUT_DIR").unwrap(); + let staticlib = format!("{}/libdarwinia_shadow.a", out_dir); let dylib = format!( "/usr/local/lib/libdarwinia_shadow.{}", match String::from_utf8_lossy(Command::new("uname").output().unwrap().stdout.as_slice()) @@ -36,14 +38,22 @@ fn main() { // Build the link library if !Command::new("go") - .args(&args(true)) + .args(&args(dynamic)) .status() .unwrap() .success() { - Command::new("go").args(&args(false)).status().unwrap(); + dynamic = false; + Command::new("go").args(&args(dynamic)).status().unwrap(); + println!("built static library at {}", out_dir); } // Post-check - println!("cargo:rustc-link-lib=darwinia_shadow"); + if dynamic { + println!("cargo:rustc-link-search=/usr/local/lib"); + println!("cargo:rustc-link-lib=dylib=darwinia_shadow"); + } else { + println!("cargo:rustc-link-search={}", out_dir); + println!("cargo:rustc-link-lib=static=darwinia_shadow"); + } } From 732c0257256c43e2731cc9158b52088ddd4b3f40 Mon Sep 17 00:00:00 2001 From: clearloop Date: Sat, 29 Aug 2020 13:18:24 +0800 Subject: [PATCH 36/36] fix(typo): fix typo in badge link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0eb2a2ef..bcedd7b2 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Shadow [![Shadow][workflow-badge]][github] -[![crate](https://img.shields.io/crates/v/darwinia-shadow.svg)](https://crates.io/crates/elvis) +[![crate](https://img.shields.io/crates/v/darwinia-shadow.svg)](https://crates.io/crates/darwinia_shadow) [![doc](https://img.shields.io/badge/current-docs-brightgreen.svg)](https://docs.rs/darwinia_shadow/) [![LICENSE](https://img.shields.io/crates/l/darwinia-shadow.svg)](https://choosealicense.com/licenses/gpl-3.0/)