├── mlc_config.json
├── pkg
├── consts
│ ├── protocol_consts.go
│ └── app_consts.go
└── builder
│ ├── builder_options.go
│ ├── test
│ └── builder_test.go
│ └── builder.go
├── docker
├── priv_validator_state.json
├── entrypoint.sh
├── Dockerfile_ephemeral
└── Dockerfile.test
├── README.md
├── .gitignore
├── .golangci.yml
├── .markdownlint.yaml
├── third_party
└── proto
│ ├── tendermint
│ ├── libs
│ │ └── bits
│ │ │ └── types.proto
│ ├── crypto
│ │ ├── keys.proto
│ │ └── proof.proto
│ ├── types
│ │ ├── evidence.proto
│ │ ├── validator.proto
│ │ ├── params.proto
│ │ └── types.proto
│ ├── version
│ │ └── types.proto
│ └── abci
│ │ └── types.proto
│ ├── cosmos_proto
│ └── cosmos.proto
│ ├── google
│ ├── api
│ │ ├── annotations.proto
│ │ ├── httpbody.proto
│ │ └── http.proto
│ └── protobuf
│ │ └── any.proto
│ ├── gogoproto
│ └── gogo.proto
│ └── confio
│ └── proofs.proto
├── proto
├── buf.gen.gogo.yaml
└── cosmos
│ └── base
│ └── query
│ └── v1beta1
│ └── pagination.proto
├── cmd
└── metro
│ ├── main.go
│ └── cmd
│ └── root.go
├── scripts
├── test_cover.sh
├── protocgen.sh
├── localnet-blocks-test.sh
└── single-node.sh
├── .github
├── dependabot.yml
├── CODEOWNERS
├── workflows
│ ├── lint.yml
│ ├── proto.yml
│ ├── ci_release.yml
│ └── test.yml
└── ISSUE_TEMPLATE
│ ├── bug-report.yml
│ └── feature-request.yml
├── app
├── genesis.go
├── encoding
│ └── encoding.go
├── antedecorators.go
├── module.go
└── export.go
├── buf.yaml
├── testutil
├── testfactory
│ ├── txs.go
│ └── utils.go
├── testnode
│ ├── node_interaction_api.go
│ ├── full_node_test.go
│ ├── rpc_client.go
│ ├── node_init.go
│ └── full_node.go
└── test_app.go
├── docs
└── architecture
│ └── adr-template.md
├── Makefile
├── go.mod
└── LICENSE
/mlc_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "retryOn429": true
3 | }
4 |
--------------------------------------------------------------------------------
/pkg/consts/protocol_consts.go:
--------------------------------------------------------------------------------
1 | package consts
2 |
3 | const (
4 | ChainIDSeparator = "|"
5 | )
6 |
--------------------------------------------------------------------------------
/docker/priv_validator_state.json:
--------------------------------------------------------------------------------
1 | {
2 | "height": "0",
3 | "round": 0,
4 | "step": 0
5 | }
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # metro
2 |
3 | shared aggregator chain that accepts transactions from many different "lazy" chains and post them on Celestia
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | frontend/node_modules
2 | frontend/dist
3 | frontend/.cache
4 | secret.yml
5 | build
6 | coverage.txt
7 | .idea
8 | .vscode
9 | tools-stamp
10 | __debug_bin
11 | profile.out
12 |
--------------------------------------------------------------------------------
/.golangci.yml:
--------------------------------------------------------------------------------
1 | run:
2 | timeout: 5m
3 | modules-download-mode: readonly
4 |
5 | linters:
6 | enable:
7 | - exportloopref
8 | - gofumpt
9 | - misspell
10 | - revive
11 | - prealloc
12 |
--------------------------------------------------------------------------------
/.markdownlint.yaml:
--------------------------------------------------------------------------------
1 | "default": true # Default state for all rules
2 | "MD010":
3 | "code_blocks": false # Disable rule for hard tabs in code blocks
4 | "MD013": false # Disable rule for line length
5 | "MD033": false # Disable rule banning inline HTML
6 |
--------------------------------------------------------------------------------
/third_party/proto/tendermint/libs/bits/types.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package tendermint.libs.bits;
3 |
4 | option go_package = "github.com/tendermint/tendermint/proto/tendermint/libs/bits";
5 |
6 | message BitArray {
7 | int64 bits = 1;
8 | repeated uint64 elems = 2;
9 | }
10 |
--------------------------------------------------------------------------------
/proto/buf.gen.gogo.yaml:
--------------------------------------------------------------------------------
1 | version: v1
2 | plugins:
3 | - name: gocosmos
4 | out: ..
5 | opt: plugins=interfacetype+grpc,Mgoogle/protobuf/any.proto=github.com/histolabs/metro/codec/types # yamllint disable-line rule:line-length
6 | - name: grpc-gateway
7 | out: ..
8 | opt: logtostderr=true,allow_colon_final_segments=true
9 |
--------------------------------------------------------------------------------
/cmd/metro/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "os"
5 |
6 | "github.com/histolabs/metro/app"
7 | "github.com/histolabs/metro/cmd/metro/cmd"
8 |
9 | svrcmd "github.com/cosmos/cosmos-sdk/server/cmd"
10 | )
11 |
12 | func main() {
13 | rootCmd := cmd.NewRootCmd()
14 | if err := svrcmd.Execute(rootCmd, cmd.EnvPrefix, app.DefaultNodeHome); err != nil {
15 | os.Exit(1)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/scripts/test_cover.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | PKGS=$(go list ./... | grep -v '/simapp')
5 |
6 | set -e
7 | echo "mode: atomic" > coverage.txt
8 | for pkg in ${PKGS[@]}; do
9 | go test -v -timeout 30m -race -test.short -coverprofile=profile.out -covermode=atomic "$pkg"
10 | if [ -f profile.out ]; then
11 | tail -n +2 profile.out >> coverage.txt;
12 | rm profile.out
13 | fi
14 | done
15 |
--------------------------------------------------------------------------------
/third_party/proto/cosmos_proto/cosmos.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package cosmos_proto;
3 |
4 | import "google/protobuf/descriptor.proto";
5 |
6 | option go_package = "github.com/regen-network/cosmos-proto";
7 |
8 | extend google.protobuf.MessageOptions {
9 | string interface_type = 93001;
10 |
11 | string implements_interface = 93002;
12 | }
13 |
14 | extend google.protobuf.FieldOptions {
15 | string accepts_interface = 93001;
16 | }
17 |
--------------------------------------------------------------------------------
/third_party/proto/tendermint/crypto/keys.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package tendermint.crypto;
3 |
4 | option go_package = "github.com/tendermint/tendermint/proto/tendermint/crypto";
5 |
6 | import "gogoproto/gogo.proto";
7 |
8 | // PublicKey defines the keys available for use with Tendermint Validators
9 | message PublicKey {
10 | option (gogoproto.compare) = true;
11 | option (gogoproto.equal) = true;
12 |
13 | oneof sum {
14 | bytes ed25519 = 1;
15 | bytes secp256k1 = 2;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/third_party/proto/tendermint/types/evidence.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package tendermint.types;
3 |
4 | option go_package = "github.com/tendermint/tendermint/proto/tendermint/types";
5 |
6 | import "gogoproto/gogo.proto";
7 | import "tendermint/types/types.proto";
8 |
9 |
10 | // EvidenceData contains any evidence of malicious wrong-doing by validators
11 | message EvidenceData {
12 | repeated tendermint.types.Evidence evidence = 1 [(gogoproto.nullable) = false];
13 | bytes hash = 2;
14 | }
15 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: docker
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | open-pull-requests-limit: 10
8 | - package-ecosystem: github-actions
9 | directory: "/"
10 | schedule:
11 | interval: daily
12 | open-pull-requests-limit: 10
13 | - package-ecosystem: gomod
14 | directory: "/"
15 | schedule:
16 | interval: daily
17 | open-pull-requests-limit: 10
18 | labels:
19 | - automerge
20 | - dependencies
21 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # CODEOWNERS:
2 |
3 | # Everything goes through the following "global owners" by default. Unless a later
4 | # match takes precedence, the "global owners" will be requested for review when
5 | # someone opens a PR. Note that the last matching pattern takes precedence, so
6 | # global owners are only requested if there isn't a more specific codeowner
7 | # specified below. For this reason, the global owners are often repeated in
8 | # directory-level definitions.
9 |
10 | # global owners
11 | * @evan-forbes
12 |
--------------------------------------------------------------------------------
/app/genesis.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "encoding/json"
5 | )
6 |
7 | // The genesis state of the blockchain is represented here as a map of raw json
8 | // messages key'd by a identifier string.
9 | // The identifier is used to determine which module genesis information belongs
10 | // to so it may be appropriately routed during init chain.
11 | // Within this application default genesis information is retrieved from
12 | // the ModuleBasicManager which populates json from each BasicModule
13 | // object provided to it during init.
14 | type GenesisState map[string]json.RawMessage
15 |
--------------------------------------------------------------------------------
/docker/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # This script creates the necessary files before starting Celestia-appd
4 |
5 | # only create the priv_validator_state.json if it doesn't exist and the command is start
6 | if [[ $1 == "start" && ! -f ${METRO_HOME}/data/priv_validator_state.json ]]
7 | then
8 | mkdir ${METRO_HOME}/data # it is alright if it fails, the script will continue executing
9 | cat < ${METRO_HOME}/data/priv_validator_state.json
10 | {
11 | "height": "0",
12 | "round": 0,
13 | "step": 0
14 | }
15 | EOF
16 | fi
17 |
18 | /bin/metro --home ${METRO_HOME} $@
19 |
--------------------------------------------------------------------------------
/pkg/consts/app_consts.go:
--------------------------------------------------------------------------------
1 | package consts
2 |
3 | import (
4 | sdkmath "cosmossdk.io/math"
5 | sdk "github.com/cosmos/cosmos-sdk/types"
6 | )
7 |
8 | const (
9 | AccountAddressPrefix = "metro"
10 | Name = "metro"
11 | // BondDenom defines the native staking token denomination.
12 | BondDenom = "utick"
13 | // BondDenomAlias defines an alias for BondDenom.
14 | BondDenomAlias = "microtick"
15 | // DisplayDenom defines the name, symbol, and display value of the Celestia token.
16 | DisplayDenom = "TICK"
17 | )
18 |
19 | func NativeDenom(amount sdkmath.Int) sdk.Coin {
20 | return sdk.NewCoin(BondDenom, amount)
21 | }
22 |
--------------------------------------------------------------------------------
/buf.yaml:
--------------------------------------------------------------------------------
1 | version: v1beta1
2 |
3 | build:
4 | roots:
5 | - proto
6 | - third_party/proto
7 | excludes:
8 | - third_party/proto/google/protobuf
9 | lint:
10 | use:
11 | - DEFAULT
12 | - COMMENTS
13 | - FILE_LOWER_SNAKE_CASE
14 | except:
15 | - UNARY_RPC
16 | - COMMENT_FIELD
17 | - SERVICE_SUFFIX
18 | - PACKAGE_VERSION_SUFFIX
19 | - RPC_REQUEST_STANDARD_NAME
20 | ignore:
21 | - tendermint
22 | - gogoproto
23 | - cosmos_proto
24 | - google
25 | - confio
26 | breaking:
27 | use:
28 | - FILE
29 | ignore:
30 | - tendermint
31 | - gogoproto
32 | - cosmos_proto
33 | - google
34 | - confio
35 |
--------------------------------------------------------------------------------
/testutil/testfactory/txs.go:
--------------------------------------------------------------------------------
1 | package testfactory
2 |
3 | import (
4 | mrand "math/rand"
5 |
6 | "github.com/tendermint/tendermint/types"
7 | )
8 |
9 | func GenerateRandomlySizedTxs(count, maxSize int) types.Txs {
10 | txs := make(types.Txs, count)
11 | for i := 0; i < count; i++ {
12 | size := mrand.Intn(maxSize)
13 | if size == 0 {
14 | size = 1
15 | }
16 | txs[i] = GenerateRandomTxs(1, size)[0]
17 | }
18 | return txs
19 | }
20 |
21 | func GenerateRandomTxs(count, size int) types.Txs {
22 | txs := make(types.Txs, count)
23 | for i := 0; i < count; i++ {
24 | tx := make([]byte, size)
25 | _, err := mrand.Read(tx)
26 | if err != nil {
27 | panic(err)
28 | }
29 | txs[i] = tx
30 | }
31 | return txs
32 | }
33 |
--------------------------------------------------------------------------------
/third_party/proto/tendermint/version/types.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package tendermint.version;
3 |
4 | option go_package = "github.com/tendermint/tendermint/proto/tendermint/version";
5 |
6 | import "gogoproto/gogo.proto";
7 |
8 | // App includes the protocol and software version for the application.
9 | // This information is included in ResponseInfo. The App.Protocol can be
10 | // updated in ResponseEndBlock.
11 | message App {
12 | uint64 protocol = 1;
13 | string software = 2;
14 | }
15 |
16 | // Consensus captures the consensus rules for processing a block in the blockchain,
17 | // including all blockchain data structures and the rules of the application's
18 | // state transition machine.
19 | message Consensus {
20 | option (gogoproto.equal) = true;
21 |
22 | uint64 block = 1;
23 | uint64 app = 2;
24 | }
25 |
--------------------------------------------------------------------------------
/scripts/protocgen.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -eo pipefail
4 |
5 | protoc_gen_gocosmos() {
6 | if ! grep "github.com/gogo/protobuf => github.com/regen-network/protobuf" go.mod &>/dev/null ; then
7 | echo -e "\tPlease run this command from somewhere inside the cosmos-sdk folder."
8 | return 1
9 | fi
10 | }
11 |
12 | protoc_gen_gocosmos
13 |
14 | cd proto
15 | proto_dirs=$(find . -path ./cosmos -prune -o -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq)
16 | for dir in $proto_dirs; do
17 | for file in $(find "${dir}" -maxdepth 1 -name '*.proto'); do
18 | if grep "option go_package" $file &> /dev/null ; then
19 | buf generate --template buf.gen.gogo.yaml $file
20 | fi
21 | done
22 | done
23 |
24 | cd ..
25 |
26 | # move proto files to the right places
27 | cp -r github.com/histolabs/metro/* ./
28 | rm -rf github.com
29 |
--------------------------------------------------------------------------------
/third_party/proto/tendermint/types/validator.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package tendermint.types;
3 |
4 | option go_package = "github.com/tendermint/tendermint/proto/tendermint/types";
5 |
6 | import "gogoproto/gogo.proto";
7 | import "tendermint/crypto/keys.proto";
8 |
9 | message ValidatorSet {
10 | repeated Validator validators = 1;
11 | Validator proposer = 2;
12 | int64 total_voting_power = 3;
13 | }
14 |
15 | message Validator {
16 | bytes address = 1;
17 | tendermint.crypto.PublicKey pub_key = 2 [(gogoproto.nullable) = false];
18 | int64 voting_power = 3;
19 | int64 proposer_priority = 4;
20 | }
21 |
22 | message SimpleValidator {
23 | tendermint.crypto.PublicKey pub_key = 1;
24 | int64 voting_power = 2;
25 | }
26 |
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | name: Lint
2 | # Lint runs golangci-lint over the entire cosmos-sdk repository
3 | # This workflow is run on every pull request and push to main
4 | # The `golangci` will pass without running if no *.{go, mod, sum} files have
5 | # been changed.
6 | on:
7 | workflow_call:
8 |
9 | jobs:
10 | golangci:
11 | name: golangci-lint
12 | runs-on: ubuntu-latest
13 | timeout-minutes: 8
14 | steps:
15 | - uses: actions/setup-go@v3
16 | with:
17 | go-version: 1.19
18 | - uses: actions/checkout@v3
19 | - uses: technote-space/get-diff-action@v6.1.2
20 | with:
21 | PATTERNS: |
22 | **/**.go
23 | go.mod
24 | go.sum
25 | - uses: golangci/golangci-lint-action@v3.3.1
26 | with:
27 | version: v1.47.2
28 | args: --timeout 10m
29 | github-token: ${{ secrets.github_token }}
30 | if: env.GIT_DIFF
31 |
--------------------------------------------------------------------------------
/docker/Dockerfile_ephemeral:
--------------------------------------------------------------------------------
1 | # stage 1 Generate metro Binary
2 | FROM golang:1.19-alpine as builder
3 |
4 | RUN apk update && \
5 | apk upgrade && \
6 | apk --no-cache add make gcc musl-dev
7 |
8 | ENV HOME /metro
9 |
10 | COPY / ${HOME}
11 | WORKDIR ${HOME}
12 |
13 | RUN make build
14 |
15 | # stage 2
16 | FROM alpine
17 |
18 | RUN apk update && \
19 | apk upgrade && \
20 | apk --no-cache add curl jq bash
21 |
22 | ENV HOME /metro
23 | COPY --from=builder ${HOME}/build/metro ${HOME}/metro
24 | COPY docker/priv_validator_state.json ${HOME}/data/priv_validator_state.json
25 | WORKDIR $HOME
26 |
27 | # p2p, rpc and prometheus port
28 | EXPOSE 26656 26657 1317 9090
29 |
30 | # This allows us to always set the --home directory using an env
31 | # var while still capturing all arguments passed at runtime
32 | ENTRYPOINT [ "/bin/bash", "-c", "exec ./metro \
33 | --home ${HOME} \
34 | \"${@}\"", "--" ]
35 | # Default command to run if no arguments are passed
36 | CMD ["--help"]
37 |
--------------------------------------------------------------------------------
/third_party/proto/tendermint/crypto/proof.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package tendermint.crypto;
3 |
4 | option go_package = "github.com/tendermint/tendermint/proto/tendermint/crypto";
5 |
6 | import "gogoproto/gogo.proto";
7 |
8 | message Proof {
9 | int64 total = 1;
10 | int64 index = 2;
11 | bytes leaf_hash = 3;
12 | repeated bytes aunts = 4;
13 | }
14 |
15 | message ValueOp {
16 | // Encoded in ProofOp.Key.
17 | bytes key = 1;
18 |
19 | // To encode in ProofOp.Data
20 | Proof proof = 2;
21 | }
22 |
23 | message DominoOp {
24 | string key = 1;
25 | string input = 2;
26 | string output = 3;
27 | }
28 |
29 | // ProofOp defines an operation used for calculating Merkle root
30 | // The data could be arbitrary format, providing necessary data
31 | // for example neighbouring node hash
32 | message ProofOp {
33 | string type = 1;
34 | bytes key = 2;
35 | bytes data = 3;
36 | }
37 |
38 | // ProofOps is Merkle proof defined by the list of ProofOps
39 | message ProofOps {
40 | repeated ProofOp ops = 1 [(gogoproto.nullable) = false];
41 | }
42 |
--------------------------------------------------------------------------------
/third_party/proto/google/api/annotations.proto:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2015, Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | syntax = "proto3";
16 |
17 | package google.api;
18 |
19 | import "google/api/http.proto";
20 | import "google/protobuf/descriptor.proto";
21 |
22 | option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
23 | option java_multiple_files = true;
24 | option java_outer_classname = "AnnotationsProto";
25 | option java_package = "com.google.api";
26 | option objc_class_prefix = "GAPI";
27 |
28 | extend google.protobuf.MethodOptions {
29 | // See `HttpRule`.
30 | HttpRule http = 72295728;
31 | }
32 |
--------------------------------------------------------------------------------
/docker/Dockerfile.test:
--------------------------------------------------------------------------------
1 | # Simple usage with a mounted data directory:
2 | # > docker build -t metro .
3 | # > docker run -it -p 46657:46657 -p 46656:46656 -v ~/.metro:/root/.metro -v ~/.metrocli:/root/.metrocli metro metro init
4 | # > docker run -it -p 46657:46657 -p 46656:46656 -v ~/.metro:/root/.metro -v ~/.metrocli:/root/.metrocli metro metro start
5 | FROM golang:1.19-alpine AS build-env
6 |
7 | # Set up dependencies
8 | ENV PACKAGES curl make git libc-dev bash gcc linux-headers eudev-dev python3
9 |
10 | # Set working directory for the build
11 | WORKDIR /go/src/github.com/histolabs/metro
12 |
13 | # Add source files
14 | COPY . .
15 |
16 | # Install minimum necessary dependencies, build Cosmos SDK, remove packages
17 | RUN apk add --no-cache $PACKAGES && \
18 | make install
19 |
20 | # Final image
21 | FROM alpine:edge
22 |
23 | # Install ca-certificates
24 | RUN apk add --update ca-certificates
25 | WORKDIR /root
26 |
27 | # Copy over binaries from the build-env
28 | COPY --from=build-env /go/bin/metro /usr/bin/metro
29 |
30 | COPY ./scripts/single-node.sh .
31 |
32 | EXPOSE 26657
33 |
34 | ENTRYPOINT [ "./single-node.sh" ]
35 | # NOTE: to run this image, docker run -d -p 26657:26657 ./single-node.sh {{chain_id}} {{genesis_account}}
36 |
--------------------------------------------------------------------------------
/.github/workflows/proto.yml:
--------------------------------------------------------------------------------
1 | name: Protobuf
2 | # Protobuf runs buf (https://buf.build/) lint and generate
3 | # This workflow is only run when a .proto file has been changed
4 | on:
5 | pull_request:
6 | paths:
7 | - "**.proto"
8 | jobs:
9 | lint:
10 | runs-on: ubuntu-latest
11 | timeout-minutes: 5
12 | steps:
13 | - uses: actions/checkout@v3
14 | - name: lint
15 | run: make proto-lint
16 | proto-gen:
17 | runs-on: ubuntu-latest
18 | timeout-minutes: 5
19 | steps:
20 | - uses: actions/checkout@v3
21 | - name: "Check protobuf generated code matches committed code"
22 | # yamllint disable
23 | run: |
24 | set -euo pipefail
25 |
26 | make proto-gen
27 |
28 | if ! git diff --stat --exit-code ; then
29 | echo ">> ERROR:"
30 | echo ">>"
31 | echo ">> Protobuf generated code requires update (either tools or .proto files may have changed)."
32 | echo ">> Ensure your tools are up-to-date, re-run 'make proto-gen' and update this PR."
33 | echo ">>"
34 | exit 1
35 | fi
36 | # yamllint enable
37 |
38 | # add this back when we start using versioning
39 | # breakage:
40 | # runs-on: ubuntu-latest
41 | # steps:
42 | # - uses: actions/checkout@v3
43 | # - name: check-breakage
44 | # run: make proto-check-breaking
45 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: Create a report to help us squash bugs!
3 | title: ""
4 | labels: ["bug"]
5 |
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | IMPORTANT: Prior to opening a bug report, check if it affects one of the
11 | core modules and if it's eligible for a bug bounty on `SECURITY.md`.
12 | Bugs that are not submitted through the appropriate channels won't
13 | receive any bounty.
14 |
15 | - type: textarea
16 | id: summary
17 | attributes:
18 | label: Summary of Bug
19 | description: Concisely describe the issue.
20 | validations:
21 | required: true
22 |
23 | - type: textarea
24 | id: version
25 | attributes:
26 | label: Version
27 | description: git commit hash or release version
28 | validations:
29 | required: true
30 |
31 | - type: textarea
32 | id: repro
33 | attributes:
34 | label: Steps to Reproduce
35 | description: >
36 | What commands in order should someone run to reproduce your problem?
37 | validations:
38 | required: true
39 |
40 | - type: checkboxes
41 | id: admin
42 | attributes:
43 | label: For Admin Use
44 | description: (do not edit)
45 | options:
46 | - label: Not duplicate issue
47 | - label: Appropriate labels applied
48 | - label: Appropriate contributors tagged
49 | - label: Contributor assigned/self-assigned
50 |
--------------------------------------------------------------------------------
/scripts/localnet-blocks-test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | CNT=0
4 | ITER=$1
5 | SLEEP=$2
6 | NUMBLOCKS=$3
7 | NODEADDR=$4
8 |
9 | if [ -z "$1" ]; then
10 | echo "Need to input number of iterations to run..."
11 | exit 1
12 | fi
13 |
14 | if [ -z "$2" ]; then
15 | echo "Need to input number of seconds to sleep between iterations"
16 | exit 1
17 | fi
18 |
19 | if [ -z "$3" ]; then
20 | echo "Need to input block height to declare completion..."
21 | exit 1
22 | fi
23 |
24 | if [ -z "$4" ]; then
25 | echo "Need to input node address to poll..."
26 | exit 1
27 | fi
28 |
29 | docker_containers=( $(docker ps -q -f name=metro --format='{{.Names}}') )
30 |
31 | while [ ${CNT} -lt $ITER ]; do
32 | curr_block=$(curl -s $NODEADDR:26657/status | jq -r '.result.sync_info.latest_block_height')
33 |
34 | if [ ! -z ${curr_block} ] ; then
35 | echo "Number of Blocks: ${curr_block}"
36 | fi
37 |
38 | if [ ! -z ${curr_block} ] && [ ${curr_block} -gt ${NUMBLOCKS} ]; then
39 | echo "Number of blocks reached. Success!"
40 | exit 0
41 | fi
42 |
43 | # Emulate network chaos:
44 | #
45 | # Every 10 blocks, pick a random container and restart it.
46 | if ! ((${CNT} % 10)); then
47 | rand_container=${docker_containers["$[RANDOM % ${#docker_containers[@]}]"]};
48 | echo "Restarting random docker container ${rand_container}"
49 | docker restart ${rand_container} &>/dev/null &
50 | fi
51 |
52 | let CNT=CNT+1
53 | sleep $SLEEP
54 | done
55 |
56 | echo "Timeout reached. Failure!"
57 | exit 1
58 |
--------------------------------------------------------------------------------
/scripts/single-node.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -o errexit -o nounset
4 |
5 | CHAINID="private"
6 |
7 | # Build genesis file incl account for passed address
8 | coins="1000000000000000utick"
9 | metro init $CHAINID --chain-id $CHAINID
10 | metro keys add validator --keyring-backend="test"
11 | # this won't work because the some proto types are decalared twice and the logs output to stdout (dependency hell involving iavl)
12 | metro add-genesis-account $(metro keys show validator -a --keyring-backend="test") $coins
13 | metro gentx validator 5000000000utick \
14 | --keyring-backend="test" \
15 | --chain-id $CHAINID \
16 | --orchestrator-address $(metro keys show validator -a --keyring-backend="test") \
17 | --evm-address 0x966e6f22781EF6a6A82BBB4DB3df8E225DfD9488 # private key: da6ed55cb2894ac2c9c10209c09de8e8b9d109b910338d5bf3d747a7e1fc9eb9
18 |
19 | metro collect-gentxs
20 |
21 | # Set proper defaults and change ports
22 | # If you encounter: `sed: -I or -i may not be used with stdin` on MacOS you can mitigate by installing gnu-sed
23 | # https://gist.github.com/andre3k1/e3a1a7133fded5de5a9ee99c87c6fa0d?permalink_comment_id=3082272#gistcomment-3082272
24 | sed -i'.bak' 's#"tcp://127.0.0.1:26657"#"tcp://0.0.0.0:26657"#g' ~/.metro/config/config.toml
25 | sed -i'.bak' 's/timeout_commit = "1s"/timeout_commit = "1s"/g' ~/.metro/config/config.toml
26 | sed -i'.bak' 's/timeout_propose = "1s"/timeout_propose = "1s"/g' ~/.metro/config/config.toml
27 | sed -i'.bak' 's/index_all_keys = false/index_all_keys = true/g' ~/.metro/config/config.toml
28 | sed -i'.bak' 's/mode = "full"/mode = "validator"/g' ~/.metro/config/config.toml
29 |
30 | # Start the app
31 | metro start
32 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.yml:
--------------------------------------------------------------------------------
1 | name: Feature Request
2 | description: Create a proposal to request a feature
3 | title: ""
4 | labels: ["enhancement"]
5 |
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | ✰ Thanks for opening an issue! ✰
11 | Before smashing the submit button please fill in the template.
12 | Word of caution: poorly thought-out proposals may be rejected without
13 | deliberation.
14 |
15 | - type: textarea
16 | id: summary
17 | attributes:
18 | label: Summary
19 | description: Short, concise description of the proposed feature.
20 | validations:
21 | required: true
22 |
23 | - type: textarea
24 | id: problem
25 | attributes:
26 | label: Problem Definition
27 | description: |
28 | Why do we need this feature?
29 | What problems may be addressed by introducing this feature?
30 | What benefits does the SDK stand to gain by including this feature?
31 | Are there any disadvantages of including this feature?
32 | validations:
33 | required: true
34 |
35 | - type: textarea
36 | id: proposal
37 | attributes:
38 | label: Proposal
39 | description: Detailed description of requirements of implementation.
40 | validations:
41 | required: true
42 |
43 | - type: checkboxes
44 | id: admin
45 | attributes:
46 | label: For Admin Use
47 | description: (do not edit)
48 | options:
49 | - label: Not duplicate issue
50 | - label: Appropriate labels applied
51 | - label: Appropriate contributors tagged
52 | - label: Contributor assigned/self-assigned
53 |
--------------------------------------------------------------------------------
/app/encoding/encoding.go:
--------------------------------------------------------------------------------
1 | package encoding
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/client"
5 | "github.com/cosmos/cosmos-sdk/codec"
6 | codectypes "github.com/cosmos/cosmos-sdk/codec/types"
7 | "github.com/cosmos/cosmos-sdk/std"
8 | "github.com/cosmos/cosmos-sdk/x/auth/tx"
9 | )
10 |
11 | type ModuleRegister interface {
12 | RegisterLegacyAminoCodec(*codec.LegacyAmino)
13 | RegisterInterfaces(codectypes.InterfaceRegistry)
14 | }
15 |
16 | // Config specifies the concrete encoding types to use for a given app.
17 | // This is provided for compatibility between protobuf and amino implementations.
18 | type Config struct {
19 | InterfaceRegistry codectypes.InterfaceRegistry
20 | Codec codec.Codec
21 | TxConfig client.TxConfig
22 | Amino *codec.LegacyAmino
23 | }
24 |
25 | // MakeConfig creates an encoding config for the app.
26 | func MakeConfig(regs ...ModuleRegister) Config {
27 | // create the codec
28 | amino := codec.NewLegacyAmino()
29 | interfaceRegistry := codectypes.NewInterfaceRegistry()
30 |
31 | // register the standard types from the sdk
32 | std.RegisterLegacyAminoCodec(amino)
33 | std.RegisterInterfaces(interfaceRegistry)
34 |
35 | // register specific modules
36 | for _, reg := range regs {
37 | reg.RegisterInterfaces(interfaceRegistry)
38 | reg.RegisterLegacyAminoCodec(amino)
39 | }
40 |
41 | // create the final configuration
42 | marshaler := codec.NewProtoCodec(interfaceRegistry)
43 | txCfg := tx.NewTxConfig(marshaler, tx.DefaultSignModes)
44 |
45 | return Config{
46 | InterfaceRegistry: interfaceRegistry,
47 | Codec: marshaler,
48 | TxConfig: txCfg,
49 | Amino: amino,
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/proto/cosmos/base/query/v1beta1/pagination.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package cosmos.base.query.v1beta1;
3 |
4 | option go_package = "github.com/cosmos/cosmos-sdk/types/query";
5 |
6 | // PageRequest is to be embedded in gRPC request messages for efficient
7 | // pagination. Ex:
8 | //
9 | // message SomeRequest {
10 | // Foo some_parameter = 1;
11 | // PageRequest pagination = 2;
12 | // }
13 | message PageRequest {
14 | // key is a value returned in PageResponse.next_key to begin
15 | // querying the next page most efficiently. Only one of offset or key
16 | // should be set.
17 | bytes key = 1;
18 |
19 | // offset is a numeric offset that can be used when key is unavailable.
20 | // It is less efficient than using key. Only one of offset or key should
21 | // be set.
22 | uint64 offset = 2;
23 |
24 | // limit is the total number of results to be returned in the result page.
25 | // If left empty it will default to a value to be set by each app.
26 | uint64 limit = 3;
27 |
28 | // count_total is set to true to indicate that the result set should include
29 | // a count of the total number of items available for pagination in UIs.
30 | // count_total is only respected when offset is used. It is ignored when key
31 | // is set.
32 | bool count_total = 4;
33 | }
34 |
35 | // PageResponse is to be embedded in gRPC response messages where the
36 | // corresponding request message has used PageRequest.
37 | //
38 | // message SomeResponse {
39 | // repeated Bar results = 1;
40 | // PageResponse page = 2;
41 | // }
42 | message PageResponse {
43 | // next_key is the key to be passed to PageRequest.key to
44 | // query the next page most efficiently
45 | bytes next_key = 1;
46 |
47 | // total is total number of results available if PageRequest.count_total
48 | // was set, its value is undefined otherwise
49 | uint64 total = 2;
50 | }
51 |
--------------------------------------------------------------------------------
/app/antedecorators.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
6 | "github.com/cosmos/cosmos-sdk/x/auth/ante"
7 | )
8 |
9 | // NewAnteDecorators returns an AnteDecorators that check and increment
10 | // sequence numbers, checks signatures & account numbers, and deducts fees from
11 | // the first signer.
12 | func NewAnteDecorators(options ante.HandlerOptions) ([]sdk.AnteDecorator, error) {
13 | if options.AccountKeeper == nil {
14 | return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "account keeper is required for ante builder")
15 | }
16 |
17 | if options.BankKeeper == nil {
18 | return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "bank keeper is required for ante builder")
19 | }
20 |
21 | if options.SignModeHandler == nil {
22 | return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder")
23 | }
24 |
25 | anteDecorators := []sdk.AnteDecorator{
26 | ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
27 | ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker),
28 | ante.NewValidateBasicDecorator(),
29 | ante.NewTxTimeoutHeightDecorator(),
30 | ante.NewValidateMemoDecorator(options.AccountKeeper),
31 | ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
32 | ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker),
33 | ante.NewSetPubKeyDecorator(options.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators
34 | ante.NewValidateSigCountDecorator(options.AccountKeeper),
35 | ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer),
36 | ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
37 | ante.NewIncrementSequenceDecorator(options.AccountKeeper),
38 | }
39 |
40 | return anteDecorators, nil
41 | }
42 |
--------------------------------------------------------------------------------
/.github/workflows/ci_release.yml:
--------------------------------------------------------------------------------
1 | name: CI and Release
2 |
3 | # Trigger on push events to main (i.e. merges), pushing new semantic version
4 | # tags, all PRs, and manual triggers
5 | on:
6 | push:
7 | branches:
8 | - main
9 | tags:
10 | - "v[0-9]+.[0-9]+.[0-9]+"
11 | - "v[0-9]+.[0-9]+.[0-9]+-alpha.[0-9]+"
12 | - "v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+"
13 | - "v[0-9]+.[0-9]+.[0-9]+-rc[0-9]+"
14 | pull_request:
15 | workflow_dispatch:
16 | # Inputs the workflow accepts.
17 | inputs:
18 | version:
19 | # Friendly description to be shown in the UI instead of 'name'
20 | description: "Semver type of new version (major / minor / patch)"
21 | # Input has to be provided for the workflow to run
22 | required: true
23 | type: choice
24 | options:
25 | - patch
26 | - minor
27 | - major
28 |
29 | jobs:
30 | # Dockerfile Linting
31 | hadolint:
32 | uses: histolabs/.github/.github/workflows/reusable_dockerfile_lint.yml@main # yamllint disable-line rule:line-length
33 |
34 | yamllint:
35 | runs-on: ubuntu-latest
36 | steps:
37 | - uses: actions/checkout@v3
38 | - uses: histolabs/.github/.github/actions/yamllint@main
39 |
40 | markdown-lint:
41 | runs-on: ubuntu-latest
42 | steps:
43 | - uses: actions/checkout@v3
44 | - uses: histolabs/.github/.github/actions/markdown-lint@main
45 |
46 | lint:
47 | uses: ./.github/workflows/lint.yml
48 |
49 | test:
50 | needs: lint
51 | uses: ./.github/workflows/test.yml
52 |
53 | # Make a release if this is a manually trigger job, i.e. workflow_dispatch
54 | release:
55 | needs: [hadolint, yamllint, markdown-lint, lint, test]
56 | runs-on: ubuntu-latest
57 | if: ${{ github.event_name == 'workflow_dispatch' }}
58 | permissions: "write-all"
59 | steps:
60 | - uses: actions/checkout@v3
61 | - name: Version Release
62 | uses: histolabs/.github/.github/actions/version-release@main
63 | with:
64 | github-token: ${{secrets.GITHUB_TOKEN}}
65 | version-bump: ${{inputs.version}}
66 |
67 |
--------------------------------------------------------------------------------
/testutil/testnode/node_interaction_api.go:
--------------------------------------------------------------------------------
1 | package testnode
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "time"
7 |
8 | "github.com/cosmos/cosmos-sdk/client"
9 | )
10 |
11 | type Context struct {
12 | rootCtx context.Context
13 | client.Context
14 | }
15 |
16 | func (c *Context) GoContext() context.Context {
17 | return c.rootCtx
18 | }
19 |
20 | // LatestHeight returns the latest height of the network or an error if the
21 | // query fails.
22 | func (c *Context) LatestHeight() (int64, error) {
23 | status, err := c.Client.Status(c.GoContext())
24 | if err != nil {
25 | return 0, err
26 | }
27 |
28 | return status.SyncInfo.LatestBlockHeight, nil
29 | }
30 |
31 | // WaitForHeightWithTimeout is the same as WaitForHeight except the caller can
32 | // provide a custom timeout.
33 | func (c *Context) WaitForHeightWithTimeout(h int64, t time.Duration) (int64, error) {
34 | ticker := time.NewTicker(time.Second)
35 | defer ticker.Stop()
36 |
37 | ctx, cancel := context.WithTimeout(c.rootCtx, t)
38 | defer cancel()
39 |
40 | var latestHeight int64
41 | for {
42 | select {
43 | case <-ctx.Done():
44 | return latestHeight, errors.New("timeout exceeded waiting for block")
45 | case <-ticker.C:
46 | latestHeight, err := c.LatestHeight()
47 | if err != nil {
48 | return 0, err
49 | }
50 | if latestHeight >= h {
51 | return latestHeight, nil
52 | }
53 | }
54 | }
55 | }
56 |
57 | // WaitForHeight performs a blocking check where it waits for a block to be
58 | // committed after a given block. If that height is not reached within a timeout,
59 | // an error is returned. Regardless, the latest height queried is returned.
60 | func (c *Context) WaitForHeight(h int64) (int64, error) {
61 | return c.WaitForHeightWithTimeout(h, 10*time.Second)
62 | }
63 |
64 | // WaitForNextBlock waits for the next block to be committed, returning an error
65 | // upon failure.
66 | func (c *Context) WaitForNextBlock() error {
67 | lastBlock, err := c.LatestHeight()
68 | if err != nil {
69 | return err
70 | }
71 |
72 | _, err = c.WaitForHeight(lastBlock + 1)
73 | if err != nil {
74 | return err
75 | }
76 |
77 | return err
78 | }
79 |
--------------------------------------------------------------------------------
/testutil/testnode/full_node_test.go:
--------------------------------------------------------------------------------
1 | package testnode
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/require"
8 | "github.com/stretchr/testify/suite"
9 | tmrand "github.com/tendermint/tendermint/libs/rand"
10 | coretypes "github.com/tendermint/tendermint/rpc/core/types"
11 | )
12 |
13 | type IntegrationTestSuite struct {
14 | suite.Suite
15 |
16 | cleanups []func() error
17 | accounts []string
18 | cctx Context
19 | }
20 |
21 | func (s *IntegrationTestSuite) SetupSuite() {
22 | if testing.Short() {
23 | s.T().Skip("skipping test in unit-tests or race-detector mode.")
24 | }
25 |
26 | s.T().Log("setting up integration test suite")
27 | require := s.Require()
28 |
29 | // we create an arbitrary number of funded accounts
30 | for i := 0; i < 300; i++ {
31 | s.accounts = append(s.accounts, tmrand.Str(9))
32 | }
33 |
34 | genState, kr, err := DefaultGenesisState(s.accounts...)
35 | require.NoError(err)
36 |
37 | tmNode, app, cctx, err := New(s.T(), DefaultParams(), DefaultTendermintConfig(), false, genState, kr)
38 | require.NoError(err)
39 |
40 | cctx, stopNode, err := StartNode(tmNode, cctx)
41 | require.NoError(err)
42 | s.cleanups = append(s.cleanups, stopNode)
43 |
44 | cctx, cleanupGRPC, err := StartGRPCServer(app, DefaultAppConfig(), cctx)
45 | require.NoError(err)
46 | s.cleanups = append(s.cleanups, cleanupGRPC)
47 |
48 | s.cctx = cctx
49 | }
50 |
51 | func (s *IntegrationTestSuite) TearDownSuite() {
52 | s.T().Log("tearing down integration test suite")
53 | for _, c := range s.cleanups {
54 | err := c()
55 | require.NoError(s.T(), err)
56 | }
57 | }
58 |
59 | func (s *IntegrationTestSuite) Test_Liveness() {
60 | require := s.Require()
61 | err := s.cctx.WaitForNextBlock()
62 | require.NoError(err)
63 | // check that we're actually able to set the consensus params
64 | var params *coretypes.ResultConsensusParams
65 | // this query can be flaky with fast block times, so we repeat it multiple
66 | // times in attempt to increase the probability of it working
67 | for i := 0; i < 20; i++ {
68 | params, err = s.cctx.Client.ConsensusParams(context.TODO(), nil)
69 | if err != nil || params == nil {
70 | continue
71 | }
72 | break
73 | }
74 | require.NotNil(params)
75 | require.Equal(int64(1), params.ConsensusParams.Block.TimeIotaMs)
76 | _, err = s.cctx.WaitForHeight(40)
77 | require.NoError(err)
78 | }
79 |
80 | func TestIntegrationTestSuite(t *testing.T) {
81 | suite.Run(t, new(IntegrationTestSuite))
82 | }
83 |
--------------------------------------------------------------------------------
/testutil/testnode/rpc_client.go:
--------------------------------------------------------------------------------
1 | package testnode
2 |
3 | import (
4 | "context"
5 | "strings"
6 |
7 | srvconfig "github.com/cosmos/cosmos-sdk/server/config"
8 | srvgrpc "github.com/cosmos/cosmos-sdk/server/grpc"
9 | srvtypes "github.com/cosmos/cosmos-sdk/server/types"
10 | "github.com/tendermint/tendermint/node"
11 | "github.com/tendermint/tendermint/rpc/client/local"
12 | "google.golang.org/grpc"
13 | "google.golang.org/grpc/credentials/insecure"
14 | )
15 |
16 | // StartNode starts the tendermint node along with a local core rpc client. The
17 | // rpc is returned via the client.Context. The function returned should be
18 | // called during cleanup to teardown the node, core client, along with canceling
19 | // the internal context.Context in the returned Context.
20 | func StartNode(tmNode *node.Node, cctx Context) (Context, func() error, error) {
21 | if err := tmNode.Start(); err != nil {
22 | return cctx, func() error { return nil }, err
23 | }
24 |
25 | coreClient := local.New(tmNode)
26 |
27 | cctx.Context = cctx.WithClient(coreClient)
28 | goCtx, cancel := context.WithCancel(context.Background())
29 | cctx.rootCtx = goCtx
30 | cleanup := func() error {
31 | cancel()
32 | err := tmNode.Stop()
33 | if err != nil {
34 | return err
35 | }
36 | tmNode.Wait()
37 | return nil
38 | }
39 |
40 | return cctx, cleanup, nil
41 | }
42 |
43 | // StartGRPCServer starts the grpc server using the provided application and
44 | // config. A grpc client connection to that server is also added to the client
45 | // context. The returned function should be used to shutdown the server.
46 | func StartGRPCServer(app srvtypes.Application, appCfg *srvconfig.Config, cctx Context) (Context, func() error, error) {
47 | emptycleanup := func() error { return nil }
48 | // Add the tx service in the gRPC router.
49 | app.RegisterTxService(cctx.Context)
50 |
51 | // Add the tendermint queries service in the gRPC router.
52 | app.RegisterTendermintService(cctx.Context)
53 |
54 | grpcSrv, err := srvgrpc.StartGRPCServer(cctx.Context, app, appCfg.GRPC)
55 | if err != nil {
56 | return Context{}, emptycleanup, err
57 | }
58 |
59 | nodeGRPCAddr := strings.Replace(appCfg.GRPC.Address, "0.0.0.0", "localhost", 1)
60 | conn, err := grpc.Dial(nodeGRPCAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
61 | if err != nil {
62 | return Context{}, emptycleanup, err
63 | }
64 |
65 | cctx.Context = cctx.WithGRPCClient(conn)
66 |
67 | return cctx, func() error {
68 | grpcSrv.Stop()
69 | return nil
70 | }, nil
71 | }
72 |
73 | // DefaultAppConfig wraps the default config described in the server
74 | func DefaultAppConfig() *srvconfig.Config {
75 | return srvconfig.DefaultConfig()
76 | }
77 |
--------------------------------------------------------------------------------
/docs/architecture/adr-template.md:
--------------------------------------------------------------------------------
1 | # ADR {ADR-NUMBER}: {TITLE}
2 |
3 | ## Changelog
4 |
5 | - {date}: {changelog}
6 |
7 | ## Context
8 |
9 | > This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high-level idea behind the solution.
10 |
11 | ## Alternative Approaches
12 |
13 | > This section contains information about alternative options that are considered before making a decision. It should contain an explanation of why the alternative approach(es) were not chosen.
14 |
15 | ## Decision
16 |
17 | > This section records the decision that was made.
18 | > It is best to record as much info as possible from the discussion that happened. This aids in not having to go back to the Pull Request to get the needed information.
19 |
20 | ## Detailed Design
21 |
22 | > This section does not need to be filled in at the start of the ADR but must be completed prior to the merging of the implementation.
23 | >
24 | > Here are some common questions that get answered as part of the detailed design:
25 | >
26 | > - What are the user requirements?
27 | >
28 | > - What systems will be affected?
29 | >
30 | > - What new data structures are needed, and what data structures will be changed?
31 | >
32 | > - What new APIs will be needed, and what APIs will be changed?
33 | >
34 | > - What are the efficiency considerations (time/space)?
35 | >
36 | > - What are the expected access patterns (load/throughput)?
37 | >
38 | > - Are there any logging, monitoring, or observability needs?
39 | >
40 | > - Are there any security considerations?
41 | >
42 | > - Are there any privacy considerations?
43 | >
44 | > - How will the changes be tested?
45 | >
46 | > - If the change is large, how will the changes be broken up for ease of review?
47 | >
48 | > - Will these changes require a breaking (major) release?
49 | >
50 | > - Does this change require coordination with the SDK or others?
51 |
52 | ## Status
53 |
54 | > A decision may be "proposed" if it hasn't been agreed upon yet, or "accepted" once it is agreed upon. Once the ADR has been implemented mark the ADR as "implemented". If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement.
55 |
56 | {Deprecated|Proposed|Accepted|Declined}
57 |
58 | ## Consequences
59 |
60 | > This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones.
61 |
62 | ### Positive
63 |
64 | ### Negative
65 |
66 | ### Neutral
67 |
68 | ## References
69 |
70 | > Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here!
71 |
72 | - {reference link}
73 |
--------------------------------------------------------------------------------
/testutil/testfactory/utils.go:
--------------------------------------------------------------------------------
1 | package testfactory
2 |
3 | import (
4 | "context"
5 | "encoding/hex"
6 |
7 | "github.com/cosmos/cosmos-sdk/client"
8 | "github.com/cosmos/cosmos-sdk/codec"
9 | "github.com/cosmos/cosmos-sdk/crypto/hd"
10 | "github.com/cosmos/cosmos-sdk/crypto/keyring"
11 | "github.com/cosmos/cosmos-sdk/simapp"
12 | sdk "github.com/cosmos/cosmos-sdk/types"
13 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
14 | banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
15 | tmrand "github.com/tendermint/tendermint/libs/rand"
16 | rpctypes "github.com/tendermint/tendermint/rpc/core/types"
17 | )
18 |
19 | const (
20 | // nolint:lll
21 | TestAccName = "test-account"
22 | testMnemo = `ramp soldier connect gadget domain mutual staff unusual first midnight iron good deputy wage vehicle mutual spike unlock rocket delay hundred script tumble choose`
23 | bondDenom = "utick"
24 | )
25 |
26 | func QueryWithoutProof(clientCtx client.Context, hashHexStr string) (*rpctypes.ResultTx, error) {
27 | hash, err := hex.DecodeString(hashHexStr)
28 | if err != nil {
29 | return nil, err
30 | }
31 |
32 | node, err := clientCtx.GetNode()
33 | if err != nil {
34 | return nil, err
35 | }
36 |
37 | return node.Tx(context.Background(), hash, false)
38 | }
39 |
40 | func GenerateKeyring(accounts ...string) keyring.Keyring {
41 | cdc := simapp.MakeTestEncodingConfig().Codec
42 | kb := keyring.NewInMemory(cdc)
43 |
44 | for _, acc := range accounts {
45 | _, _, err := kb.NewMnemonic(acc, keyring.English, "", "", hd.Secp256k1)
46 | if err != nil {
47 | panic(err)
48 | }
49 | }
50 |
51 | _, err := kb.NewAccount(TestAccName, testMnemo, "1234", "", hd.Secp256k1)
52 | if err != nil {
53 | panic(err)
54 | }
55 |
56 | return kb
57 | }
58 |
59 | func RandomAddress() sdk.Address {
60 | name := tmrand.Str(6)
61 | kr := GenerateKeyring(name)
62 | rec, err := kr.Key(name)
63 | if err != nil {
64 | panic(err)
65 | }
66 | addr, err := rec.GetAddress()
67 | if err != nil {
68 | panic(err)
69 | }
70 | return addr
71 | }
72 |
73 | func FundKeyringAccounts(cdc codec.Codec, accounts ...string) (keyring.Keyring, []banktypes.Balance, []authtypes.GenesisAccount) {
74 | kr := GenerateKeyring(accounts...)
75 | genAccounts := make([]authtypes.GenesisAccount, len(accounts))
76 | genBalances := make([]banktypes.Balance, len(accounts))
77 |
78 | for i, acc := range accounts {
79 | rec, err := kr.Key(acc)
80 | if err != nil {
81 | panic(err)
82 | }
83 |
84 | addr, err := rec.GetAddress()
85 | if err != nil {
86 | panic(err)
87 | }
88 |
89 | balances := sdk.NewCoins(
90 | sdk.NewCoin(bondDenom, sdk.NewInt(99999999999999999)),
91 | )
92 |
93 | genBalances[i] = banktypes.Balance{Address: addr.String(), Coins: balances.Sort()}
94 | genAccounts[i] = authtypes.NewBaseAccount(addr, nil, 0, 0)
95 | }
96 | return kr, genBalances, genAccounts
97 | }
98 |
--------------------------------------------------------------------------------
/third_party/proto/tendermint/types/params.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package tendermint.types;
3 |
4 | option go_package = "github.com/tendermint/tendermint/proto/tendermint/types";
5 |
6 | import "gogoproto/gogo.proto";
7 | import "google/protobuf/duration.proto";
8 |
9 | option (gogoproto.equal_all) = true;
10 |
11 | // ConsensusParams contains consensus critical parameters that determine the
12 | // validity of blocks.
13 | message ConsensusParams {
14 | BlockParams block = 1 [(gogoproto.nullable) = false];
15 | EvidenceParams evidence = 2 [(gogoproto.nullable) = false];
16 | ValidatorParams validator = 3 [(gogoproto.nullable) = false];
17 | VersionParams version = 4 [(gogoproto.nullable) = false];
18 | }
19 |
20 | // BlockParams contains limits on the block size.
21 | message BlockParams {
22 | // Max block size, in bytes.
23 | // Note: must be greater than 0
24 | int64 max_bytes = 1;
25 | // Max gas per block.
26 | // Note: must be greater or equal to -1
27 | int64 max_gas = 2;
28 | // Minimum time increment between consecutive blocks (in milliseconds) If the
29 | // block header timestamp is ahead of the system clock, decrease this value.
30 | //
31 | // Not exposed to the application.
32 | int64 time_iota_ms = 3;
33 | }
34 |
35 | // EvidenceParams determine how we handle evidence of malfeasance.
36 | message EvidenceParams {
37 | // Max age of evidence, in blocks.
38 | //
39 | // The basic formula for calculating this is: MaxAgeDuration / {average block
40 | // time}.
41 | int64 max_age_num_blocks = 1;
42 |
43 | // Max age of evidence, in time.
44 | //
45 | // It should correspond with an app's "unbonding period" or other similar
46 | // mechanism for handling [Nothing-At-Stake
47 | // attacks](https://github.com/ethereum/wiki/wiki/Proof-of-Stake-FAQ#what-is-the-nothing-at-stake-problem-and-how-can-it-be-fixed).
48 | google.protobuf.Duration max_age_duration = 2
49 | [(gogoproto.nullable) = false, (gogoproto.stdduration) = true];
50 |
51 | // This sets the maximum size of total evidence in bytes that can be committed in a single block.
52 | // and should fall comfortably under the max block bytes.
53 | // Default is 1048576 or 1MB
54 | int64 max_bytes = 3;
55 | }
56 |
57 | // ValidatorParams restrict the public key types validators can use.
58 | // NOTE: uses ABCI pubkey naming, not Amino names.
59 | message ValidatorParams {
60 | option (gogoproto.populate) = true;
61 | option (gogoproto.equal) = true;
62 |
63 | repeated string pub_key_types = 1;
64 | }
65 |
66 | // VersionParams contains the ABCI application version.
67 | message VersionParams {
68 | option (gogoproto.populate) = true;
69 | option (gogoproto.equal) = true;
70 |
71 | uint64 app_version = 1;
72 | }
73 |
74 | // HashedParams is a subset of ConsensusParams.
75 | //
76 | // It is hashed into the Header.ConsensusHash.
77 | message HashedParams {
78 | int64 block_max_bytes = 1;
79 | int64 block_max_gas = 2;
80 | }
81 |
--------------------------------------------------------------------------------
/app/module.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "encoding/json"
5 |
6 | "github.com/cosmos/cosmos-sdk/codec"
7 | sdk "github.com/cosmos/cosmos-sdk/types"
8 | "github.com/cosmos/cosmos-sdk/x/bank"
9 | banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
10 | "github.com/cosmos/cosmos-sdk/x/crisis"
11 | crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types"
12 | "github.com/cosmos/cosmos-sdk/x/mint"
13 | minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
14 | "github.com/cosmos/cosmos-sdk/x/staking"
15 | stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
16 | "github.com/histolabs/metro/pkg/consts"
17 | )
18 |
19 | // bankModule defines a custom wrapper around the x/bank module's AppModuleBasic
20 | // implementation to provide custom default genesis state.
21 | type bankModule struct {
22 | bank.AppModuleBasic
23 | }
24 |
25 | // DefaultGenesis returns custom x/bank module genesis state.
26 | func (bankModule) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage {
27 | metadata := banktypes.Metadata{
28 | Description: "The native staking token of the Celestia network.",
29 | Base: consts.BondDenom,
30 | Name: consts.DisplayDenom,
31 | Display: consts.DisplayDenom,
32 | Symbol: consts.DisplayDenom,
33 | DenomUnits: []*banktypes.DenomUnit{
34 | {
35 | Denom: consts.BondDenom,
36 | Exponent: 0,
37 | Aliases: []string{
38 | consts.BondDenomAlias,
39 | },
40 | },
41 | {
42 | Denom: consts.DisplayDenom,
43 | Exponent: 6,
44 | Aliases: []string{},
45 | },
46 | },
47 | }
48 |
49 | genState := banktypes.DefaultGenesisState()
50 | genState.DenomMetadata = append(genState.DenomMetadata, metadata)
51 |
52 | return cdc.MustMarshalJSON(genState)
53 | }
54 |
55 | // stakingModule wraps the x/staking module in order to overwrite specific
56 | // ModuleManager APIs.
57 | type stakingModule struct {
58 | staking.AppModuleBasic
59 | }
60 |
61 | // DefaultGenesis returns custom x/staking module genesis state.
62 | func (stakingModule) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage {
63 | params := stakingtypes.DefaultParams()
64 | params.BondDenom = consts.BondDenom
65 |
66 | return cdc.MustMarshalJSON(&stakingtypes.GenesisState{
67 | Params: params,
68 | })
69 | }
70 |
71 | type crisisModule struct {
72 | crisis.AppModuleBasic
73 | }
74 |
75 | // DefaultGenesis returns custom x/crisis module genesis state.
76 | func (crisisModule) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage {
77 | return cdc.MustMarshalJSON(&crisistypes.GenesisState{
78 | ConstantFee: sdk.NewCoin(consts.BondDenom, sdk.NewInt(1000)),
79 | })
80 | }
81 |
82 | type mintModule struct {
83 | mint.AppModuleBasic
84 | }
85 |
86 | // DefaultGenesis returns custom x/mint module genesis state.
87 | func (mintModule) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage {
88 | genState := minttypes.DefaultGenesisState()
89 | genState.Params.MintDenom = consts.BondDenom
90 |
91 | return cdc.MustMarshalJSON(genState)
92 | }
93 |
--------------------------------------------------------------------------------
/third_party/proto/google/api/httpbody.proto:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | //
15 |
16 | syntax = "proto3";
17 |
18 | package google.api;
19 |
20 | import "google/protobuf/any.proto";
21 |
22 | option cc_enable_arenas = true;
23 | option go_package = "google.golang.org/genproto/googleapis/api/httpbody;httpbody";
24 | option java_multiple_files = true;
25 | option java_outer_classname = "HttpBodyProto";
26 | option java_package = "com.google.api";
27 | option objc_class_prefix = "GAPI";
28 |
29 | // Message that represents an arbitrary HTTP body. It should only be used for
30 | // payload formats that can't be represented as JSON, such as raw binary or
31 | // an HTML page.
32 | //
33 | //
34 | // This message can be used both in streaming and non-streaming API methods in
35 | // the request as well as the response.
36 | //
37 | // It can be used as a top-level request field, which is convenient if one
38 | // wants to extract parameters from either the URL or HTTP template into the
39 | // request fields and also want access to the raw HTTP body.
40 | //
41 | // Example:
42 | //
43 | // message GetResourceRequest {
44 | // // A unique request id.
45 | // string request_id = 1;
46 | //
47 | // // The raw HTTP body is bound to this field.
48 | // google.api.HttpBody http_body = 2;
49 | // }
50 | //
51 | // service ResourceService {
52 | // rpc GetResource(GetResourceRequest) returns (google.api.HttpBody);
53 | // rpc UpdateResource(google.api.HttpBody) returns
54 | // (google.protobuf.Empty);
55 | // }
56 | //
57 | // Example with streaming methods:
58 | //
59 | // service CaldavService {
60 | // rpc GetCalendar(stream google.api.HttpBody)
61 | // returns (stream google.api.HttpBody);
62 | // rpc UpdateCalendar(stream google.api.HttpBody)
63 | // returns (stream google.api.HttpBody);
64 | // }
65 | //
66 | // Use of this type only changes how the request and response bodies are
67 | // handled, all other features will continue to work unchanged.
68 | message HttpBody {
69 | // The HTTP Content-Type header value specifying the content type of the body.
70 | string content_type = 1;
71 |
72 | // The HTTP request/response body as raw binary.
73 | bytes data = 2;
74 |
75 | // Application specific response metadata. Must be set in the first response
76 | // for streaming APIs.
77 | repeated google.protobuf.Any extensions = 3;
78 | }
--------------------------------------------------------------------------------
/pkg/builder/builder_options.go:
--------------------------------------------------------------------------------
1 | package builder
2 |
3 | import (
4 | sdkclient "github.com/cosmos/cosmos-sdk/client"
5 | sdk "github.com/cosmos/cosmos-sdk/types"
6 | "github.com/cosmos/cosmos-sdk/types/tx"
7 | authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
8 | )
9 |
10 | type TxBuilderOption func(builder sdkclient.TxBuilder) sdkclient.TxBuilder
11 |
12 | func SetGasLimit(limit uint64) TxBuilderOption {
13 | return func(builder sdkclient.TxBuilder) sdkclient.TxBuilder {
14 | builder.SetGasLimit(limit)
15 | return builder
16 | }
17 | }
18 |
19 | func SetFeeAmount(fees sdk.Coins) TxBuilderOption {
20 | return func(builder sdkclient.TxBuilder) sdkclient.TxBuilder {
21 | builder.SetFeeAmount(fees)
22 | return builder
23 | }
24 | }
25 |
26 | func SetMemo(memo string) TxBuilderOption {
27 | return func(builder sdkclient.TxBuilder) sdkclient.TxBuilder {
28 | builder.SetMemo(memo)
29 | return builder
30 | }
31 | }
32 |
33 | func SetFeePayer(feePayer sdk.AccAddress) TxBuilderOption {
34 | return func(builder sdkclient.TxBuilder) sdkclient.TxBuilder {
35 | builder.SetFeePayer(feePayer)
36 | return builder
37 | }
38 | }
39 |
40 | func SetTip(tip *tx.Tip) TxBuilderOption {
41 | return func(builder sdkclient.TxBuilder) sdkclient.TxBuilder {
42 | builder.SetTip(tip)
43 | return builder
44 | }
45 | }
46 |
47 | func SetTimeoutHeight(height uint64) TxBuilderOption {
48 | return func(builder sdkclient.TxBuilder) sdkclient.TxBuilder {
49 | builder.SetTimeoutHeight(height)
50 | return builder
51 | }
52 | }
53 |
54 | func SetFeeGranter(feeGranter sdk.AccAddress) TxBuilderOption {
55 | return func(builder sdkclient.TxBuilder) sdkclient.TxBuilder {
56 | builder.SetFeeGranter(feeGranter)
57 | return builder
58 | }
59 | }
60 |
61 | // InheritTxConfig sets all of the accessible configurations from a given tx
62 | // into a a give client.TxBuilder
63 | func InheritTxConfig(builder sdkclient.TxBuilder, tx authsigning.Tx) sdkclient.TxBuilder {
64 | if gas := tx.GetGas(); gas != 0 {
65 | builder.SetGasLimit(gas)
66 | }
67 |
68 | if feeAmmount := tx.GetFee(); !feeAmmount.AmountOf("utia").Equal(sdk.NewInt(0)) {
69 | builder.SetFeeAmount(tx.GetFee())
70 | }
71 |
72 | if memo := tx.GetMemo(); memo != "" {
73 | builder.SetMemo(tx.GetMemo())
74 | }
75 |
76 | if tip := tx.GetTip(); tip != nil {
77 | builder.SetTip(tip)
78 | }
79 |
80 | if timeoutHeight := tx.GetTimeoutHeight(); timeoutHeight != 0 {
81 | builder.SetTimeoutHeight(timeoutHeight)
82 | }
83 |
84 | signers := tx.GetSigners()
85 | // Note: if there are multiple signers in a PFB, then this could create an
86 | // invalid signature. This is not an issue at this time because we currently
87 | // ignore pfbs with multiple signers
88 | if len(signers) == 1 {
89 | if feePayer := tx.FeeGranter(); !feePayer.Equals(signers[0]) {
90 | builder.SetFeeGranter(tx.FeeGranter())
91 | }
92 | }
93 |
94 | if feeGranter := tx.FeeGranter(); !feeGranter.Empty() {
95 | builder.SetFeeGranter(tx.FeeGranter())
96 | }
97 |
98 | return builder
99 | }
100 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #!/usr/bin/make -f
2 |
3 | VERSION := $(shell echo $(shell git describe --tags) | sed 's/^v//')
4 | COMMIT := $(shell git log -1 --format='%H')
5 | DOCKER := $(shell which docker)
6 | DOCKER_BUF := $(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace bufbuild/buf
7 | IMAGE := ghcr.io/tendermint/docker-build-proto:latest
8 | DOCKER_PROTO_BUILDER := docker run -v $(shell pwd):/workspace --workdir /workspace $(IMAGE)
9 |
10 | # process linker flags
11 | ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=metro \
12 | -X github.com/cosmos/cosmos-sdk/version.AppName=metro \
13 | -X github.com/cosmos/cosmos-sdk/version.Version=$(VERSION) \
14 | -X github.com/cosmos/cosmos-sdk/version.Commit=$(COMMIT) \
15 | -X "github.com/cosmos/cosmos-sdk/version.BuildTags=$(build_tags_comma_sep)"
16 | ldflags += $(LDFLAGS)
17 |
18 | BUILD_FLAGS := -ldflags '$(ldflags)'
19 |
20 | all: install
21 |
22 | install: go.sum
23 | @echo "--> Installing metro"
24 | @go install -mod=readonly $(BUILD_FLAGS) ./cmd/metro
25 |
26 | go.sum: mod
27 | @echo "--> Verifying dependencies have expected content"
28 | GO111MODULE=on go mod verify
29 |
30 | mod:
31 | @echo "--> Updating go.mod"
32 | @go mod tidy
33 |
34 | pre-build:
35 | @echo "--> Fetching latest git tags"
36 | @git fetch --tags
37 |
38 | build: mod
39 | @go install github.com/gobuffalo/packr/v2/packr2@latest
40 | @cd ./cmd/metro && packr2
41 | @mkdir -p build/
42 | @go build $(BUILD_FLAGS) -o build/ ./cmd/metro
43 | @packr2 clean
44 | @go mod tidy
45 |
46 | proto-gen:
47 | @echo "--> Generating Protobuf files"
48 | $(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace tendermintdev/sdk-proto-gen:v0.7 sh ./scripts/protocgen.sh
49 | .PHONY: proto-gen
50 |
51 | proto-lint:
52 | @echo "--> Linting Protobuf files"
53 | @$(DOCKER_BUF) lint --error-format=json
54 | .PHONY: proto-lint
55 |
56 | proto-format:
57 | @echo "--> Formatting Protobuf files"
58 | @$(DOCKER_PROTO_BUILDER) find . -name '*.proto' -path "./proto/*" -exec clang-format -i {} \;
59 | .PHONY: proto-format
60 |
61 | build-docker:
62 | @echo "--> Building Docker image"
63 | $(DOCKER) build -t histolabs/metro -f docker/Dockerfile .
64 | .PHONY: build-docker
65 |
66 | lint:
67 | @echo "--> Running golangci-lint"
68 | @golangci-lint run
69 | @echo "--> Running markdownlint"
70 | @markdownlint --config .markdownlint.yaml '**/*.md'
71 | .PHONY: lint
72 |
73 | fmt:
74 | @echo "--> Running golangci-lint --fix"
75 | @golangci-lint run --fix
76 | @echo "--> Running markdownlint --fix"
77 | @markdownlint --fix --quiet --config .markdownlint.yaml .
78 | .PHONY: fmt
79 |
80 | test:
81 | @echo "--> Running unit tests"
82 | @go test -mod=readonly ./...
83 | .PHONY: test
84 |
85 | test-all: test-race test-cover
86 |
87 | test-race:
88 | @echo "--> Running tests with -race"
89 | @VERSION=$(VERSION) go test -mod=readonly -race -test.short ./...
90 | .PHONY: test-race
91 |
92 | test-cover:
93 | @echo "--> Generating coverage.txt"
94 | @export VERSION=$(VERSION); bash -x scripts/test_cover.sh
95 | .PHONY: test-cover
96 |
97 | benchmark:
98 | @echo "--> Running tests with -bench"
99 | @go test -mod=readonly -bench=. ./...
100 | .PHONY: benchmark
101 |
--------------------------------------------------------------------------------
/third_party/proto/gogoproto/gogo.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers for Go with Gadgets
2 | //
3 | // Copyright (c) 2013, The GoGo Authors. All rights reserved.
4 | // http://github.com/gogo/protobuf
5 | //
6 | // Redistribution and use in source and binary forms, with or without
7 | // modification, are permitted provided that the following conditions are
8 | // met:
9 | //
10 | // * Redistributions of source code must retain the above copyright
11 | // notice, this list of conditions and the following disclaimer.
12 | // * Redistributions in binary form must reproduce the above
13 | // copyright notice, this list of conditions and the following disclaimer
14 | // in the documentation and/or other materials provided with the
15 | // distribution.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | syntax = "proto2";
30 | package gogoproto;
31 |
32 | import "google/protobuf/descriptor.proto";
33 |
34 | option java_package = "com.google.protobuf";
35 | option java_outer_classname = "GoGoProtos";
36 | option go_package = "github.com/gogo/protobuf/gogoproto";
37 |
38 | extend google.protobuf.EnumOptions {
39 | optional bool goproto_enum_prefix = 62001;
40 | optional bool goproto_enum_stringer = 62021;
41 | optional bool enum_stringer = 62022;
42 | optional string enum_customname = 62023;
43 | optional bool enumdecl = 62024;
44 | }
45 |
46 | extend google.protobuf.EnumValueOptions {
47 | optional string enumvalue_customname = 66001;
48 | }
49 |
50 | extend google.protobuf.FileOptions {
51 | optional bool goproto_getters_all = 63001;
52 | optional bool goproto_enum_prefix_all = 63002;
53 | optional bool goproto_stringer_all = 63003;
54 | optional bool verbose_equal_all = 63004;
55 | optional bool face_all = 63005;
56 | optional bool gostring_all = 63006;
57 | optional bool populate_all = 63007;
58 | optional bool stringer_all = 63008;
59 | optional bool onlyone_all = 63009;
60 |
61 | optional bool equal_all = 63013;
62 | optional bool description_all = 63014;
63 | optional bool testgen_all = 63015;
64 | optional bool benchgen_all = 63016;
65 | optional bool marshaler_all = 63017;
66 | optional bool unmarshaler_all = 63018;
67 | optional bool stable_marshaler_all = 63019;
68 |
69 | optional bool sizer_all = 63020;
70 |
71 | optional bool goproto_enum_stringer_all = 63021;
72 | optional bool enum_stringer_all = 63022;
73 |
74 | optional bool unsafe_marshaler_all = 63023;
75 | optional bool unsafe_unmarshaler_all = 63024;
76 |
77 | optional bool goproto_extensions_map_all = 63025;
78 | optional bool goproto_unrecognized_all = 63026;
79 | optional bool gogoproto_import = 63027;
80 | optional bool protosizer_all = 63028;
81 | optional bool compare_all = 63029;
82 | optional bool typedecl_all = 63030;
83 | optional bool enumdecl_all = 63031;
84 |
85 | optional bool goproto_registration = 63032;
86 | optional bool messagename_all = 63033;
87 |
88 | optional bool goproto_sizecache_all = 63034;
89 | optional bool goproto_unkeyed_all = 63035;
90 | }
91 |
92 | extend google.protobuf.MessageOptions {
93 | optional bool goproto_getters = 64001;
94 | optional bool goproto_stringer = 64003;
95 | optional bool verbose_equal = 64004;
96 | optional bool face = 64005;
97 | optional bool gostring = 64006;
98 | optional bool populate = 64007;
99 | optional bool stringer = 67008;
100 | optional bool onlyone = 64009;
101 |
102 | optional bool equal = 64013;
103 | optional bool description = 64014;
104 | optional bool testgen = 64015;
105 | optional bool benchgen = 64016;
106 | optional bool marshaler = 64017;
107 | optional bool unmarshaler = 64018;
108 | optional bool stable_marshaler = 64019;
109 |
110 | optional bool sizer = 64020;
111 |
112 | optional bool unsafe_marshaler = 64023;
113 | optional bool unsafe_unmarshaler = 64024;
114 |
115 | optional bool goproto_extensions_map = 64025;
116 | optional bool goproto_unrecognized = 64026;
117 |
118 | optional bool protosizer = 64028;
119 | optional bool compare = 64029;
120 |
121 | optional bool typedecl = 64030;
122 |
123 | optional bool messagename = 64033;
124 |
125 | optional bool goproto_sizecache = 64034;
126 | optional bool goproto_unkeyed = 64035;
127 | }
128 |
129 | extend google.protobuf.FieldOptions {
130 | optional bool nullable = 65001;
131 | optional bool embed = 65002;
132 | optional string customtype = 65003;
133 | optional string customname = 65004;
134 | optional string jsontag = 65005;
135 | optional string moretags = 65006;
136 | optional string casttype = 65007;
137 | optional string castkey = 65008;
138 | optional string castvalue = 65009;
139 |
140 | optional bool stdtime = 65010;
141 | optional bool stdduration = 65011;
142 | optional bool wktpointer = 65012;
143 |
144 | optional string castrepeated = 65013;
145 | }
146 |
--------------------------------------------------------------------------------
/pkg/builder/test/builder_test.go:
--------------------------------------------------------------------------------
1 | package builder_test
2 |
3 | import (
4 | "strings"
5 | "testing"
6 | "time"
7 |
8 | "github.com/histolabs/metro/app"
9 | "github.com/histolabs/metro/app/encoding"
10 | "github.com/histolabs/metro/pkg/builder"
11 | "github.com/histolabs/metro/pkg/consts"
12 | "github.com/histolabs/metro/testutil/testfactory"
13 | "github.com/histolabs/metro/testutil/testnode"
14 | "github.com/stretchr/testify/require"
15 | "github.com/stretchr/testify/suite"
16 |
17 | sdk "github.com/cosmos/cosmos-sdk/types"
18 | banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
19 | abci "github.com/tendermint/tendermint/abci/types"
20 | )
21 |
22 | func TestIntegrationTestSuite(t *testing.T) {
23 | suite.Run(t, new(IntegrationTestSuite))
24 | }
25 |
26 | type IntegrationTestSuite struct {
27 | suite.Suite
28 |
29 | cleanup func() error
30 | accounts []string
31 | cctx testnode.Context
32 | ecfg encoding.Config
33 | }
34 |
35 | func (s *IntegrationTestSuite) SetupSuite() {
36 | if testing.Short() {
37 | s.T().Skip("skipping test in unit-tests or race-detector mode.")
38 | }
39 |
40 | s.T().Log("setting up integration test suite")
41 | cleanup, accounts, cctx := testnode.DefaultNetwork(s.T(), time.Millisecond*500)
42 |
43 | s.cctx = cctx
44 | s.accounts = accounts
45 | s.cleanup = cleanup
46 |
47 | s.ecfg = encoding.MakeConfig(app.ModuleEncodingRegisters...)
48 | }
49 |
50 | func (s *IntegrationTestSuite) TearDownSuite() {
51 | s.T().Log("tearing down integration test suite")
52 | err := s.cleanup()
53 | require.NoError(s.T(), err)
54 | }
55 |
56 | func (s *IntegrationTestSuite) TestPrimaryChainIDBuilder() {
57 | t := s.T()
58 |
59 | // define the tx builder options
60 | feeCoin := sdk.Coin{
61 | Denom: consts.BondDenom,
62 | Amount: sdk.NewInt(1),
63 | }
64 |
65 | opts := []builder.TxBuilderOption{
66 | builder.SetFeeAmount(sdk.NewCoins(feeCoin)),
67 | builder.SetGasLimit(1000000000),
68 | }
69 |
70 | signer := builder.NewKeyringSigner(s.ecfg, s.cctx.Keyring, s.accounts[0], s.cctx.ChainID)
71 | err := signer.UpdateAccount(s.cctx.GoContext(), s.cctx.GRPCClient)
72 | require.NoError(t, err)
73 |
74 | msg := createMsgSend(t, signer, s.accounts[1], sdk.NewInt(10000000))
75 |
76 | sdkTx, err := signer.BuildSignedTx(signer.NewTxBuilder(opts...), false, msg)
77 | require.NoError(t, err)
78 |
79 | rawTx, err := s.ecfg.TxConfig.TxEncoder()(sdkTx)
80 | require.NoError(t, err)
81 |
82 | resp, err := s.cctx.BroadcastTxSync(rawTx)
83 | require.NoError(t, err)
84 |
85 | require.Equal(t, abci.CodeTypeOK, resp.Code)
86 |
87 | err = s.cctx.WaitForNextBlock()
88 | require.NoError(t, err)
89 |
90 | res, err := testfactory.QueryWithoutProof(s.cctx.Context, resp.TxHash)
91 | require.NoError(t, err)
92 |
93 | require.Equal(t, abci.CodeTypeOK, res.TxResult.Code)
94 | }
95 |
96 | func (s *IntegrationTestSuite) TestSecondaryChainIDBuilder() {
97 | t := s.T()
98 |
99 | // define the tx builder options
100 | feeCoin := sdk.Coin{
101 | Denom: consts.BondDenom,
102 | Amount: sdk.NewInt(1),
103 | }
104 |
105 | opts := []builder.TxBuilderOption{
106 | builder.SetFeeAmount(sdk.NewCoins(feeCoin)),
107 | builder.SetGasLimit(1000000000),
108 | }
109 |
110 | secondaryChainID := "taco"
111 | chainID := strings.Join([]string{s.cctx.ChainID, secondaryChainID}, consts.ChainIDSeparator)
112 |
113 | signer := builder.NewKeyringSigner(s.ecfg, s.cctx.Keyring, s.accounts[0], chainID)
114 | err := signer.UpdateAccount(s.cctx.GoContext(), s.cctx.GRPCClient)
115 | require.NoError(t, err)
116 |
117 | addr, err := signer.GetSignerInfo().GetAddress()
118 | require.NoError(t, err)
119 |
120 | initBal, err := queryBalance(s.cctx, addr)
121 | require.NoError(t, err)
122 |
123 | amount := sdk.NewInt(1000000000000)
124 |
125 | msg := createMsgSend(t, signer, s.accounts[1], amount)
126 |
127 | sdkTx, err := signer.BuildSignedTx(signer.NewTxBuilder(opts...), true, msg)
128 | require.NoError(t, err)
129 |
130 | rawTx, err := s.ecfg.TxConfig.TxEncoder()(sdkTx)
131 | require.NoError(t, err)
132 |
133 | resp, err := s.cctx.BroadcastTxSync(rawTx)
134 | require.NoError(t, err)
135 |
136 | require.Equal(t, abci.CodeTypeOK, resp.Code)
137 |
138 | err = s.cctx.WaitForNextBlock()
139 | require.NoError(t, err)
140 |
141 | res, err := testfactory.QueryWithoutProof(s.cctx.Context, resp.TxHash)
142 | require.NoError(t, err)
143 |
144 | require.Equal(t, abci.CodeTypeOK, res.TxResult.Code)
145 |
146 | currentBal, err := queryBalance(s.cctx, addr)
147 | require.NoError(t, err)
148 |
149 | // check that the balance only decreased from gas and that the send did not actually get executed
150 | diff := initBal.Sub(*currentBal)
151 | require.True(t, diff.Amount.LT(amount))
152 | require.True(t, diff.Amount.GTE(sdk.NewInt(1)))
153 | }
154 |
155 | func createMsgSend(t *testing.T, signer *builder.KeyringSigner, receiver string, amount sdk.Int) *banktypes.MsgSend {
156 | // create a msg send transaction
157 | amountCoin := sdk.Coin{
158 | Denom: consts.BondDenom,
159 | Amount: amount,
160 | }
161 |
162 | addr, err := signer.GetSignerInfo().GetAddress()
163 | if err != nil {
164 | panic(err)
165 | }
166 |
167 | sendAcc, err := signer.Key(receiver)
168 | require.NoError(t, err)
169 |
170 | sendAddr, err := sendAcc.GetAddress()
171 | require.NoError(t, err)
172 |
173 | return banktypes.NewMsgSend(addr, sendAddr, sdk.NewCoins(amountCoin))
174 | }
175 |
176 | func queryBalance(cctx testnode.Context, addr sdk.AccAddress) (*sdk.Coin, error) {
177 | qc := banktypes.NewQueryClient(cctx.GRPCClient)
178 |
179 | res, err := qc.Balance(cctx.GoContext(), banktypes.NewQueryBalanceRequest(addr, consts.BondDenom))
180 | if err != nil {
181 | return nil, err
182 | }
183 |
184 | return res.Balance, nil
185 | }
186 |
--------------------------------------------------------------------------------
/testutil/testnode/node_init.go:
--------------------------------------------------------------------------------
1 | package testnode
2 |
3 | import (
4 | "crypto/ecdsa"
5 | "encoding/json"
6 | "fmt"
7 | "net/url"
8 | "os"
9 | "path/filepath"
10 | "testing"
11 |
12 | "github.com/cosmos/cosmos-sdk/client/tx"
13 | "github.com/cosmos/cosmos-sdk/codec"
14 | "github.com/cosmos/cosmos-sdk/crypto/keyring"
15 | cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
16 | "github.com/cosmos/cosmos-sdk/server"
17 | sdk "github.com/cosmos/cosmos-sdk/types"
18 | banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
19 | "github.com/cosmos/cosmos-sdk/x/genutil"
20 | genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
21 | stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
22 | "github.com/ethereum/go-ethereum/crypto"
23 | "github.com/histolabs/metro/app/encoding"
24 | "github.com/histolabs/metro/pkg/consts"
25 | "github.com/tendermint/tendermint/config"
26 | tmos "github.com/tendermint/tendermint/libs/os"
27 | tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
28 | "github.com/tendermint/tendermint/types"
29 | tmtime "github.com/tendermint/tendermint/types/time"
30 | )
31 |
32 | func collectGenFiles(tmCfg *config.Config, encCfg encoding.Config, pubKey cryptotypes.PubKey, nodeID, chainID, rootDir string) error {
33 | genTime := tmtime.Now()
34 |
35 | gentxsDir := filepath.Join(rootDir, "gentxs")
36 |
37 | initCfg := genutiltypes.NewInitConfig(chainID, gentxsDir, nodeID, pubKey)
38 |
39 | genFile := tmCfg.GenesisFile()
40 | genDoc, err := types.GenesisDocFromFile(genFile)
41 | if err != nil {
42 | return err
43 | }
44 |
45 | appState, err := genutil.GenAppStateFromConfig(
46 | encCfg.Codec,
47 | encCfg.TxConfig,
48 | tmCfg,
49 | initCfg,
50 | *genDoc,
51 | banktypes.GenesisBalancesIterator{},
52 | )
53 | if err != nil {
54 | return err
55 | }
56 |
57 | genDoc = &types.GenesisDoc{
58 | GenesisTime: genTime,
59 | ChainID: chainID,
60 | Validators: nil,
61 | AppState: appState,
62 | ConsensusParams: genDoc.ConsensusParams,
63 | }
64 |
65 | if err := genDoc.ValidateAndComplete(); err != nil {
66 | return err
67 | }
68 |
69 | return genDoc.SaveAs(genFile)
70 | }
71 |
72 | func initGenFiles(
73 | cparams *tmproto.ConsensusParams,
74 | state map[string]json.RawMessage,
75 | codec codec.Codec,
76 | file,
77 | chainID string,
78 | ) error {
79 | appGenStateJSON, err := json.MarshalIndent(state, "", " ")
80 | if err != nil {
81 | return err
82 | }
83 |
84 | genDoc := types.GenesisDoc{
85 | ChainID: chainID,
86 | AppState: appGenStateJSON,
87 | ConsensusParams: cparams,
88 | Validators: nil,
89 | }
90 |
91 | return genDoc.SaveAs(file)
92 | }
93 |
94 | func createValidator(
95 | kr keyring.Keyring,
96 | encCfg encoding.Config,
97 | pubKey cryptotypes.PubKey,
98 | valopAcc,
99 | nodeID,
100 | chainID,
101 | baseDir string,
102 | ) error {
103 | rec, err := kr.Key(valopAcc)
104 | if err != nil {
105 | return err
106 | }
107 | addr, err := rec.GetAddress()
108 | if err != nil {
109 | return err
110 | }
111 | p2pAddr, _, err := server.FreeTCPAddr()
112 | if err != nil {
113 | return err
114 | }
115 | p2pURL, err := url.Parse(p2pAddr)
116 | if err != nil {
117 | return err
118 | }
119 | commission, err := sdk.NewDecFromStr("0.5")
120 | if err != nil {
121 | return err
122 | }
123 | ethPrivateKey, err := crypto.GenerateKey()
124 | if err != nil {
125 | return err
126 | }
127 | orchEVMPublicKey := ethPrivateKey.Public().(*ecdsa.PublicKey)
128 | evmAddr := crypto.PubkeyToAddress(*orchEVMPublicKey)
129 |
130 | createValMsg, err := stakingtypes.NewMsgCreateValidator(
131 | sdk.ValAddress(addr),
132 | pubKey,
133 | sdk.NewCoin(consts.BondDenom, sdk.NewInt(100000000)),
134 | stakingtypes.NewDescription("test", "", "", "", ""),
135 | stakingtypes.NewCommissionRates(commission, sdk.OneDec(), sdk.OneDec()),
136 | sdk.OneInt(),
137 | addr,
138 | evmAddr,
139 | )
140 | if err != nil {
141 | return err
142 | }
143 |
144 | memo := fmt.Sprintf("%s@%s:%s", nodeID, p2pURL.Hostname(), p2pURL.Port())
145 | fee := sdk.NewCoins(sdk.NewCoin(consts.BondDenom, sdk.NewInt(1)))
146 | txBuilder := encCfg.TxConfig.NewTxBuilder()
147 | err = txBuilder.SetMsgs(createValMsg)
148 | if err != nil {
149 | return err
150 | }
151 | txBuilder.SetFeeAmount(fee) // Arbitrary fee
152 | txBuilder.SetGasLimit(1000000) // Need at least 100386
153 | txBuilder.SetMemo(memo)
154 |
155 | txFactory := tx.Factory{}
156 | txFactory = txFactory.
157 | WithChainID(chainID).
158 | WithMemo(memo).
159 | WithKeybase(kr).
160 | WithTxConfig(encCfg.TxConfig)
161 |
162 | err = tx.Sign(txFactory, valopAcc, txBuilder, true)
163 | if err != nil {
164 | return err
165 | }
166 |
167 | txBz, err := encCfg.TxConfig.TxJSONEncoder()(txBuilder.GetTx())
168 | if err != nil {
169 | return err
170 | }
171 | gentxsDir := filepath.Join(baseDir, "gentxs")
172 | return writeFile(fmt.Sprintf("%v.json", "test"), gentxsDir, txBz)
173 | }
174 |
175 | func writeFile(name string, dir string, contents []byte) error {
176 | writePath := filepath.Join(dir)
177 | file := filepath.Join(writePath, name)
178 |
179 | err := tmos.EnsureDir(writePath, 0o755)
180 | if err != nil {
181 | return err
182 | }
183 |
184 | err = os.WriteFile(file, contents, 0o644) // nolint: gosec
185 | if err != nil {
186 | return err
187 | }
188 |
189 | return nil
190 | }
191 |
192 | func initFileStructure(t *testing.T, tmCfg *config.Config) (string, error) {
193 | basePath := filepath.Join(t.TempDir(), ".metro")
194 | tmCfg.SetRoot(basePath)
195 | configPath := filepath.Join(basePath, "config")
196 | err := os.MkdirAll(configPath, os.ModePerm)
197 | if err != nil {
198 | return "", err
199 | }
200 | if err != nil {
201 | return "", err
202 | }
203 | return basePath, nil
204 | }
205 |
--------------------------------------------------------------------------------
/third_party/proto/google/protobuf/any.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers - Google's data interchange format
2 | // Copyright 2008 Google Inc. All rights reserved.
3 | // https://developers.google.com/protocol-buffers/
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are
7 | // met:
8 | //
9 | // * Redistributions of source code must retain the above copyright
10 | // notice, this list of conditions and the following disclaimer.
11 | // * Redistributions in binary form must reproduce the above
12 | // copyright notice, this list of conditions and the following disclaimer
13 | // in the documentation and/or other materials provided with the
14 | // distribution.
15 | // * Neither the name of Google Inc. nor the names of its
16 | // contributors may be used to endorse or promote products derived from
17 | // this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | syntax = "proto3";
32 |
33 | package google.protobuf;
34 |
35 | import "gogoproto/gogo.proto";
36 |
37 | option csharp_namespace = "Google.Protobuf.WellKnownTypes";
38 | option go_package = "types";
39 | option java_package = "com.google.protobuf";
40 | option java_outer_classname = "AnyProto";
41 | option java_multiple_files = true;
42 | option objc_class_prefix = "GPB";
43 |
44 | // `Any` contains an arbitrary serialized protocol buffer message along with a
45 | // URL that describes the type of the serialized message.
46 | //
47 | // Protobuf library provides support to pack/unpack Any values in the form
48 | // of utility functions or additional generated methods of the Any type.
49 | //
50 | // Example 1: Pack and unpack a message in C++.
51 | //
52 | // Foo foo = ...;
53 | // Any any;
54 | // any.PackFrom(foo);
55 | // ...
56 | // if (any.UnpackTo(&foo)) {
57 | // ...
58 | // }
59 | //
60 | // Example 2: Pack and unpack a message in Java.
61 | //
62 | // Foo foo = ...;
63 | // Any any = Any.pack(foo);
64 | // ...
65 | // if (any.is(Foo.class)) {
66 | // foo = any.unpack(Foo.class);
67 | // }
68 | //
69 | // Example 3: Pack and unpack a message in Python.
70 | //
71 | // foo = Foo(...)
72 | // any = Any()
73 | // any.Pack(foo)
74 | // ...
75 | // if any.Is(Foo.DESCRIPTOR):
76 | // any.Unpack(foo)
77 | // ...
78 | //
79 | // Example 4: Pack and unpack a message in Go
80 | //
81 | // foo := &pb.Foo{...}
82 | // any, err := ptypes.MarshalAny(foo)
83 | // ...
84 | // foo := &pb.Foo{}
85 | // if err := ptypes.UnmarshalAny(any, foo); err != nil {
86 | // ...
87 | // }
88 | //
89 | // The pack methods provided by protobuf library will by default use
90 | // 'type.googleapis.com/full.type.name' as the type URL and the unpack
91 | // methods only use the fully qualified type name after the last '/'
92 | // in the type URL, for example "foo.bar.com/x/y.z" will yield type
93 | // name "y.z".
94 | //
95 | //
96 | // JSON
97 | // ====
98 | // The JSON representation of an `Any` value uses the regular
99 | // representation of the deserialized, embedded message, with an
100 | // additional field `@type` which contains the type URL. Example:
101 | //
102 | // package google.profile;
103 | // message Person {
104 | // string first_name = 1;
105 | // string last_name = 2;
106 | // }
107 | //
108 | // {
109 | // "@type": "type.googleapis.com/google.profile.Person",
110 | // "firstName": ,
111 | // "lastName":
112 | // }
113 | //
114 | // If the embedded message type is well-known and has a custom JSON
115 | // representation, that representation will be embedded adding a field
116 | // `value` which holds the custom JSON in addition to the `@type`
117 | // field. Example (for message [google.protobuf.Duration][]):
118 | //
119 | // {
120 | // "@type": "type.googleapis.com/google.protobuf.Duration",
121 | // "value": "1.212s"
122 | // }
123 | //
124 | message Any {
125 | // A URL/resource name that uniquely identifies the type of the serialized
126 | // protocol buffer message. This string must contain at least
127 | // one "/" character. The last segment of the URL's path must represent
128 | // the fully qualified name of the type (as in
129 | // `path/google.protobuf.Duration`). The name should be in a canonical form
130 | // (e.g., leading "." is not accepted).
131 | //
132 | // In practice, teams usually precompile into the binary all types that they
133 | // expect it to use in the context of Any. However, for URLs which use the
134 | // scheme `http`, `https`, or no scheme, one can optionally set up a type
135 | // server that maps type URLs to message definitions as follows:
136 | //
137 | // * If no scheme is provided, `https` is assumed.
138 | // * An HTTP GET on the URL must yield a [google.protobuf.Type][]
139 | // value in binary format, or produce an error.
140 | // * Applications are allowed to cache lookup results based on the
141 | // URL, or have them precompiled into a binary to avoid any
142 | // lookup. Therefore, binary compatibility needs to be preserved
143 | // on changes to types. (Use versioned type names to manage
144 | // breaking changes.)
145 | //
146 | // Note: this functionality is not currently available in the official
147 | // protobuf release, and it is not used for type URLs beginning with
148 | // type.googleapis.com.
149 | //
150 | // Schemes other than `http`, `https` (or the empty scheme) might be
151 | // used with implementation specific semantics.
152 | //
153 | string type_url = 1;
154 |
155 | // Must be a valid serialized protocol buffer of the above specified type.
156 | bytes value = 2;
157 |
158 | option (gogoproto.typedecl) = false;
159 | }
160 |
161 | option (gogoproto.goproto_registration) = false;
162 |
--------------------------------------------------------------------------------
/app/export.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "encoding/json"
5 | "log"
6 |
7 | tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
8 |
9 | servertypes "github.com/cosmos/cosmos-sdk/server/types"
10 | sdk "github.com/cosmos/cosmos-sdk/types"
11 | slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
12 | "github.com/cosmos/cosmos-sdk/x/staking"
13 | stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
14 | )
15 |
16 | // ExportAppStateAndValidators exports the state of the application for a genesis
17 | // file.
18 | func (app *App) ExportAppStateAndValidators(
19 | forZeroHeight bool, jailAllowedAddrs []string,
20 | ) (servertypes.ExportedApp, error) {
21 | // as if they could withdraw from the start of the next block
22 | ctx := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()})
23 |
24 | // We export at last height + 1, because that's the height at which
25 | // Tendermint will start InitChain.
26 | height := app.LastBlockHeight() + 1
27 | if forZeroHeight {
28 | height = 0
29 | app.prepForZeroHeightGenesis(ctx, jailAllowedAddrs)
30 | }
31 |
32 | genState := app.mm.ExportGenesis(ctx, app.appCodec)
33 | appState, err := json.MarshalIndent(genState, "", " ")
34 | if err != nil {
35 | return servertypes.ExportedApp{}, err
36 | }
37 |
38 | validators, err := staking.WriteValidators(ctx, app.StakingKeeper)
39 | return servertypes.ExportedApp{
40 | AppState: appState,
41 | Validators: validators,
42 | Height: height,
43 | ConsensusParams: app.BaseApp.GetConsensusParams(ctx),
44 | }, err
45 | }
46 |
47 | // prepForZeroHeightGenesis preps for fresh start at zero height. Zero height
48 | // genesis is a temporary feature which will be deprecated in favour of export
49 | // at a block height.
50 | func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []string) {
51 | applyAllowedAddrs := false
52 |
53 | // check if there is a allowed address list
54 | if len(jailAllowedAddrs) > 0 {
55 | applyAllowedAddrs = true
56 | }
57 |
58 | allowedAddrsMap := make(map[string]bool)
59 |
60 | for _, addr := range jailAllowedAddrs {
61 | _, err := sdk.ValAddressFromBech32(addr)
62 | if err != nil {
63 | log.Fatal(err)
64 | }
65 | allowedAddrsMap[addr] = true
66 | }
67 |
68 | /* Just to be safe, assert the invariants on current state. */
69 | app.CrisisKeeper.AssertInvariants(ctx)
70 |
71 | /* Handle fee distribution state. */
72 |
73 | // withdraw all validator commission
74 | app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) {
75 | _, _ = app.DistrKeeper.WithdrawValidatorCommission(ctx, val.GetOperator())
76 | return false
77 | })
78 |
79 | // withdraw all delegator rewards
80 | dels := app.StakingKeeper.GetAllDelegations(ctx)
81 | for _, delegation := range dels {
82 | valAddr, err := sdk.ValAddressFromBech32(delegation.ValidatorAddress)
83 | if err != nil {
84 | panic(err)
85 | }
86 |
87 | delAddr, err := sdk.AccAddressFromBech32(delegation.DelegatorAddress)
88 | if err != nil {
89 | panic(err)
90 | }
91 | _, _ = app.DistrKeeper.WithdrawDelegationRewards(ctx, delAddr, valAddr)
92 | }
93 |
94 | // clear validator slash events
95 | app.DistrKeeper.DeleteAllValidatorSlashEvents(ctx)
96 |
97 | // clear validator historical rewards
98 | app.DistrKeeper.DeleteAllValidatorHistoricalRewards(ctx)
99 |
100 | // set context height to zero
101 | height := ctx.BlockHeight()
102 | ctx = ctx.WithBlockHeight(0)
103 |
104 | // reinitialize all validators
105 | app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) {
106 | // donate any unwithdrawn outstanding reward fraction tokens to the community pool
107 | scraps := app.DistrKeeper.GetValidatorOutstandingRewardsCoins(ctx, val.GetOperator())
108 | feePool := app.DistrKeeper.GetFeePool(ctx)
109 | feePool.CommunityPool = feePool.CommunityPool.Add(scraps...)
110 | app.DistrKeeper.SetFeePool(ctx, feePool)
111 |
112 | if err := app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator()); err != nil {
113 | panic(err)
114 | }
115 | return false
116 | })
117 |
118 | // reinitialize all delegations
119 | for _, del := range dels {
120 | valAddr, err := sdk.ValAddressFromBech32(del.ValidatorAddress)
121 | if err != nil {
122 | panic(err)
123 | }
124 | delAddr, err := sdk.AccAddressFromBech32(del.DelegatorAddress)
125 | if err != nil {
126 | panic(err)
127 | }
128 | _ = app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, delAddr, valAddr)
129 | _ = app.DistrKeeper.Hooks().AfterDelegationModified(ctx, delAddr, valAddr)
130 | }
131 |
132 | // reset context height
133 | ctx = ctx.WithBlockHeight(height)
134 |
135 | /* Handle staking state. */
136 |
137 | // iterate through redelegations, reset creation height
138 | app.StakingKeeper.IterateRedelegations(ctx, func(_ int64, red stakingtypes.Redelegation) (stop bool) {
139 | for i := range red.Entries {
140 | red.Entries[i].CreationHeight = 0
141 | }
142 | app.StakingKeeper.SetRedelegation(ctx, red)
143 | return false
144 | })
145 |
146 | // iterate through unbonding delegations, reset creation height
147 | app.StakingKeeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd stakingtypes.UnbondingDelegation) (stop bool) {
148 | for i := range ubd.Entries {
149 | ubd.Entries[i].CreationHeight = 0
150 | }
151 | app.StakingKeeper.SetUnbondingDelegation(ctx, ubd)
152 | return false
153 | })
154 |
155 | // Iterate through validators by power descending, reset bond heights, and
156 | // update bond intra-tx counters.
157 | store := ctx.KVStore(app.keys[stakingtypes.StoreKey])
158 | iter := sdk.KVStoreReversePrefixIterator(store, stakingtypes.ValidatorsKey)
159 | counter := int16(0)
160 |
161 | for ; iter.Valid(); iter.Next() {
162 | addr := sdk.ValAddress(stakingtypes.AddressFromValidatorsKey(iter.Key()))
163 | validator, found := app.StakingKeeper.GetValidator(ctx, addr)
164 | if !found {
165 | panic("expected validator, not found")
166 | }
167 |
168 | validator.UnbondingHeight = 0
169 | if applyAllowedAddrs && !allowedAddrsMap[addr.String()] {
170 | validator.Jailed = true
171 | }
172 |
173 | app.StakingKeeper.SetValidator(ctx, validator)
174 | counter++
175 | }
176 |
177 | iter.Close()
178 |
179 | _, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
180 | if err != nil {
181 | log.Fatal(err)
182 | }
183 |
184 | /* Handle slashing state. */
185 |
186 | // reset start height on signing infos
187 | app.SlashingKeeper.IterateValidatorSigningInfos(
188 | ctx,
189 | func(addr sdk.ConsAddress, info slashingtypes.ValidatorSigningInfo) (stop bool) {
190 | info.StartHeight = 0
191 | app.SlashingKeeper.SetValidatorSigningInfo(ctx, addr, info)
192 | return false
193 | },
194 | )
195 | }
196 |
--------------------------------------------------------------------------------
/testutil/testnode/full_node.go:
--------------------------------------------------------------------------------
1 | package testnode
2 |
3 | import (
4 | "encoding/json"
5 | "os"
6 | "testing"
7 | "time"
8 |
9 | "github.com/cosmos/cosmos-sdk/crypto/keyring"
10 | pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types"
11 | "github.com/cosmos/cosmos-sdk/server"
12 | srvtypes "github.com/cosmos/cosmos-sdk/server/types"
13 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
14 | banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
15 | "github.com/cosmos/cosmos-sdk/x/genutil"
16 | "github.com/histolabs/metro/app"
17 | "github.com/histolabs/metro/app/encoding"
18 | "github.com/histolabs/metro/cmd/metro/cmd"
19 | "github.com/histolabs/metro/testutil/testfactory"
20 | "github.com/stretchr/testify/require"
21 | "github.com/tendermint/tendermint/config"
22 | "github.com/tendermint/tendermint/libs/log"
23 | tmrand "github.com/tendermint/tendermint/libs/rand"
24 | "github.com/tendermint/tendermint/node"
25 | "github.com/tendermint/tendermint/p2p"
26 | "github.com/tendermint/tendermint/privval"
27 | tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
28 | "github.com/tendermint/tendermint/proxy"
29 | "github.com/tendermint/tendermint/types"
30 | dbm "github.com/tendermint/tm-db"
31 | )
32 |
33 | // New creates a ready to use tendermint node that operates a single validator
34 | // metro network using the provided genesis state. The provided keyring
35 | // is stored in the client.Context that is returned.
36 | //
37 | // NOTE: the forced delay between blocks, TimeIotaMs in the consensus
38 | // parameters, is set to the lowest possible value (1ms).
39 | func New(
40 | t *testing.T,
41 | cparams *tmproto.ConsensusParams,
42 | tmCfg *config.Config,
43 | supressLog bool,
44 | genState map[string]json.RawMessage,
45 | kr keyring.Keyring,
46 | ) (*node.Node, srvtypes.Application, Context, error) {
47 | var logger log.Logger
48 | if supressLog {
49 | logger = log.NewNopLogger()
50 | } else {
51 | logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout))
52 | logger = log.NewFilter(logger, log.AllowError())
53 | }
54 |
55 | baseDir, err := initFileStructure(t, tmCfg)
56 | if err != nil {
57 | return nil, nil, Context{}, err
58 | }
59 |
60 | chainID := tmrand.Str(6)
61 |
62 | encCfg := encoding.MakeConfig(app.ModuleEncodingRegisters...)
63 |
64 | nodeKey, err := p2p.LoadOrGenNodeKey(tmCfg.NodeKeyFile())
65 | if err != nil {
66 | return nil, nil, Context{}, err
67 | }
68 |
69 | nodeID, pubKey, err := genutil.InitializeNodeValidatorFiles(tmCfg)
70 | if err != nil {
71 | return nil, nil, Context{}, err
72 | }
73 |
74 | err = createValidator(kr, encCfg, pubKey, "validator", nodeID, chainID, baseDir)
75 | if err != nil {
76 | return nil, nil, Context{}, err
77 | }
78 |
79 | err = initGenFiles(cparams, genState, encCfg.Codec, tmCfg.GenesisFile(), chainID)
80 | if err != nil {
81 | return nil, nil, Context{}, err
82 | }
83 |
84 | err = collectGenFiles(tmCfg, encCfg, pubKey, nodeID, chainID, baseDir)
85 | if err != nil {
86 | return nil, nil, Context{}, err
87 | }
88 |
89 | db := dbm.NewMemDB()
90 |
91 | appOpts := appOptions{
92 | options: map[string]interface{}{
93 | server.FlagPruning: pruningtypes.PruningOptionNothing,
94 | },
95 | }
96 |
97 | app := cmd.NewAppServer(logger, db, nil, appOpts)
98 |
99 | tmNode, err := node.NewNode(
100 | tmCfg,
101 | privval.LoadOrGenFilePV(tmCfg.PrivValidatorKeyFile(), tmCfg.PrivValidatorStateFile()),
102 | nodeKey,
103 | proxy.NewLocalClientCreator(app),
104 | node.DefaultGenesisDocProviderFunc(tmCfg),
105 | node.DefaultDBProvider,
106 | node.DefaultMetricsProvider(tmCfg.Instrumentation),
107 | logger,
108 | )
109 |
110 | cCtx := Context{}.
111 | WithKeyring(kr).
112 | WithHomeDir(tmCfg.RootDir).
113 | WithChainID(chainID).
114 | WithInterfaceRegistry(encCfg.InterfaceRegistry).
115 | WithCodec(encCfg.Codec).
116 | WithLegacyAmino(encCfg.Amino).
117 | WithTxConfig(encCfg.TxConfig).
118 | WithAccountRetriever(authtypes.AccountRetriever{})
119 |
120 | return tmNode, app, Context{Context: cCtx}, err
121 | }
122 |
123 | type appOptions struct {
124 | options map[string]interface{}
125 | }
126 |
127 | // Get implements AppOptions
128 | func (ao appOptions) Get(o string) interface{} {
129 | return ao.options[o]
130 | }
131 |
132 | func DefaultParams() *tmproto.ConsensusParams {
133 | cparams := types.DefaultConsensusParams()
134 | return cparams
135 | }
136 |
137 | func DefaultTendermintConfig() *config.Config {
138 | tmCfg := config.DefaultConfig()
139 | tmCfg.Consensus.TimeoutCommit = time.Millisecond * 300
140 | tmCfg.Mempool.MaxTxBytes = 22020096 // 21MB
141 | return tmCfg
142 | }
143 |
144 | // DefaultGenesisState returns a default genesis state and a keyring with
145 | // accounts that have coins. The keyring accounts are based on the
146 | // fundedAccounts parameter.
147 | func DefaultGenesisState(fundedAccounts ...string) (map[string]json.RawMessage, keyring.Keyring, error) {
148 | encCfg := encoding.MakeConfig(app.ModuleEncodingRegisters...)
149 | state := app.ModuleBasics.DefaultGenesis(encCfg.Codec)
150 | fundedAccounts = append(fundedAccounts, "validator")
151 | kr, bankBals, authAccs := testfactory.FundKeyringAccounts(encCfg.Codec, fundedAccounts...)
152 |
153 | // set the accounts in the genesis state
154 | var authGenState authtypes.GenesisState
155 | encCfg.Codec.MustUnmarshalJSON(state[authtypes.ModuleName], &authGenState)
156 |
157 | accounts, err := authtypes.PackAccounts(authAccs)
158 | if err != nil {
159 | return nil, nil, err
160 | }
161 |
162 | authGenState.Accounts = append(authGenState.Accounts, accounts...)
163 | state[authtypes.ModuleName] = encCfg.Codec.MustMarshalJSON(&authGenState)
164 |
165 | // set the balances in the genesis state
166 | var bankGenState banktypes.GenesisState
167 | encCfg.Codec.MustUnmarshalJSON(state[banktypes.ModuleName], &bankGenState)
168 |
169 | bankGenState.Balances = append(bankGenState.Balances, bankBals...)
170 | state[banktypes.ModuleName] = encCfg.Codec.MustMarshalJSON(&bankGenState)
171 |
172 | return state, kr, nil
173 | }
174 |
175 | // DefaultNetwork creates an in-process single validator metro network
176 | // using test friendly defaults. These defaults include fast block times and
177 | // funded accounts. The returned client.Context has a keyring with all of the
178 | // funded keys stored in it.
179 | func DefaultNetwork(t *testing.T, blockTime time.Duration) (cleanup func() error, accounts []string, cctx Context) {
180 | // we create an arbitrary number of funded accounts
181 | accounts = make([]string, 300)
182 | for i := 0; i < 300; i++ {
183 | accounts[i] = tmrand.Str(9)
184 | }
185 |
186 | tmCfg := DefaultTendermintConfig()
187 | tmCfg.Consensus.TimeoutCommit = blockTime
188 |
189 | genState, kr, err := DefaultGenesisState(accounts...)
190 | require.NoError(t, err)
191 |
192 | tmNode, app, cctx, err := New(t, DefaultParams(), tmCfg, false, genState, kr)
193 | require.NoError(t, err)
194 |
195 | cctx, stopNode, err := StartNode(tmNode, cctx)
196 | require.NoError(t, err)
197 |
198 | cctx, cleanupGRPC, err := StartGRPCServer(app, DefaultAppConfig(), cctx)
199 | require.NoError(t, err)
200 |
201 | return func() error {
202 | err := stopNode()
203 | if err != nil {
204 | return err
205 | }
206 | return cleanupGRPC()
207 | }, accounts, cctx
208 | }
209 |
--------------------------------------------------------------------------------
/third_party/proto/tendermint/types/types.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package tendermint.types;
3 |
4 | option go_package = "github.com/tendermint/tendermint/proto/tendermint/types";
5 |
6 | import "gogoproto/gogo.proto";
7 | import "google/protobuf/timestamp.proto";
8 | import "tendermint/crypto/proof.proto";
9 | import "tendermint/version/types.proto";
10 | import "tendermint/types/validator.proto";
11 |
12 | // BlockIdFlag indicates which BlcokID the signature is for
13 | enum BlockIDFlag {
14 | option (gogoproto.goproto_enum_stringer) = true;
15 | option (gogoproto.goproto_enum_prefix) = false;
16 |
17 | BLOCK_ID_FLAG_UNKNOWN = 0 [(gogoproto.enumvalue_customname) = "BlockIDFlagUnknown"];
18 | BLOCK_ID_FLAG_ABSENT = 1 [(gogoproto.enumvalue_customname) = "BlockIDFlagAbsent"];
19 | BLOCK_ID_FLAG_COMMIT = 2 [(gogoproto.enumvalue_customname) = "BlockIDFlagCommit"];
20 | BLOCK_ID_FLAG_NIL = 3 [(gogoproto.enumvalue_customname) = "BlockIDFlagNil"];
21 | }
22 |
23 | // SignedMsgType is a type of signed message in the consensus.
24 | enum SignedMsgType {
25 | option (gogoproto.goproto_enum_stringer) = true;
26 | option (gogoproto.goproto_enum_prefix) = false;
27 |
28 | SIGNED_MSG_TYPE_UNKNOWN = 0 [(gogoproto.enumvalue_customname) = "UnknownType"];
29 | // Votes
30 | SIGNED_MSG_TYPE_PREVOTE = 1 [(gogoproto.enumvalue_customname) = "PrevoteType"];
31 | SIGNED_MSG_TYPE_PRECOMMIT = 2 [(gogoproto.enumvalue_customname) = "PrecommitType"];
32 |
33 | // Proposals
34 | SIGNED_MSG_TYPE_PROPOSAL = 32 [(gogoproto.enumvalue_customname) = "ProposalType"];
35 | }
36 |
37 | // PartsetHeader
38 | message PartSetHeader {
39 | uint32 total = 1;
40 | bytes hash = 2;
41 | }
42 |
43 | message Part {
44 | uint32 index = 1;
45 | bytes bytes = 2;
46 | tendermint.crypto.Proof proof = 3 [(gogoproto.nullable) = false];
47 | }
48 |
49 | // BlockID
50 | message BlockID {
51 | bytes hash = 1;
52 | PartSetHeader part_set_header = 2 [(gogoproto.nullable) = false];
53 | }
54 |
55 | // --------------------------------
56 |
57 | // Header defines the structure of a Tendermint block header.
58 | message Header {
59 | // basic block info
60 | tendermint.version.Consensus version = 1 [(gogoproto.nullable) = false];
61 | string chain_id = 2 [(gogoproto.customname) = "ChainID"];
62 | int64 height = 3;
63 | google.protobuf.Timestamp time = 4 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
64 |
65 | // prev block info
66 | BlockID last_block_id = 5 [(gogoproto.nullable) = false];
67 |
68 | // hashes of block data
69 | bytes last_commit_hash = 6; // commit from validators from the last block
70 | bytes data_hash = 7; // transactions
71 |
72 | // hashes from the app output from the prev block
73 | bytes validators_hash = 8; // validators for the current block
74 | bytes next_validators_hash = 9; // validators for the next block
75 | bytes consensus_hash = 10; // consensus params for current block
76 | bytes app_hash = 11; // state after txs from the previous block
77 | bytes last_results_hash = 12; // root hash of all results from the txs from the previous block
78 |
79 | // consensus info
80 | bytes evidence_hash = 13; // evidence included in the block
81 | bytes proposer_address = 14; // original proposer of the block
82 | }
83 |
84 | // Data contains the set of transactions included in the block
85 | message Data {
86 | // Txs that will be applied by state @ block.Height+1.
87 | // NOTE: not all txs here are valid. We're just agreeing on the order first.
88 | // This means that block.AppHash does not include these txs.
89 | repeated bytes txs = 1;
90 | IntermediateStateRoots intermediate_state_roots = 2 [(gogoproto.nullable) = false];
91 | EvidenceList evidence = 3 [(gogoproto.nullable) = false];
92 | Messages messages = 4 [(gogoproto.nullable) = false];
93 | }
94 |
95 | message Evidence {
96 | oneof sum {
97 | DuplicateVoteEvidence duplicate_vote_evidence = 1;
98 | LightClientAttackEvidence light_client_attack_evidence = 2;
99 | }
100 | }
101 |
102 | // DuplicateVoteEvidence contains evidence of a validator signed two conflicting votes.
103 | message DuplicateVoteEvidence {
104 | tendermint.types.Vote vote_a = 1;
105 | tendermint.types.Vote vote_b = 2;
106 | int64 total_voting_power = 3;
107 | int64 validator_power = 4;
108 | google.protobuf.Timestamp timestamp = 5 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
109 | }
110 |
111 | // LightClientAttackEvidence contains evidence of a set of validators attempting to mislead a light client.
112 | message LightClientAttackEvidence {
113 | tendermint.types.LightBlock conflicting_block = 1;
114 | int64 common_height = 2;
115 | repeated tendermint.types.Validator byzantine_validators = 3;
116 | int64 total_voting_power = 4;
117 | google.protobuf.Timestamp timestamp = 5 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
118 | }
119 |
120 | message EvidenceList {
121 | repeated Evidence evidence = 1 [(gogoproto.nullable) = false];
122 | }
123 |
124 | message IntermediateStateRoots {
125 | repeated bytes raw_roots_list = 1;
126 | }
127 |
128 | message Messages {
129 | repeated Message messages_list = 1;
130 | }
131 |
132 | message Message {
133 | bytes namespace_id = 1;
134 | bytes data = 2;
135 | }
136 |
137 | // Vote represents a prevote, precommit, or commit vote from validators for
138 | // consensus.
139 | message Vote {
140 | SignedMsgType type = 1;
141 | int64 height = 2;
142 | int32 round = 3;
143 | BlockID block_id = 4
144 | [(gogoproto.nullable) = false, (gogoproto.customname) = "BlockID"]; // zero if vote is nil.
145 | google.protobuf.Timestamp timestamp = 5
146 | [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
147 | bytes validator_address = 6;
148 | int32 validator_index = 7;
149 | bytes signature = 8;
150 | }
151 |
152 | // Commit contains the evidence that a block was committed by a set of validators.
153 | message Commit {
154 | int64 height = 1;
155 | int32 round = 2;
156 | BlockID block_id = 3 [(gogoproto.nullable) = false, (gogoproto.customname) = "BlockID"];
157 | repeated CommitSig signatures = 4 [(gogoproto.nullable) = false];
158 | }
159 |
160 | // CommitSig is a part of the Vote included in a Commit.
161 | message CommitSig {
162 | BlockIDFlag block_id_flag = 1;
163 | bytes validator_address = 2;
164 | google.protobuf.Timestamp timestamp = 3
165 | [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
166 | bytes signature = 4;
167 | }
168 |
169 | message Proposal {
170 | SignedMsgType type = 1;
171 | int64 height = 2;
172 | int32 round = 3;
173 | int32 pol_round = 4;
174 | BlockID block_id = 5 [(gogoproto.customname) = "BlockID", (gogoproto.nullable) = false];
175 | google.protobuf.Timestamp timestamp = 6
176 | [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
177 | bytes signature = 7;
178 | }
179 |
180 | message SignedHeader {
181 | Header header = 1;
182 | Commit commit = 2;
183 | }
184 |
185 | message LightBlock {
186 | SignedHeader signed_header = 1;
187 | tendermint.types.ValidatorSet validator_set = 2;
188 | }
189 |
190 | message BlockMeta {
191 | BlockID block_id = 1 [(gogoproto.customname) = "BlockID", (gogoproto.nullable) = false];
192 | int64 block_size = 2;
193 | Header header = 3 [(gogoproto.nullable) = false];
194 | int64 num_txs = 4;
195 | }
196 |
197 | // TxProof represents a Merkle proof of the presence of a transaction in the Merkle tree.
198 | message TxProof {
199 | bytes root_hash = 1;
200 | bytes data = 2;
201 | tendermint.crypto.Proof proof = 3;
202 | }
203 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Tests / Code Coverage
2 | # Tests / Code Coverage workflow runs unit tests and uploads a code coverage
3 | # report
4 | # This workflow is run on pushes to main & every Pull Requests where a .go,
5 | # .mod, .sum have been changed
6 | on:
7 | workflow_call:
8 |
9 | jobs:
10 | cleanup-runs:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: rokroskar/workflow-run-cleanup-action@master
14 | env:
15 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
16 | if: |
17 | !startsWith(github.ref, 'refs/tags/') &&
18 | github.ref != 'refs/heads/master'
19 |
20 | install-tparse:
21 | runs-on: ubuntu-latest
22 | steps:
23 | - uses: actions/setup-go@v3
24 | with:
25 | go-version: 1.19
26 | - name: Display go version
27 | run: go version
28 | - name: install tparse
29 | run: >
30 | export GO111MODULE="on" &&
31 | go install github.com/mfridman/tparse@v0.8.3
32 | - uses: actions/cache@v3.2.2
33 | with:
34 | path: ~/go/bin
35 | key: ${{ runner.os }}-go-tparse-binary
36 |
37 | # don't use cosmovisor until we have tests
38 | # test-cosmovisor:
39 | # runs-on: ubuntu-latest
40 | # steps:
41 | # - uses: actions/checkout@v3
42 | # - uses: actions/setup-go@v3
43 | # with:
44 | # go-version: 1.19
45 | # - name: Display go version
46 | # run: go version
47 | # - uses: technote-space/get-diff-action@v6.1.2
48 | # id: git_diff
49 | # with:
50 | # PREFIX_FILTER: |
51 | # cosmovisor
52 | # PATTERNS: |
53 | # **/**.go
54 | # go.mod
55 | # go.sum
56 | # - name: Run cosmovisor tests
57 | # run: cd cosmovisor; make
58 | # if: env.GIT_DIFF
59 |
60 | split-test-files:
61 | runs-on: ubuntu-latest
62 | steps:
63 | - uses: actions/checkout@v3
64 | - name: Create a file with all the pkgs
65 | run: go list ./... > pkgs.txt
66 | - name: Split pkgs into 4 files
67 | run: split -d -n l/4 --elide-empty-files pkgs.txt pkgs.txt.part.
68 | # cache multiple
69 | - uses: actions/upload-artifact@v3
70 | with:
71 | name: "${{ github.sha }}-00"
72 | path: ./pkgs.txt.part.00
73 | - uses: actions/upload-artifact@v3
74 | with:
75 | name: "${{ github.sha }}-01"
76 | path: ./pkgs.txt.part.01
77 | - uses: actions/upload-artifact@v3
78 | with:
79 | name: "${{ github.sha }}-02"
80 | path: ./pkgs.txt.part.02
81 | - uses: actions/upload-artifact@v3
82 | with:
83 | name: "${{ github.sha }}-03"
84 | path: ./pkgs.txt.part.03
85 |
86 | tests:
87 | runs-on: ubuntu-latest
88 | needs: split-test-files
89 | strategy:
90 | fail-fast: false
91 | matrix:
92 | part: ["00", "01", "02", "03"]
93 | steps:
94 | - uses: actions/checkout@v3
95 | - uses: actions/setup-go@v3
96 | with:
97 | go-version: 1.19
98 | - uses: technote-space/get-diff-action@v6.1.2
99 | with:
100 | PATTERNS: |
101 | **/**.go
102 | go.mod
103 | go.sum
104 | - uses: actions/download-artifact@v3
105 | with:
106 | name: "${{ github.sha }}-${{ matrix.part }}"
107 | if: env.GIT_DIFF
108 | - name: test & coverage report creation
109 | run: >
110 | cat pkgs.txt.part.${{ matrix.part }} |
111 | xargs go test -mod=readonly -timeout 30m
112 | -coverprofile=${{ matrix.part }}profile.out
113 | -covermode=atomic -tags='norace ledger test_ledger_mock'
114 | if: env.GIT_DIFF
115 | - uses: actions/upload-artifact@v3
116 | with:
117 | name: "${{ github.sha }}-${{ matrix.part }}-coverage"
118 | path: ./${{ matrix.part }}profile.out
119 |
120 | upload-coverage-report:
121 | runs-on: ubuntu-latest
122 | needs: tests
123 | steps:
124 | - uses: actions/checkout@v3
125 | - uses: technote-space/get-diff-action@v6.1.2
126 | with:
127 | PATTERNS: |
128 | **/**.go
129 | go.mod
130 | go.sum
131 | - uses: actions/download-artifact@v3
132 | with:
133 | name: "${{ github.sha }}-00-coverage"
134 | if: env.GIT_DIFF
135 | - uses: actions/download-artifact@v3
136 | with:
137 | name: "${{ github.sha }}-01-coverage"
138 | if: env.GIT_DIFF
139 | - uses: actions/download-artifact@v3
140 | with:
141 | name: "${{ github.sha }}-02-coverage"
142 | if: env.GIT_DIFF
143 | - uses: actions/download-artifact@v3
144 | with:
145 | name: "${{ github.sha }}-03-coverage"
146 | if: env.GIT_DIFF
147 | - run: |
148 | cat ./*profile.out | grep -v "mode: atomic" >> coverage.txt
149 | if: env.GIT_DIFF
150 | - name: filter out DONTCOVER
151 | # yamllint disable
152 | run: |
153 | (find . -type f -name '*.go' | xargs grep -l 'DONTCOVER') > excludelist.txt
154 | find . -type f -name '*.pb.*' >> excludelist.txt
155 | find . -type f -path './tests/mocks/*.go' >> excludelist.txt
156 | while IFS= read -r filename; do
157 | # trim filename
158 | trimmedname=$(echo $filename | xargs)
159 | echo "Excluding ${trimmedname} from coverage report..."
160 | sed -i.bak "/$(echo $trimmedname | sed 's/\//\\\//g')/d" coverage.txt
161 | done < excludelist.txt
162 | # yamllint enable
163 | if: env.GIT_DIFF
164 | - uses: codecov/codecov-action@v3
165 | with:
166 | file: ./coverage.txt
167 | if: env.GIT_DIFF
168 |
169 | test-race:
170 | runs-on: ubuntu-latest
171 | needs: split-test-files
172 | strategy:
173 | fail-fast: false
174 | matrix:
175 | part: ["00", "01", "02", "03"]
176 | steps:
177 | - uses: actions/checkout@v3
178 | - uses: actions/setup-go@v3
179 | with:
180 | go-version: 1.19
181 | - uses: technote-space/get-diff-action@v6.1.2
182 | with:
183 | PATTERNS: |
184 | **/**.go
185 | go.mod
186 | go.sum
187 | - uses: actions/download-artifact@v3
188 | with:
189 | name: "${{ github.sha }}-${{ matrix.part }}"
190 | if: env.GIT_DIFF
191 | - name: test & coverage report creation
192 | run: >
193 | cat pkgs.txt.part.${{ matrix.part }} |
194 | xargs go test -mod=readonly -json -timeout 30m
195 | -race -test.short -tags='cgo' > ${{ matrix.part }}-race-output.txt
196 | if: env.GIT_DIFF
197 | - uses: actions/upload-artifact@v3
198 | with:
199 | name: "${{ github.sha }}-${{ matrix.part }}-race-output"
200 | path: ./${{ matrix.part }}-race-output.txt
201 |
202 | race-detector-report:
203 | runs-on: ubuntu-latest
204 | needs: [test-race, install-tparse]
205 | timeout-minutes: 5
206 | steps:
207 | - uses: actions/checkout@v3
208 | - uses: technote-space/get-diff-action@v6.1.2
209 | id: git_diff
210 | with:
211 | PATTERNS: |
212 | **/**.go
213 | go.mod
214 | go.sum
215 | - uses: actions/download-artifact@v3
216 | with:
217 | name: "${{ github.sha }}-00-race-output"
218 | if: env.GIT_DIFF
219 | - uses: actions/download-artifact@v3
220 | with:
221 | name: "${{ github.sha }}-01-race-output"
222 | if: env.GIT_DIFF
223 | - uses: actions/download-artifact@v3
224 | with:
225 | name: "${{ github.sha }}-02-race-output"
226 | if: env.GIT_DIFF
227 | - uses: actions/download-artifact@v3
228 | with:
229 | name: "${{ github.sha }}-03-race-output"
230 | if: env.GIT_DIFF
231 | - uses: actions/cache@v3.2.2
232 | with:
233 | path: ~/go/bin
234 | key: ${{ runner.os }}-go-tparse-binary
235 | if: env.GIT_DIFF
236 | - name: Generate test report (go test -race)
237 | run: cat ./*-race-output.txt | ~/go/bin/tparse
238 | if: env.GIT_DIFF
239 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/histolabs/metro
2 |
3 | go 1.19
4 |
5 | require (
6 | github.com/ethereum/go-ethereum v1.10.26
7 | github.com/gogo/protobuf v1.3.3 // indirect
8 | github.com/golang/protobuf v1.5.2 // indirect
9 | github.com/google/uuid v1.3.0 // indirect
10 | github.com/gorilla/mux v1.8.0 // indirect
11 | github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
12 | github.com/pkg/errors v0.9.1 // indirect
13 | github.com/spf13/cast v1.5.0
14 | github.com/spf13/cobra v1.6.1
15 | github.com/stretchr/testify v1.8.1
16 | github.com/tendermint/tm-db v0.6.7
17 | golang.org/x/crypto v0.4.0 // indirect
18 | golang.org/x/net v0.4.0 // indirect
19 | golang.org/x/sys v0.3.0 // indirect
20 | golang.org/x/term v0.3.0 // indirect
21 | google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 // indirect
22 | google.golang.org/grpc v1.51.0
23 | )
24 |
25 | require (
26 | cosmossdk.io/math v1.0.0-beta.4
27 | github.com/cosmos/cosmos-sdk v0.46.6
28 | github.com/tendermint/tendermint v0.34.23
29 | )
30 |
31 | require (
32 | cloud.google.com/go v0.105.0 // indirect
33 | cloud.google.com/go/compute v1.12.1 // indirect
34 | cloud.google.com/go/compute/metadata v0.2.1 // indirect
35 | cloud.google.com/go/iam v0.7.0 // indirect
36 | cloud.google.com/go/storage v1.27.0 // indirect
37 | cosmossdk.io/errors v1.0.0-beta.7 // indirect
38 | filippo.io/edwards25519 v1.0.0-rc.1 // indirect
39 | github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
40 | github.com/99designs/keyring v1.2.1 // indirect
41 | github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect
42 | github.com/Workiva/go-datastructures v1.0.53 // indirect
43 | github.com/armon/go-metrics v0.4.1 // indirect
44 | github.com/aws/aws-sdk-go v1.40.45 // indirect
45 | github.com/beorn7/perks v1.0.1 // indirect
46 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
47 | github.com/bgentry/speakeasy v0.1.0 // indirect
48 | github.com/btcsuite/btcd v0.22.1 // indirect
49 | github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
50 | github.com/celestiaorg/nmt v0.12.0 // indirect
51 | github.com/cenkalti/backoff/v4 v4.1.3 // indirect
52 | github.com/cespare/xxhash v1.1.0 // indirect
53 | github.com/cespare/xxhash/v2 v2.1.2 // indirect
54 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
55 | github.com/cockroachdb/apd/v2 v2.0.2 // indirect
56 | github.com/coinbase/rosetta-sdk-go v0.7.9 // indirect
57 | github.com/confio/ics23/go v0.9.0 // indirect
58 | github.com/cosmos/btcutil v1.0.5 // indirect
59 | github.com/cosmos/cosmos-proto v1.0.0-beta.1 // indirect
60 | github.com/cosmos/go-bip39 v1.0.0 // indirect
61 | github.com/cosmos/gogoproto v1.4.3 // indirect
62 | github.com/cosmos/gorocksdb v1.2.0 // indirect
63 | github.com/cosmos/iavl v0.19.4 // indirect
64 | github.com/cosmos/ledger-cosmos-go v0.12.1 // indirect
65 | github.com/creachadair/taskgroup v0.3.2 // indirect
66 | github.com/danieljoos/wincred v1.1.2 // indirect
67 | github.com/davecgh/go-spew v1.1.1 // indirect
68 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
69 | github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
70 | github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
71 | github.com/dgraph-io/ristretto v0.1.1 // indirect
72 | github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
73 | github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac // indirect
74 | github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
75 | github.com/felixge/httpsnoop v1.0.2 // indirect
76 | github.com/fsnotify/fsnotify v1.6.0 // indirect
77 | github.com/gin-gonic/gin v1.7.0 // indirect
78 | github.com/go-kit/kit v0.12.0 // indirect
79 | github.com/go-kit/log v0.2.1 // indirect
80 | github.com/go-logfmt/logfmt v0.5.1 // indirect
81 | github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
82 | github.com/gogo/gateway v1.1.0 // indirect
83 | github.com/golang/glog v1.0.0 // indirect
84 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
85 | github.com/golang/snappy v0.0.4 // indirect
86 | github.com/google/btree v1.1.2 // indirect
87 | github.com/google/go-cmp v0.5.9 // indirect
88 | github.com/google/orderedcode v0.0.1 // indirect
89 | github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
90 | github.com/googleapis/gax-go/v2 v2.6.0 // indirect
91 | github.com/gorilla/handlers v1.5.1 // indirect
92 | github.com/gorilla/websocket v1.5.0 // indirect
93 | github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
94 | github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
95 | github.com/gtank/merlin v0.1.1 // indirect
96 | github.com/gtank/ristretto255 v0.1.2 // indirect
97 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
98 | github.com/hashicorp/go-getter v1.6.2 // indirect
99 | github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
100 | github.com/hashicorp/go-safetemp v1.0.0 // indirect
101 | github.com/hashicorp/go-version v1.6.0 // indirect
102 | github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
103 | github.com/hashicorp/hcl v1.0.0 // indirect
104 | github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 // indirect
105 | github.com/improbable-eng/grpc-web v0.15.0 // indirect
106 | github.com/inconshreveable/mousetrap v1.0.1 // indirect
107 | github.com/jmespath/go-jmespath v0.4.0 // indirect
108 | github.com/jmhodges/levigo v1.0.0 // indirect
109 | github.com/klauspost/compress v1.15.12 // indirect
110 | github.com/lib/pq v1.10.7 // indirect
111 | github.com/libp2p/go-buffer-pool v0.1.0 // indirect
112 | github.com/magiconair/properties v1.8.7 // indirect
113 | github.com/manifoldco/promptui v0.9.0 // indirect
114 | github.com/mattn/go-colorable v0.1.13 // indirect
115 | github.com/mattn/go-isatty v0.0.16 // indirect
116 | github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
117 | github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect
118 | github.com/minio/highwayhash v1.0.2 // indirect
119 | github.com/mitchellh/go-homedir v1.1.0 // indirect
120 | github.com/mitchellh/go-testing-interface v1.0.0 // indirect
121 | github.com/mitchellh/mapstructure v1.5.0 // indirect
122 | github.com/mtibben/percent v0.2.1 // indirect
123 | github.com/nxadm/tail v1.4.8 // indirect
124 | github.com/pelletier/go-toml v1.9.5 // indirect
125 | github.com/pelletier/go-toml/v2 v2.0.5 // indirect
126 | github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
127 | github.com/pmezard/go-difflib v1.0.0 // indirect
128 | github.com/prometheus/client_golang v1.14.0 // indirect
129 | github.com/prometheus/client_model v0.3.0 // indirect
130 | github.com/prometheus/common v0.39.0 // indirect
131 | github.com/prometheus/procfs v0.8.0 // indirect
132 | github.com/rakyll/statik v0.1.7 // indirect
133 | github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
134 | github.com/regen-network/cosmos-proto v0.3.1 // indirect
135 | github.com/rs/cors v1.8.2 // indirect
136 | github.com/rs/zerolog v1.28.0 // indirect
137 | github.com/sasha-s/go-deadlock v0.3.1 // indirect
138 | github.com/spf13/afero v1.9.2 // indirect
139 | github.com/spf13/jwalterweatherman v1.1.0 // indirect
140 | github.com/spf13/pflag v1.0.5 // indirect
141 | github.com/spf13/viper v1.14.0 // indirect
142 | github.com/subosito/gotenv v1.4.1 // indirect
143 | github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
144 | github.com/tendermint/btcd v0.1.1 // indirect
145 | github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 // indirect
146 | github.com/tendermint/go-amino v0.16.0 // indirect
147 | github.com/ulikunitz/xz v0.5.8 // indirect
148 | github.com/zondax/hid v0.9.1 // indirect
149 | github.com/zondax/ledger-go v0.14.0 // indirect
150 | go.etcd.io/bbolt v1.3.6 // indirect
151 | go.opencensus.io v0.23.0 // indirect
152 | golang.org/x/exp v0.0.0-20221019170559-20944726eadf // indirect
153 | golang.org/x/oauth2 v0.3.0 // indirect
154 | golang.org/x/text v0.5.0 // indirect
155 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
156 | google.golang.org/api v0.102.0 // indirect
157 | google.golang.org/appengine v1.6.7 // indirect
158 | google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 // indirect
159 | gopkg.in/ini.v1 v1.67.0 // indirect
160 | gopkg.in/yaml.v2 v2.4.0 // indirect
161 | gopkg.in/yaml.v3 v3.0.1 // indirect
162 | nhooyr.io/websocket v1.8.6 // indirect
163 | sigs.k8s.io/yaml v1.3.0 // indirect
164 | )
165 |
166 | replace (
167 | github.com/cosmos/cosmos-sdk => github.com/histolabs/cosmos-sdk v0.0.0-20221230021044-779df3c9a0f5
168 | github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
169 | github.com/tendermint/tendermint => github.com/histolabs/tendermint v0.0.0-20221227204023-ec49dd7d580f
170 | )
171 |
--------------------------------------------------------------------------------
/third_party/proto/confio/proofs.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package ics23;
4 | option go_package = "github.com/confio/ics23/go";
5 |
6 | enum HashOp {
7 | // NO_HASH is the default if no data passed. Note this is an illegal argument some places.
8 | NO_HASH = 0;
9 | SHA256 = 1;
10 | SHA512 = 2;
11 | KECCAK = 3;
12 | RIPEMD160 = 4;
13 | BITCOIN = 5; // ripemd160(sha256(x))
14 | }
15 |
16 | /**
17 | LengthOp defines how to process the key and value of the LeafOp
18 | to include length information. After encoding the length with the given
19 | algorithm, the length will be prepended to the key and value bytes.
20 | (Each one with it's own encoded length)
21 | */
22 | enum LengthOp {
23 | // NO_PREFIX don't include any length info
24 | NO_PREFIX = 0;
25 | // VAR_PROTO uses protobuf (and go-amino) varint encoding of the length
26 | VAR_PROTO = 1;
27 | // VAR_RLP uses rlp int encoding of the length
28 | VAR_RLP = 2;
29 | // FIXED32_BIG uses big-endian encoding of the length as a 32 bit integer
30 | FIXED32_BIG = 3;
31 | // FIXED32_LITTLE uses little-endian encoding of the length as a 32 bit integer
32 | FIXED32_LITTLE = 4;
33 | // FIXED64_BIG uses big-endian encoding of the length as a 64 bit integer
34 | FIXED64_BIG = 5;
35 | // FIXED64_LITTLE uses little-endian encoding of the length as a 64 bit integer
36 | FIXED64_LITTLE = 6;
37 | // REQUIRE_32_BYTES is like NONE, but will fail if the input is not exactly 32 bytes (sha256 output)
38 | REQUIRE_32_BYTES = 7;
39 | // REQUIRE_64_BYTES is like NONE, but will fail if the input is not exactly 64 bytes (sha512 output)
40 | REQUIRE_64_BYTES = 8;
41 | }
42 |
43 | /**
44 | ExistenceProof takes a key and a value and a set of steps to perform on it.
45 | The result of peforming all these steps will provide a "root hash", which can
46 | be compared to the value in a header.
47 |
48 | Since it is computationally infeasible to produce a hash collision for any of the used
49 | cryptographic hash functions, if someone can provide a series of operations to transform
50 | a given key and value into a root hash that matches some trusted root, these key and values
51 | must be in the referenced merkle tree.
52 |
53 | The only possible issue is maliablity in LeafOp, such as providing extra prefix data,
54 | which should be controlled by a spec. Eg. with lengthOp as NONE,
55 | prefix = FOO, key = BAR, value = CHOICE
56 | and
57 | prefix = F, key = OOBAR, value = CHOICE
58 | would produce the same value.
59 |
60 | With LengthOp this is tricker but not impossible. Which is why the "leafPrefixEqual" field
61 | in the ProofSpec is valuable to prevent this mutability. And why all trees should
62 | length-prefix the data before hashing it.
63 | */
64 | message ExistenceProof {
65 | bytes key = 1;
66 | bytes value = 2;
67 | LeafOp leaf = 3;
68 | repeated InnerOp path = 4;
69 | }
70 |
71 | /*
72 | NonExistenceProof takes a proof of two neighbors, one left of the desired key,
73 | one right of the desired key. If both proofs are valid AND they are neighbors,
74 | then there is no valid proof for the given key.
75 | */
76 | message NonExistenceProof {
77 | bytes key = 1; // TODO: remove this as unnecessary??? we prove a range
78 | ExistenceProof left = 2;
79 | ExistenceProof right = 3;
80 | }
81 |
82 | /*
83 | CommitmentProof is either an ExistenceProof or a NonExistenceProof, or a Batch of such messages
84 | */
85 | message CommitmentProof {
86 | oneof proof {
87 | ExistenceProof exist = 1;
88 | NonExistenceProof nonexist = 2;
89 | BatchProof batch = 3;
90 | CompressedBatchProof compressed = 4;
91 | }
92 | }
93 |
94 | /**
95 | LeafOp represents the raw key-value data we wish to prove, and
96 | must be flexible to represent the internal transformation from
97 | the original key-value pairs into the basis hash, for many existing
98 | merkle trees.
99 |
100 | key and value are passed in. So that the signature of this operation is:
101 | leafOp(key, value) -> output
102 |
103 | To process this, first prehash the keys and values if needed (ANY means no hash in this case):
104 | hkey = prehashKey(key)
105 | hvalue = prehashValue(value)
106 |
107 | Then combine the bytes, and hash it
108 | output = hash(prefix || length(hkey) || hkey || length(hvalue) || hvalue)
109 | */
110 | message LeafOp {
111 | HashOp hash = 1;
112 | HashOp prehash_key = 2;
113 | HashOp prehash_value = 3;
114 | LengthOp length = 4;
115 | // prefix is a fixed bytes that may optionally be included at the beginning to differentiate
116 | // a leaf node from an inner node.
117 | bytes prefix = 5;
118 | }
119 |
120 | /**
121 | InnerOp represents a merkle-proof step that is not a leaf.
122 | It represents concatenating two children and hashing them to provide the next result.
123 |
124 | The result of the previous step is passed in, so the signature of this op is:
125 | innerOp(child) -> output
126 |
127 | The result of applying InnerOp should be:
128 | output = op.hash(op.prefix || child || op.suffix)
129 |
130 | where the || operator is concatenation of binary data,
131 | and child is the result of hashing all the tree below this step.
132 |
133 | Any special data, like prepending child with the length, or prepending the entire operation with
134 | some value to differentiate from leaf nodes, should be included in prefix and suffix.
135 | If either of prefix or suffix is empty, we just treat it as an empty string
136 | */
137 | message InnerOp {
138 | HashOp hash = 1;
139 | bytes prefix = 2;
140 | bytes suffix = 3;
141 | }
142 |
143 |
144 | /**
145 | ProofSpec defines what the expected parameters are for a given proof type.
146 | This can be stored in the client and used to validate any incoming proofs.
147 |
148 | verify(ProofSpec, Proof) -> Proof | Error
149 |
150 | As demonstrated in tests, if we don't fix the algorithm used to calculate the
151 | LeafHash for a given tree, there are many possible key-value pairs that can
152 | generate a given hash (by interpretting the preimage differently).
153 | We need this for proper security, requires client knows a priori what
154 | tree format server uses. But not in code, rather a configuration object.
155 | */
156 | message ProofSpec {
157 | // any field in the ExistenceProof must be the same as in this spec.
158 | // except Prefix, which is just the first bytes of prefix (spec can be longer)
159 | LeafOp leaf_spec = 1;
160 | InnerSpec inner_spec = 2;
161 | // max_depth (if > 0) is the maximum number of InnerOps allowed (mainly for fixed-depth tries)
162 | int32 max_depth = 3;
163 | // min_depth (if > 0) is the minimum number of InnerOps allowed (mainly for fixed-depth tries)
164 | int32 min_depth = 4;
165 | }
166 |
167 | /*
168 | InnerSpec contains all store-specific structure info to determine if two proofs from a
169 | given store are neighbors.
170 |
171 | This enables:
172 |
173 | isLeftMost(spec: InnerSpec, op: InnerOp)
174 | isRightMost(spec: InnerSpec, op: InnerOp)
175 | isLeftNeighbor(spec: InnerSpec, left: InnerOp, right: InnerOp)
176 | */
177 | message InnerSpec {
178 | // Child order is the ordering of the children node, must count from 0
179 | // iavl tree is [0, 1] (left then right)
180 | // merk is [0, 2, 1] (left, right, here)
181 | repeated int32 child_order = 1;
182 | int32 child_size = 2;
183 | int32 min_prefix_length = 3;
184 | int32 max_prefix_length = 4;
185 | // empty child is the prehash image that is used when one child is nil (eg. 20 bytes of 0)
186 | bytes empty_child = 5;
187 | // hash is the algorithm that must be used for each InnerOp
188 | HashOp hash = 6;
189 | }
190 |
191 | /*
192 | BatchProof is a group of multiple proof types than can be compressed
193 | */
194 | message BatchProof {
195 | repeated BatchEntry entries = 1;
196 | }
197 |
198 | // Use BatchEntry not CommitmentProof, to avoid recursion
199 | message BatchEntry {
200 | oneof proof {
201 | ExistenceProof exist = 1;
202 | NonExistenceProof nonexist = 2;
203 | }
204 | }
205 |
206 |
207 | /****** all items here are compressed forms *******/
208 |
209 | message CompressedBatchProof {
210 | repeated CompressedBatchEntry entries = 1;
211 | repeated InnerOp lookup_inners = 2;
212 | }
213 |
214 | // Use BatchEntry not CommitmentProof, to avoid recursion
215 | message CompressedBatchEntry {
216 | oneof proof {
217 | CompressedExistenceProof exist = 1;
218 | CompressedNonExistenceProof nonexist = 2;
219 | }
220 | }
221 |
222 | message CompressedExistenceProof {
223 | bytes key = 1;
224 | bytes value = 2;
225 | LeafOp leaf = 3;
226 | // these are indexes into the lookup_inners table in CompressedBatchProof
227 | repeated int32 path = 4;
228 | }
229 |
230 | message CompressedNonExistenceProof {
231 | bytes key = 1; // TODO: remove this as unnecessary??? we prove a range
232 | CompressedExistenceProof left = 2;
233 | CompressedExistenceProof right = 3;
234 | }
235 |
--------------------------------------------------------------------------------
/pkg/builder/builder.go:
--------------------------------------------------------------------------------
1 | package builder
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "strings"
7 | "sync"
8 |
9 | "github.com/cosmos/cosmos-sdk/client"
10 | sdkclient "github.com/cosmos/cosmos-sdk/client"
11 | "github.com/cosmos/cosmos-sdk/crypto/keyring"
12 | sdktypes "github.com/cosmos/cosmos-sdk/types"
13 | "github.com/cosmos/cosmos-sdk/types/tx"
14 | "github.com/cosmos/cosmos-sdk/types/tx/signing"
15 | authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
16 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
17 | "github.com/histolabs/metro/app/encoding"
18 | "github.com/histolabs/metro/pkg/consts"
19 | "google.golang.org/grpc"
20 | )
21 |
22 | // KeyringSigner uses a keyring to sign and build celestia-app transactions
23 | type KeyringSigner struct {
24 | keyring.Keyring
25 | keyringAccName string
26 |
27 | chainID string
28 | secondaryChainID string
29 | encCfg encoding.Config
30 |
31 | sync.RWMutex
32 | acc authtypes.AccountI
33 | }
34 |
35 | // NewKeyringSigner returns a new KeyringSigner using the provided keyring
36 | func NewKeyringSigner(encCfg encoding.Config, ring keyring.Keyring, name string, chainID string) *KeyringSigner {
37 | ids := strings.SplitN(chainID, consts.ChainIDSeparator, 2)
38 | secondaryChainID := ""
39 | if len(ids) > 1 {
40 | secondaryChainID = ids[1]
41 | }
42 |
43 | return &KeyringSigner{
44 | Keyring: ring,
45 | keyringAccName: name,
46 | chainID: chainID,
47 | secondaryChainID: secondaryChainID,
48 | encCfg: encCfg,
49 | }
50 | }
51 |
52 | // Update queries the application to find the latest account number and
53 | // sequence, updating the respective internal fields. The internal account
54 | // number must be set by this method or by manually calling k.SetAccountNumber
55 | // in order for any built transactions to be valid
56 | func (k *KeyringSigner) UpdateAccount(ctx context.Context, conn *grpc.ClientConn) error {
57 | info, err := k.Key(k.keyringAccName)
58 | if err != nil {
59 | return err
60 | }
61 |
62 | addr, err := info.GetAddress()
63 | if err != nil {
64 | return err
65 | }
66 |
67 | acc, err := QueryAccount(ctx, conn, k.encCfg, addr.String())
68 | if err != nil {
69 | return err
70 | }
71 | k.Lock()
72 | defer k.Unlock()
73 |
74 | k.acc = acc
75 | return nil
76 | }
77 |
78 | func (k *KeyringSigner) UpdateAccountFromClient(clientCtx client.Context) error {
79 | rec := k.GetSignerInfo()
80 |
81 | addr, err := rec.GetAddress()
82 | if err != nil {
83 | return err
84 | }
85 |
86 | accNum, seq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, addr)
87 | if err != nil {
88 | return err
89 | }
90 |
91 | k.SetAccountNumber(accNum)
92 | k.SetSequence(seq)
93 |
94 | return nil
95 | }
96 |
97 | // NewTxBuilder returns the default sdk Tx builder using the celestia-app encoding config
98 | func (k *KeyringSigner) NewTxBuilder(opts ...TxBuilderOption) sdkclient.TxBuilder {
99 | builder := k.encCfg.TxConfig.NewTxBuilder()
100 | for _, opt := range opts {
101 | builder = opt(builder)
102 | }
103 | return builder
104 | }
105 |
106 | // BuildSignedTx creates and signs a sdk.Tx that contains the provided message. The interal
107 | // account number must be set by calling k.QueryAccountNumber or by manually setting it via
108 | // k.SetAccountNumber for the built transactions to be valid.
109 | func (k *KeyringSigner) BuildSignedTx(builder sdkclient.TxBuilder, isSecondary bool, msg ...sdktypes.Msg) (authsigning.Tx, error) {
110 | k.RLock()
111 | sequence := k.acc.GetSequence()
112 | if isSecondary {
113 | sequence = k.acc.GetSecondarySequence(k.secondaryChainID)
114 | builder.SetSecondaryChainID(k.secondaryChainID)
115 | }
116 | k.RUnlock()
117 |
118 | // set the msg
119 | err := builder.SetMsgs(msg...)
120 | if err != nil {
121 | return nil, err
122 | }
123 |
124 | // lookup account info
125 | keyInfo, err := k.Key(k.keyringAccName)
126 | if err != nil {
127 | return nil, err
128 | }
129 |
130 | pub, err := keyInfo.GetPubKey()
131 | if err != nil {
132 | return nil, err
133 | }
134 |
135 | // we must first set an empty signature in order generate
136 | // the correct sign bytes
137 | sigV2 := signing.SignatureV2{
138 | PubKey: pub,
139 | Data: &signing.SingleSignatureData{
140 | SignMode: signing.SignMode_SIGN_MODE_DIRECT,
141 | Signature: nil,
142 | },
143 | Sequence: sequence,
144 | }
145 |
146 | // set the empty signature
147 | err = builder.SetSignatures(sigV2)
148 | if err != nil {
149 | return nil, err
150 | }
151 |
152 | signerData, err := k.GetSignerData(isSecondary)
153 | if err != nil {
154 | return nil, err
155 | }
156 |
157 | // Generate the bytes to be signed.
158 | bytesToSign, err := k.encCfg.TxConfig.SignModeHandler().GetSignBytes(
159 | signing.SignMode_SIGN_MODE_DIRECT,
160 | signerData,
161 | builder.GetTx(),
162 | )
163 | if err != nil {
164 | return nil, err
165 | }
166 |
167 | addr, err := keyInfo.GetAddress()
168 | if err != nil {
169 | return nil, err
170 | }
171 |
172 | // Sign those bytes using the keyring. we are ignoring the returned public key
173 | sigBytes, _, err := k.SignByAddress(addr, bytesToSign)
174 | if err != nil {
175 | return nil, err
176 | }
177 |
178 | // Construct the SignatureV2 struct, this time including a real signature
179 | sigV2 = signing.SignatureV2{
180 | PubKey: pub,
181 | Data: &signing.SingleSignatureData{
182 | SignMode: signing.SignMode_SIGN_MODE_DIRECT,
183 | Signature: sigBytes,
184 | },
185 | Sequence: sequence,
186 | }
187 |
188 | // set the final signature
189 | err = builder.SetSignatures(sigV2)
190 | if err != nil {
191 | return nil, err
192 | }
193 |
194 | // return the signed transaction
195 | return builder.GetTx(), nil
196 | }
197 |
198 | // SetAccountNumber manually sets the underlying account number
199 | func (k *KeyringSigner) SetAccountNumber(n uint64) error {
200 | k.Lock()
201 | defer k.Unlock()
202 |
203 | return k.acc.SetAccountNumber(n)
204 | }
205 |
206 | // SetSequence manually sets the underlying sequence number
207 | func (k *KeyringSigner) SetSequence(n uint64) error {
208 | k.Lock()
209 | defer k.Unlock()
210 |
211 | return k.acc.SetSequence(n)
212 | }
213 |
214 | // SetSecondarySequence manually sets the underlying secondary sequence number
215 | func (k *KeyringSigner) SetSecondarySequence(id string, n uint64) error {
216 | k.Lock()
217 | defer k.Unlock()
218 |
219 | return k.acc.SetSecondarySequence(id, n)
220 | }
221 |
222 | // SetKeyringAccName manually sets the underlying keyring account name
223 | func (k *KeyringSigner) SetKeyringAccName(name string) {
224 | k.keyringAccName = name
225 | }
226 |
227 | // GetSignerInfo returns the signer info for the KeyringSigner's account. panics
228 | // if the account in KeyringSigner does not exist.
229 | func (k *KeyringSigner) GetSignerInfo() *keyring.Record {
230 | info, err := k.Key(k.keyringAccName)
231 | if err != nil {
232 | panic(err)
233 | }
234 | return info
235 | }
236 |
237 | func (k *KeyringSigner) GetSignerData(isSecondary bool) (authsigning.SignerData, error) {
238 | k.RLock()
239 | accountNumber := k.acc.GetAccountNumber()
240 | sequence := k.acc.GetSequence()
241 | if isSecondary {
242 | if k.secondaryChainID == "" {
243 | k.RUnlock()
244 | return authsigning.SignerData{}, errors.New("no secondary chain-id set for secondary tx")
245 | }
246 | accountNumber = 0
247 | sequence = k.acc.GetSecondarySequence(k.secondaryChainID)
248 | }
249 | k.RUnlock()
250 |
251 | record, err := k.Key(k.keyringAccName)
252 | if err != nil {
253 | return authsigning.SignerData{}, err
254 | }
255 |
256 | pubKey, err := record.GetPubKey()
257 | if err != nil {
258 | return authsigning.SignerData{}, err
259 | }
260 |
261 | address := pubKey.Address()
262 |
263 | return authsigning.SignerData{
264 | Address: address.String(),
265 | ChainID: k.chainID,
266 | AccountNumber: accountNumber,
267 | Sequence: sequence,
268 | PubKey: pubKey,
269 | }, nil
270 | }
271 |
272 | // EncodeTx uses the keyring signer's encoding config to encode the provided sdk transaction
273 | func (k *KeyringSigner) EncodeTx(tx sdktypes.Tx) ([]byte, error) {
274 | return k.encCfg.TxConfig.TxEncoder()(tx)
275 | }
276 |
277 | // BroadcastTx uses the provided grpc connection to broadcast a signed and encoded transaction
278 | func BroadcastTx(ctx context.Context, conn *grpc.ClientConn, mode tx.BroadcastMode, txBytes []byte) (*tx.BroadcastTxResponse, error) {
279 | txClient := tx.NewServiceClient(conn)
280 |
281 | return txClient.BroadcastTx(
282 | ctx,
283 | &tx.BroadcastTxRequest{
284 | Mode: mode,
285 | TxBytes: txBytes,
286 | },
287 | )
288 | }
289 |
290 | // QueryAccount fetches the account number and sequence number from the celestia-app node.
291 | func QueryAccount(ctx context.Context, conn *grpc.ClientConn, encCfg encoding.Config, address string) (authtypes.AccountI, error) {
292 | qclient := authtypes.NewQueryClient(conn)
293 | resp, err := qclient.Account(
294 | ctx,
295 | &authtypes.QueryAccountRequest{Address: address},
296 | )
297 | if err != nil {
298 | return nil, err
299 | }
300 |
301 | var acc authtypes.AccountI
302 | err = encCfg.InterfaceRegistry.UnpackAny(resp.Account, &acc)
303 | if err != nil {
304 | return nil, err
305 | }
306 |
307 | return acc, nil
308 | }
309 |
--------------------------------------------------------------------------------
/cmd/metro/cmd/root.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "os"
7 | "time"
8 |
9 | "github.com/cosmos/cosmos-sdk/simapp/simd/cmd"
10 | "github.com/cosmos/cosmos-sdk/x/crisis"
11 | "github.com/histolabs/metro/app"
12 | "github.com/histolabs/metro/app/encoding"
13 | "github.com/histolabs/metro/pkg/consts"
14 |
15 | "github.com/cosmos/cosmos-sdk/baseapp"
16 | "github.com/cosmos/cosmos-sdk/client"
17 | "github.com/cosmos/cosmos-sdk/client/config"
18 | "github.com/cosmos/cosmos-sdk/client/debug"
19 | "github.com/cosmos/cosmos-sdk/client/flags"
20 | "github.com/cosmos/cosmos-sdk/client/keys"
21 | "github.com/cosmos/cosmos-sdk/client/rpc"
22 | "github.com/cosmos/cosmos-sdk/codec"
23 | "github.com/cosmos/cosmos-sdk/server"
24 | serverconfig "github.com/cosmos/cosmos-sdk/server/config"
25 | servertypes "github.com/cosmos/cosmos-sdk/server/types"
26 | "github.com/cosmos/cosmos-sdk/store"
27 | sdk "github.com/cosmos/cosmos-sdk/types"
28 | authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
29 | "github.com/cosmos/cosmos-sdk/x/auth/types"
30 | banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
31 | genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
32 | "github.com/spf13/cast"
33 | "github.com/spf13/cobra"
34 | tmcmds "github.com/tendermint/tendermint/cmd/tendermint/commands"
35 | tmcfg "github.com/tendermint/tendermint/config"
36 | tmcli "github.com/tendermint/tendermint/libs/cli"
37 | "github.com/tendermint/tendermint/libs/log"
38 | dbm "github.com/tendermint/tm-db"
39 | )
40 |
41 | const EnvPrefix = "CELESTIA"
42 |
43 | // NewRootCmd creates a new root command for metro. It is called once in the
44 | // main function.
45 | func NewRootCmd() *cobra.Command {
46 | encodingConfig := encoding.MakeConfig(app.ModuleEncodingRegisters...)
47 |
48 | cfg := sdk.GetConfig()
49 | cfg.SetBech32PrefixForAccount(app.Bech32PrefixAccAddr, app.Bech32PrefixAccPub)
50 | cfg.SetBech32PrefixForValidator(app.Bech32PrefixValAddr, app.Bech32PrefixValPub)
51 | cfg.SetBech32PrefixForConsensusNode(app.Bech32PrefixConsAddr, app.Bech32PrefixConsPub)
52 | cfg.Seal()
53 |
54 | initClientCtx := client.Context{}.
55 | WithCodec(encodingConfig.Codec).
56 | WithInterfaceRegistry(encodingConfig.InterfaceRegistry).
57 | WithTxConfig(encodingConfig.TxConfig).
58 | WithLegacyAmino(encodingConfig.Amino).
59 | WithInput(os.Stdin).
60 | WithAccountRetriever(types.AccountRetriever{}).
61 | WithBroadcastMode(flags.BroadcastBlock).
62 | WithHomeDir(app.DefaultNodeHome).
63 | WithViper(EnvPrefix)
64 |
65 | rootCmd := &cobra.Command{
66 | Use: "metro",
67 | Short: "Start metro app",
68 | PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
69 | initClientCtx, err := client.ReadPersistentCommandFlags(initClientCtx, cmd.Flags())
70 | if err != nil {
71 | return err
72 | }
73 | initClientCtx, err = config.ReadFromClientConfig(initClientCtx)
74 | if err != nil {
75 | return err
76 | }
77 |
78 | if err := client.SetCmdClientContextHandler(initClientCtx, cmd); err != nil {
79 | return err
80 | }
81 |
82 | // Override the default tendermint config for metro
83 | tmCfg := tmcfg.DefaultConfig()
84 |
85 | // Set broadcast timeout to be 50 seconds in order to avoid timeouts for long block times
86 | tmCfg.RPC.TimeoutBroadcastTxCommit = 50 * time.Second
87 | tmCfg.RPC.MaxBodyBytes = int64(8388608) // 8 MiB
88 | tmCfg.Mempool.TTLNumBlocks = 10
89 | tmCfg.Mempool.MaxTxBytes = 2 * 1024 * 1024 // 2 MiB
90 | tmCfg.Mempool.Version = "v1" // prioritized mempool
91 | tmCfg.Consensus.TimeoutPropose = time.Second * 10
92 | tmCfg.Consensus.TimeoutCommit = time.Second * 8
93 | tmCfg.Consensus.SkipTimeoutCommit = false
94 |
95 | customAppTemplate, customAppConfig := initAppConfig()
96 | return server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig, tmCfg)
97 | },
98 | SilenceUsage: true,
99 | }
100 |
101 | initRootCmd(rootCmd, encodingConfig)
102 |
103 | return rootCmd
104 | }
105 |
106 | // initAppConfig helps to override default appConfig template and configs.
107 | // return "", nil if no custom configuration is required for the application.
108 | func initAppConfig() (string, interface{}) {
109 | type CustomAppConfig struct {
110 | serverconfig.Config
111 | }
112 |
113 | // Optionally allow the chain developer to overwrite the SDK's default
114 | // server config.
115 | srvCfg := serverconfig.DefaultConfig()
116 | srvCfg.API.Enable = true
117 |
118 | // the default snapshot interval was determined by picking a large enough
119 | // value as to not dramatically increase resource requirements while also
120 | // being greater than zero so that there are more nodes that will serve
121 | // snapshots to nodes that state sync
122 | srvCfg.StateSync.SnapshotInterval = 1500
123 | srvCfg.StateSync.SnapshotKeepRecent = 2
124 | srvCfg.MinGasPrices = fmt.Sprintf("0.001%s", consts.BondDenom)
125 |
126 | CelestiaAppCfg := CustomAppConfig{Config: *srvCfg}
127 |
128 | CelestiaAppTemplate := serverconfig.DefaultConfigTemplate
129 |
130 | return CelestiaAppTemplate, CelestiaAppCfg
131 | }
132 |
133 | func initRootCmd(rootCmd *cobra.Command, encodingConfig encoding.Config) {
134 | cfg := sdk.GetConfig()
135 | cfg.Seal()
136 |
137 | debugCmd := debug.Cmd()
138 |
139 | rootCmd.AddCommand(
140 | genutilcli.InitCmd(app.ModuleBasics, app.DefaultNodeHome),
141 | genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, app.DefaultNodeHome),
142 | genutilcli.MigrateGenesisCmd(),
143 | cmd.AddGenesisAccountCmd(app.DefaultNodeHome),
144 | genutilcli.GenTxCmd(app.ModuleBasics, encodingConfig.TxConfig, banktypes.GenesisBalancesIterator{}, app.DefaultNodeHome),
145 | genutilcli.ValidateGenesisCmd(app.ModuleBasics),
146 | tmcli.NewCompletionCmd(rootCmd, true),
147 | tmcmds.RollbackStateCmd,
148 | debugCmd,
149 | config.Cmd(),
150 | )
151 |
152 | server.AddCommands(rootCmd, app.DefaultNodeHome, NewAppServer, createAppAndExport, addModuleInitFlags)
153 |
154 | // set the default keyring backend to `file`
155 | keybase := keys.Commands(app.DefaultNodeHome)
156 | keybase.Flag(flags.FlagKeyringBackend).DefValue = "file"
157 |
158 | // add keybase, auxiliary RPC, query, and tx child commands
159 | rootCmd.AddCommand(
160 | rpc.StatusCommand(),
161 | queryCommand(),
162 | txCommand(),
163 | keybase,
164 | )
165 | }
166 |
167 | func addModuleInitFlags(startCmd *cobra.Command) {
168 | crisis.AddModuleInitFlags(startCmd)
169 | }
170 |
171 | func queryCommand() *cobra.Command {
172 | cmd := &cobra.Command{
173 | Use: "query",
174 | Aliases: []string{"q"},
175 | Short: "Querying subcommands",
176 | DisableFlagParsing: true,
177 | SuggestionsMinimumDistance: 2,
178 | RunE: client.ValidateCmd,
179 | }
180 |
181 | cmd.AddCommand(
182 | authcmd.GetAccountCmd(),
183 | rpc.ValidatorCommand(),
184 | rpc.BlockCommand(),
185 | authcmd.QueryTxsByEventsCmd(),
186 | authcmd.QueryTxCmd(),
187 | )
188 |
189 | app.ModuleBasics.AddQueryCommands(cmd)
190 | cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID")
191 |
192 | return cmd
193 | }
194 |
195 | func txCommand() *cobra.Command {
196 | cmd := &cobra.Command{
197 | Use: "tx",
198 | Short: "Transactions subcommands",
199 | DisableFlagParsing: true,
200 | SuggestionsMinimumDistance: 2,
201 | RunE: client.ValidateCmd,
202 | }
203 |
204 | cmd.AddCommand(
205 | authcmd.GetSignCommand(),
206 | authcmd.GetSignBatchCommand(),
207 | authcmd.GetMultiSignCommand(),
208 | authcmd.GetValidateSignaturesCommand(),
209 | flags.LineBreak,
210 | authcmd.GetBroadcastCommand(),
211 | authcmd.GetEncodeCommand(),
212 | authcmd.GetDecodeCommand(),
213 | )
214 |
215 | app.ModuleBasics.AddTxCommands(cmd)
216 | cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID")
217 |
218 | return cmd
219 | }
220 |
221 | func NewAppServer(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts servertypes.AppOptions) servertypes.Application {
222 | var cache sdk.MultiStorePersistentCache
223 |
224 | if cast.ToBool(appOpts.Get(server.FlagInterBlockCache)) {
225 | cache = store.NewCommitKVStoreCacheManager()
226 | }
227 |
228 | skipUpgradeHeights := make(map[int64]bool)
229 | for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) {
230 | skipUpgradeHeights[int64(h)] = true
231 | }
232 |
233 | pruningOpts, err := server.GetPruningOptionsFromFlags(appOpts)
234 | if err != nil {
235 | panic(err)
236 | }
237 |
238 | return app.New(
239 | logger, db, traceStore, true, skipUpgradeHeights,
240 | cast.ToString(appOpts.Get(flags.FlagHome)),
241 | cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)),
242 | encoding.MakeConfig(app.ModuleEncodingRegisters...), // Ideally, we would reuse the one created by NewRootCmd.
243 | appOpts,
244 | baseapp.SetPruning(pruningOpts),
245 | baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(server.FlagMinGasPrices))),
246 | baseapp.SetMinRetainBlocks(cast.ToUint64(appOpts.Get(server.FlagMinRetainBlocks))),
247 | baseapp.SetHaltHeight(cast.ToUint64(appOpts.Get(server.FlagHaltHeight))),
248 | baseapp.SetHaltTime(cast.ToUint64(appOpts.Get(server.FlagHaltTime))),
249 | baseapp.SetMinRetainBlocks(cast.ToUint64(appOpts.Get(server.FlagMinRetainBlocks))),
250 | baseapp.SetInterBlockCache(cache),
251 | baseapp.SetTrace(cast.ToBool(appOpts.Get(server.FlagTrace))),
252 | baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents))),
253 | )
254 | }
255 |
256 | func createAppAndExport(
257 | logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailWhiteList []string,
258 | appOpts servertypes.AppOptions,
259 | ) (servertypes.ExportedApp, error) {
260 | encCfg := encoding.MakeConfig(app.ModuleEncodingRegisters...) // Ideally, we would reuse the one created by NewRootCmd.
261 | encCfg.Codec = codec.NewProtoCodec(encCfg.InterfaceRegistry)
262 | var capp *app.App
263 | if height != -1 {
264 | capp = app.New(logger, db, traceStore, false, map[int64]bool{}, "", uint(1), encCfg, appOpts)
265 |
266 | if err := capp.LoadHeight(height); err != nil {
267 | return servertypes.ExportedApp{}, err
268 | }
269 | } else {
270 | capp = app.New(logger, db, traceStore, true, map[int64]bool{}, "", uint(1), encCfg, appOpts)
271 | }
272 |
273 | return capp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList)
274 | }
275 |
--------------------------------------------------------------------------------
/testutil/test_app.go:
--------------------------------------------------------------------------------
1 | package testutil
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "time"
7 |
8 | "github.com/cosmos/cosmos-sdk/client/flags"
9 | "github.com/cosmos/cosmos-sdk/codec"
10 | codectypes "github.com/cosmos/cosmos-sdk/codec/types"
11 | cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
12 | "github.com/cosmos/cosmos-sdk/crypto/keyring"
13 | "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
14 | "github.com/cosmos/cosmos-sdk/server"
15 | "github.com/cosmos/cosmos-sdk/simapp"
16 | "github.com/cosmos/cosmos-sdk/testutil/mock"
17 | sdk "github.com/cosmos/cosmos-sdk/types"
18 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
19 | banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
20 | "github.com/histolabs/metro/app"
21 | "github.com/histolabs/metro/app/encoding"
22 | "github.com/histolabs/metro/pkg/consts"
23 | "github.com/histolabs/metro/testutil/testfactory"
24 | "github.com/spf13/cast"
25 | abci "github.com/tendermint/tendermint/abci/types"
26 | "github.com/tendermint/tendermint/libs/log"
27 | tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
28 | tmtypes "github.com/tendermint/tendermint/types"
29 | dbm "github.com/tendermint/tm-db"
30 |
31 | stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
32 | )
33 |
34 | const (
35 | ChainID = "testapp"
36 | )
37 |
38 | // Get flags every time the simulator is run
39 | func init() {
40 | simapp.GetSimulatorFlags()
41 | }
42 |
43 | // DefaultConsensusParams defines the default Tendermint consensus params used in
44 | // SimApp testing.
45 | var DefaultConsensusParams = &abci.ConsensusParams{
46 | Block: &abci.BlockParams{
47 | MaxBytes: 200000,
48 | MaxGas: 2000000,
49 | },
50 | Evidence: &tmproto.EvidenceParams{
51 | MaxAgeNumBlocks: 302400,
52 | MaxAgeDuration: 504 * time.Hour, // 3 weeks is the max duration
53 | MaxBytes: 10000,
54 | },
55 | Validator: &tmproto.ValidatorParams{
56 | PubKeyTypes: []string{
57 | tmtypes.ABCIPubKeyTypeEd25519,
58 | },
59 | },
60 | }
61 |
62 | type emptyAppOptions struct{}
63 |
64 | // Get implements AppOptions
65 | func (ao emptyAppOptions) Get(o string) interface{} {
66 | return nil
67 | }
68 |
69 | // SetupTestAppWithGenesisValSet initializes a new app with a validator set and genesis accounts
70 | // that also act as delegators. For simplicity, each validator is bonded with a delegation
71 | // of one consensus engine unit in the default token of the app from first genesis
72 | // account. A Nop logger is set in app.
73 | func SetupTestAppWithGenesisValSet(genAccounts ...string) (*app.App, keyring.Keyring) {
74 | // var cache sdk.MultiStorePersistentCache
75 | // EmptyAppOptions is a stub implementing AppOptions
76 | emptyOpts := emptyAppOptions{}
77 | // var anteOpt = func(bapp *baseapp.BaseApp) { bapp.SetAnteHandler(nil) }
78 | db := dbm.NewMemDB()
79 | skipUpgradeHeights := make(map[int64]bool)
80 |
81 | encCfg := encoding.MakeConfig(app.ModuleEncodingRegisters...)
82 |
83 | testApp := app.New(
84 | log.NewNopLogger(), db, nil, true, skipUpgradeHeights,
85 | cast.ToString(emptyOpts.Get(flags.FlagHome)),
86 | cast.ToUint(emptyOpts.Get(server.FlagInvCheckPeriod)),
87 | encCfg,
88 | emptyOpts,
89 | )
90 |
91 | genesisState, valSet, kr := GenesisStateWithSingleValidator(testApp, genAccounts...)
92 |
93 | stateBytes, err := json.MarshalIndent(genesisState, "", " ")
94 | if err != nil {
95 | panic(err)
96 | }
97 |
98 | // init chain will set the validator set and initialize the genesis accounts
99 | testApp.InitChain(
100 | abci.RequestInitChain{
101 | Validators: []abci.ValidatorUpdate{},
102 | ConsensusParams: DefaultConsensusParams,
103 | AppStateBytes: stateBytes,
104 | ChainId: ChainID,
105 | },
106 | )
107 |
108 | // commit genesis changes
109 | testApp.Commit()
110 | testApp.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{
111 | Height: testApp.LastBlockHeight() + 1,
112 | AppHash: testApp.LastCommitID().Hash,
113 | ValidatorsHash: valSet.Hash(),
114 | NextValidatorsHash: valSet.Hash(),
115 | }})
116 |
117 | return testApp, kr
118 | }
119 |
120 | // AddGenesisAccount mimics the cli addGenesisAccount command, providing an
121 | // account with an allocation of to "token" and "tia" tokens in the genesis
122 | // state
123 | func AddGenesisAccount(addr sdk.AccAddress, appState app.GenesisState, cdc codec.Codec) (map[string]json.RawMessage, error) {
124 | // create concrete account type based on input parameters
125 | var genAccount authtypes.GenesisAccount
126 |
127 | coins := sdk.Coins{
128 | sdk.NewCoin("token", sdk.NewInt(1000000)),
129 | sdk.NewCoin(consts.BondDenom, sdk.NewInt(1000000)),
130 | }
131 |
132 | balances := banktypes.Balance{Address: addr.String(), Coins: coins.Sort()}
133 | baseAccount := authtypes.NewBaseAccount(addr, nil, 0, 0)
134 |
135 | genAccount = baseAccount
136 |
137 | if err := genAccount.Validate(); err != nil {
138 | return appState, fmt.Errorf("failed to validate new genesis account: %w", err)
139 | }
140 |
141 | authGenState := authtypes.GetGenesisStateFromAppState(cdc, appState)
142 |
143 | accs, err := authtypes.UnpackAccounts(authGenState.Accounts)
144 | if err != nil {
145 | return appState, fmt.Errorf("failed to get accounts from any: %w", err)
146 | }
147 |
148 | if accs.Contains(addr) {
149 | return appState, fmt.Errorf("cannot add account at existing address %s", addr)
150 | }
151 |
152 | // Add the new account to the set of genesis accounts and sanitize the
153 | // accounts afterwards.
154 | accs = append(accs, genAccount)
155 | accs = authtypes.SanitizeGenesisAccounts(accs)
156 |
157 | genAccs, err := authtypes.PackAccounts(accs)
158 | if err != nil {
159 | return appState, fmt.Errorf("failed to convert accounts into any's: %w", err)
160 | }
161 | authGenState.Accounts = genAccs
162 |
163 | authGenStateBz, err := cdc.MarshalJSON(&authGenState)
164 | if err != nil {
165 | return appState, fmt.Errorf("failed to marshal auth genesis state: %w", err)
166 | }
167 |
168 | appState[authtypes.ModuleName] = authGenStateBz
169 |
170 | bankGenState := banktypes.GetGenesisStateFromAppState(cdc, appState)
171 | bankGenState.Balances = append(bankGenState.Balances, balances)
172 | bankGenState.Balances = banktypes.SanitizeGenesisBalances(bankGenState.Balances)
173 |
174 | bankGenStateBz, err := cdc.MarshalJSON(bankGenState)
175 | if err != nil {
176 | return appState, fmt.Errorf("failed to marshal bank genesis state: %w", err)
177 | }
178 |
179 | appState[banktypes.ModuleName] = bankGenStateBz
180 | return appState, nil
181 | }
182 |
183 | // GenesisStateWithSingleValidator initializes GenesisState with a single validator and genesis accounts
184 | // that also act as delegators.
185 | func GenesisStateWithSingleValidator(testApp *app.App, genAccounts ...string) (app.GenesisState, *tmtypes.ValidatorSet, keyring.Keyring) {
186 | privVal := mock.NewPV()
187 | pubKey, err := privVal.GetPubKey()
188 | if err != nil {
189 | panic(err)
190 | }
191 |
192 | // create validator set with single validator
193 | validator := tmtypes.NewValidator(pubKey, 1)
194 | valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
195 |
196 | // generate genesis account
197 | senderPrivKey := secp256k1.GenPrivKey()
198 | accs := make([]authtypes.GenesisAccount, 0, len(genAccounts)+1)
199 | acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0)
200 | accs = append(accs, acc)
201 | balances := make([]banktypes.Balance, 0, len(genAccounts)+1)
202 | balances = append(balances, banktypes.Balance{
203 | Address: acc.GetAddress().String(),
204 | Coins: sdk.NewCoins(sdk.NewCoin(consts.BondDenom, sdk.NewInt(100000000000000))),
205 | })
206 |
207 | kr, fundedBankAccs, fundedAuthAccs := testfactory.FundKeyringAccounts(testApp.AppCodec(), genAccounts...)
208 | accs = append(accs, fundedAuthAccs...)
209 | balances = append(balances, fundedBankAccs...)
210 |
211 | genesisState := NewDefaultGenesisState(testApp.AppCodec())
212 | genesisState = genesisStateWithValSet(testApp, genesisState, valSet, accs, balances...)
213 |
214 | return genesisState, valSet, kr
215 | }
216 |
217 | func genesisStateWithValSet(
218 | mapp *app.App,
219 | genesisState app.GenesisState,
220 | valSet *tmtypes.ValidatorSet,
221 | genAccs []authtypes.GenesisAccount,
222 | balances ...banktypes.Balance,
223 | ) app.GenesisState {
224 | // set genesis accounts
225 | authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs)
226 | genesisState[authtypes.ModuleName] = mapp.AppCodec().MustMarshalJSON(authGenesis)
227 |
228 | validators := make([]stakingtypes.Validator, 0, len(valSet.Validators))
229 | delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators))
230 |
231 | bondAmt := sdk.DefaultPowerReduction
232 |
233 | for _, val := range valSet.Validators {
234 | pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey)
235 | if err != nil {
236 | panic(err)
237 | }
238 | pkAny, err := codectypes.NewAnyWithValue(pk)
239 | if err != nil {
240 | panic(err)
241 | }
242 | validator := stakingtypes.Validator{
243 | OperatorAddress: sdk.ValAddress(val.Address).String(),
244 | ConsensusPubkey: pkAny,
245 | Jailed: false,
246 | Status: stakingtypes.Bonded,
247 | Tokens: bondAmt,
248 | DelegatorShares: sdk.OneDec(),
249 | Description: stakingtypes.Description{},
250 | UnbondingHeight: int64(0),
251 | UnbondingTime: time.Unix(0, 0).UTC(),
252 | Commission: stakingtypes.NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
253 | MinSelfDelegation: sdk.ZeroInt(),
254 | }
255 | validators = append(validators, validator)
256 | delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec()))
257 |
258 | }
259 | // set validators and delegations
260 | stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations)
261 | genesisState[stakingtypes.ModuleName] = mapp.AppCodec().MustMarshalJSON(stakingGenesis)
262 |
263 | totalSupply := sdk.NewCoins()
264 | for _, b := range balances {
265 | // add genesis acc tokens to total supply
266 | totalSupply = totalSupply.Add(b.Coins...)
267 | }
268 |
269 | for range delegations {
270 | // add delegated tokens to total supply
271 | totalSupply = totalSupply.Add(sdk.NewCoin(consts.BondDenom, bondAmt))
272 | }
273 |
274 | // add bonded amount to bonded pool module account
275 | balances = append(balances, banktypes.Balance{
276 | Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(),
277 | Coins: sdk.Coins{sdk.NewCoin(consts.BondDenom, bondAmt)},
278 | })
279 |
280 | // update total supply
281 | bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{})
282 | genesisState[banktypes.ModuleName] = mapp.AppCodec().MustMarshalJSON(bankGenesis)
283 |
284 | return genesisState
285 | }
286 |
287 | // NewDefaultGenesisState generates the default state for the application.
288 | func NewDefaultGenesisState(cdc codec.JSONCodec) app.GenesisState {
289 | return app.ModuleBasics.DefaultGenesis(cdc)
290 | }
291 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2022 Evan Forbes
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/third_party/proto/google/api/http.proto:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | syntax = "proto3";
16 |
17 | package google.api;
18 |
19 | option cc_enable_arenas = true;
20 | option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
21 | option java_multiple_files = true;
22 | option java_outer_classname = "HttpProto";
23 | option java_package = "com.google.api";
24 | option objc_class_prefix = "GAPI";
25 |
26 |
27 | // Defines the HTTP configuration for an API service. It contains a list of
28 | // [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method
29 | // to one or more HTTP REST API methods.
30 | message Http {
31 | // A list of HTTP configuration rules that apply to individual API methods.
32 | //
33 | // **NOTE:** All service configuration rules follow "last one wins" order.
34 | repeated HttpRule rules = 1;
35 |
36 | // When set to true, URL path parmeters will be fully URI-decoded except in
37 | // cases of single segment matches in reserved expansion, where "%2F" will be
38 | // left encoded.
39 | //
40 | // The default behavior is to not decode RFC 6570 reserved characters in multi
41 | // segment matches.
42 | bool fully_decode_reserved_expansion = 2;
43 | }
44 |
45 | // `HttpRule` defines the mapping of an RPC method to one or more HTTP
46 | // REST API methods. The mapping specifies how different portions of the RPC
47 | // request message are mapped to URL path, URL query parameters, and
48 | // HTTP request body. The mapping is typically specified as an
49 | // `google.api.http` annotation on the RPC method,
50 | // see "google/api/annotations.proto" for details.
51 | //
52 | // The mapping consists of a field specifying the path template and
53 | // method kind. The path template can refer to fields in the request
54 | // message, as in the example below which describes a REST GET
55 | // operation on a resource collection of messages:
56 | //
57 | //
58 | // service Messaging {
59 | // rpc GetMessage(GetMessageRequest) returns (Message) {
60 | // option (google.api.http).get = "/v1/messages/{message_id}/{sub.subfield}";
61 | // }
62 | // }
63 | // message GetMessageRequest {
64 | // message SubMessage {
65 | // string subfield = 1;
66 | // }
67 | // string message_id = 1; // mapped to the URL
68 | // SubMessage sub = 2; // `sub.subfield` is url-mapped
69 | // }
70 | // message Message {
71 | // string text = 1; // content of the resource
72 | // }
73 | //
74 | // The same http annotation can alternatively be expressed inside the
75 | // `GRPC API Configuration` YAML file.
76 | //
77 | // http:
78 | // rules:
79 | // - selector: .Messaging.GetMessage
80 | // get: /v1/messages/{message_id}/{sub.subfield}
81 | //
82 | // This definition enables an automatic, bidrectional mapping of HTTP
83 | // JSON to RPC. Example:
84 | //
85 | // HTTP | RPC
86 | // -----|-----
87 | // `GET /v1/messages/123456/foo` | `GetMessage(message_id: "123456" sub: SubMessage(subfield: "foo"))`
88 | //
89 | // In general, not only fields but also field paths can be referenced
90 | // from a path pattern. Fields mapped to the path pattern cannot be
91 | // repeated and must have a primitive (non-message) type.
92 | //
93 | // Any fields in the request message which are not bound by the path
94 | // pattern automatically become (optional) HTTP query
95 | // parameters. Assume the following definition of the request message:
96 | //
97 | //
98 | // service Messaging {
99 | // rpc GetMessage(GetMessageRequest) returns (Message) {
100 | // option (google.api.http).get = "/v1/messages/{message_id}";
101 | // }
102 | // }
103 | // message GetMessageRequest {
104 | // message SubMessage {
105 | // string subfield = 1;
106 | // }
107 | // string message_id = 1; // mapped to the URL
108 | // int64 revision = 2; // becomes a parameter
109 | // SubMessage sub = 3; // `sub.subfield` becomes a parameter
110 | // }
111 | //
112 | //
113 | // This enables a HTTP JSON to RPC mapping as below:
114 | //
115 | // HTTP | RPC
116 | // -----|-----
117 | // `GET /v1/messages/123456?revision=2&sub.subfield=foo` | `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: "foo"))`
118 | //
119 | // Note that fields which are mapped to HTTP parameters must have a
120 | // primitive type or a repeated primitive type. Message types are not
121 | // allowed. In the case of a repeated type, the parameter can be
122 | // repeated in the URL, as in `...?param=A¶m=B`.
123 | //
124 | // For HTTP method kinds which allow a request body, the `body` field
125 | // specifies the mapping. Consider a REST update method on the
126 | // message resource collection:
127 | //
128 | //
129 | // service Messaging {
130 | // rpc UpdateMessage(UpdateMessageRequest) returns (Message) {
131 | // option (google.api.http) = {
132 | // put: "/v1/messages/{message_id}"
133 | // body: "message"
134 | // };
135 | // }
136 | // }
137 | // message UpdateMessageRequest {
138 | // string message_id = 1; // mapped to the URL
139 | // Message message = 2; // mapped to the body
140 | // }
141 | //
142 | //
143 | // The following HTTP JSON to RPC mapping is enabled, where the
144 | // representation of the JSON in the request body is determined by
145 | // protos JSON encoding:
146 | //
147 | // HTTP | RPC
148 | // -----|-----
149 | // `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" message { text: "Hi!" })`
150 | //
151 | // The special name `*` can be used in the body mapping to define that
152 | // every field not bound by the path template should be mapped to the
153 | // request body. This enables the following alternative definition of
154 | // the update method:
155 | //
156 | // service Messaging {
157 | // rpc UpdateMessage(Message) returns (Message) {
158 | // option (google.api.http) = {
159 | // put: "/v1/messages/{message_id}"
160 | // body: "*"
161 | // };
162 | // }
163 | // }
164 | // message Message {
165 | // string message_id = 1;
166 | // string text = 2;
167 | // }
168 | //
169 | //
170 | // The following HTTP JSON to RPC mapping is enabled:
171 | //
172 | // HTTP | RPC
173 | // -----|-----
174 | // `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" text: "Hi!")`
175 | //
176 | // Note that when using `*` in the body mapping, it is not possible to
177 | // have HTTP parameters, as all fields not bound by the path end in
178 | // the body. This makes this option more rarely used in practice of
179 | // defining REST APIs. The common usage of `*` is in custom methods
180 | // which don't use the URL at all for transferring data.
181 | //
182 | // It is possible to define multiple HTTP methods for one RPC by using
183 | // the `additional_bindings` option. Example:
184 | //
185 | // service Messaging {
186 | // rpc GetMessage(GetMessageRequest) returns (Message) {
187 | // option (google.api.http) = {
188 | // get: "/v1/messages/{message_id}"
189 | // additional_bindings {
190 | // get: "/v1/users/{user_id}/messages/{message_id}"
191 | // }
192 | // };
193 | // }
194 | // }
195 | // message GetMessageRequest {
196 | // string message_id = 1;
197 | // string user_id = 2;
198 | // }
199 | //
200 | //
201 | // This enables the following two alternative HTTP JSON to RPC
202 | // mappings:
203 | //
204 | // HTTP | RPC
205 | // -----|-----
206 | // `GET /v1/messages/123456` | `GetMessage(message_id: "123456")`
207 | // `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: "123456")`
208 | //
209 | // # Rules for HTTP mapping
210 | //
211 | // The rules for mapping HTTP path, query parameters, and body fields
212 | // to the request message are as follows:
213 | //
214 | // 1. The `body` field specifies either `*` or a field path, or is
215 | // omitted. If omitted, it indicates there is no HTTP request body.
216 | // 2. Leaf fields (recursive expansion of nested messages in the
217 | // request) can be classified into three types:
218 | // (a) Matched in the URL template.
219 | // (b) Covered by body (if body is `*`, everything except (a) fields;
220 | // else everything under the body field)
221 | // (c) All other fields.
222 | // 3. URL query parameters found in the HTTP request are mapped to (c) fields.
223 | // 4. Any body sent with an HTTP request can contain only (b) fields.
224 | //
225 | // The syntax of the path template is as follows:
226 | //
227 | // Template = "/" Segments [ Verb ] ;
228 | // Segments = Segment { "/" Segment } ;
229 | // Segment = "*" | "**" | LITERAL | Variable ;
230 | // Variable = "{" FieldPath [ "=" Segments ] "}" ;
231 | // FieldPath = IDENT { "." IDENT } ;
232 | // Verb = ":" LITERAL ;
233 | //
234 | // The syntax `*` matches a single path segment. The syntax `**` matches zero
235 | // or more path segments, which must be the last part of the path except the
236 | // `Verb`. The syntax `LITERAL` matches literal text in the path.
237 | //
238 | // The syntax `Variable` matches part of the URL path as specified by its
239 | // template. A variable template must not contain other variables. If a variable
240 | // matches a single path segment, its template may be omitted, e.g. `{var}`
241 | // is equivalent to `{var=*}`.
242 | //
243 | // If a variable contains exactly one path segment, such as `"{var}"` or
244 | // `"{var=*}"`, when such a variable is expanded into a URL path, all characters
245 | // except `[-_.~0-9a-zA-Z]` are percent-encoded. Such variables show up in the
246 | // Discovery Document as `{var}`.
247 | //
248 | // If a variable contains one or more path segments, such as `"{var=foo/*}"`
249 | // or `"{var=**}"`, when such a variable is expanded into a URL path, all
250 | // characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. Such variables
251 | // show up in the Discovery Document as `{+var}`.
252 | //
253 | // NOTE: While the single segment variable matches the semantics of
254 | // [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2
255 | // Simple String Expansion, the multi segment variable **does not** match
256 | // RFC 6570 Reserved Expansion. The reason is that the Reserved Expansion
257 | // does not expand special characters like `?` and `#`, which would lead
258 | // to invalid URLs.
259 | //
260 | // NOTE: the field paths in variables and in the `body` must not refer to
261 | // repeated fields or map fields.
262 | message HttpRule {
263 | // Selects methods to which this rule applies.
264 | //
265 | // Refer to [selector][google.api.DocumentationRule.selector] for syntax details.
266 | string selector = 1;
267 |
268 | // Determines the URL pattern is matched by this rules. This pattern can be
269 | // used with any of the {get|put|post|delete|patch} methods. A custom method
270 | // can be defined using the 'custom' field.
271 | oneof pattern {
272 | // Used for listing and getting information about resources.
273 | string get = 2;
274 |
275 | // Used for updating a resource.
276 | string put = 3;
277 |
278 | // Used for creating a resource.
279 | string post = 4;
280 |
281 | // Used for deleting a resource.
282 | string delete = 5;
283 |
284 | // Used for updating a resource.
285 | string patch = 6;
286 |
287 | // The custom pattern is used for specifying an HTTP method that is not
288 | // included in the `pattern` field, such as HEAD, or "*" to leave the
289 | // HTTP method unspecified for this rule. The wild-card rule is useful
290 | // for services that provide content to Web (HTML) clients.
291 | CustomHttpPattern custom = 8;
292 | }
293 |
294 | // The name of the request field whose value is mapped to the HTTP body, or
295 | // `*` for mapping all fields not captured by the path pattern to the HTTP
296 | // body. NOTE: the referred field must not be a repeated field and must be
297 | // present at the top-level of request message type.
298 | string body = 7;
299 |
300 | // Optional. The name of the response field whose value is mapped to the HTTP
301 | // body of response. Other response fields are ignored. When
302 | // not set, the response message will be used as HTTP body of response.
303 | string response_body = 12;
304 |
305 | // Additional HTTP bindings for the selector. Nested bindings must
306 | // not contain an `additional_bindings` field themselves (that is,
307 | // the nesting may only be one level deep).
308 | repeated HttpRule additional_bindings = 11;
309 | }
310 |
311 | // A custom pattern is used for defining custom HTTP verb.
312 | message CustomHttpPattern {
313 | // The name of this custom HTTP verb.
314 | string kind = 1;
315 |
316 | // The path matched by this custom verb.
317 | string path = 2;
318 | }
319 |
--------------------------------------------------------------------------------
/third_party/proto/tendermint/abci/types.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package tendermint.abci;
3 |
4 | option go_package = "github.com/tendermint/tendermint/abci/types";
5 |
6 | // For more information on gogo.proto, see:
7 | // https://github.com/gogo/protobuf/blob/master/extensions.md
8 | import "tendermint/crypto/proof.proto";
9 | import "tendermint/types/types.proto";
10 | import "tendermint/crypto/keys.proto";
11 | import "tendermint/types/params.proto";
12 | import "google/protobuf/timestamp.proto";
13 | import "gogoproto/gogo.proto";
14 |
15 | // This file is copied from http://github.com/tendermint/abci
16 | // NOTE: When using custom types, mind the warnings.
17 | // https://github.com/gogo/protobuf/blob/master/custom_types.md#warnings-and-issues
18 |
19 | //----------------------------------------
20 | // Request types
21 |
22 | message Request {
23 | oneof value {
24 | RequestEcho echo = 1;
25 | RequestFlush flush = 2;
26 | RequestInfo info = 3;
27 | RequestInitChain init_chain = 4;
28 | RequestQuery query = 5;
29 | RequestBeginBlock begin_block = 6;
30 | RequestCheckTx check_tx = 7;
31 | RequestDeliverTx deliver_tx = 8;
32 | RequestEndBlock end_block = 9;
33 | RequestCommit commit = 10;
34 | RequestListSnapshots list_snapshots = 11;
35 | RequestOfferSnapshot offer_snapshot = 12;
36 | RequestLoadSnapshotChunk load_snapshot_chunk = 13;
37 | RequestApplySnapshotChunk apply_snapshot_chunk = 14;
38 | RequestPreprocessTxs preprocess_txs = 15;
39 | }
40 | }
41 |
42 | message RequestEcho {
43 | string message = 1;
44 | }
45 |
46 | message RequestFlush {}
47 |
48 | message RequestInfo {
49 | string version = 1;
50 | uint64 block_version = 2;
51 | uint64 p2p_version = 3;
52 | string abci_version = 4;
53 | }
54 |
55 | message RequestInitChain {
56 | google.protobuf.Timestamp time = 1
57 | [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
58 | string chain_id = 2;
59 | ConsensusParams consensus_params = 3;
60 | repeated ValidatorUpdate validators = 4 [(gogoproto.nullable) = false];
61 | bytes app_state_bytes = 5;
62 | int64 initial_height = 6;
63 | }
64 |
65 | message RequestQuery {
66 | bytes data = 1;
67 | string path = 2;
68 | int64 height = 3;
69 | bool prove = 4;
70 | }
71 |
72 | message RequestBeginBlock {
73 | bytes hash = 1;
74 | tendermint.types.Header header = 2 [(gogoproto.nullable) = false];
75 | LastCommitInfo last_commit_info = 3 [(gogoproto.nullable) = false];
76 | repeated Evidence byzantine_validators = 4 [(gogoproto.nullable) = false];
77 | }
78 |
79 | enum CheckTxType {
80 | NEW = 0 [(gogoproto.enumvalue_customname) = "New"];
81 | RECHECK = 1 [(gogoproto.enumvalue_customname) = "Recheck"];
82 | }
83 |
84 | message RequestCheckTx {
85 | bytes tx = 1;
86 | CheckTxType type = 2;
87 | }
88 |
89 | message RequestDeliverTx {
90 | bytes tx = 1;
91 | }
92 |
93 | message RequestEndBlock {
94 | int64 height = 1;
95 | }
96 |
97 | message RequestCommit {}
98 |
99 | // lists available snapshots
100 | message RequestListSnapshots {
101 | }
102 |
103 | // offers a snapshot to the application
104 | message RequestOfferSnapshot {
105 | Snapshot snapshot = 1; // snapshot offered by peers
106 | bytes app_hash = 2; // light client-verified app hash for snapshot height
107 | }
108 |
109 | // loads a snapshot chunk
110 | message RequestLoadSnapshotChunk {
111 | uint64 height = 1;
112 | uint32 format = 2;
113 | uint32 chunk = 3;
114 | }
115 |
116 | // Applies a snapshot chunk
117 | message RequestApplySnapshotChunk {
118 | uint32 index = 1;
119 | bytes chunk = 2;
120 | string sender = 3;
121 | }
122 |
123 | message RequestPreprocessTxs {
124 | repeated bytes txs = 1;
125 | }
126 |
127 | //----------------------------------------
128 | // Response types
129 |
130 | message Response {
131 | oneof value {
132 | ResponseException exception = 1;
133 | ResponseEcho echo = 2;
134 | ResponseFlush flush = 3;
135 | ResponseInfo info = 4;
136 | ResponseInitChain init_chain = 5;
137 | ResponseQuery query = 6;
138 | ResponseBeginBlock begin_block = 7;
139 | ResponseCheckTx check_tx = 8;
140 | ResponseDeliverTx deliver_tx = 9;
141 | ResponseEndBlock end_block = 10;
142 | ResponseCommit commit = 11;
143 | ResponseListSnapshots list_snapshots = 12;
144 | ResponseOfferSnapshot offer_snapshot = 13;
145 | ResponseLoadSnapshotChunk load_snapshot_chunk = 14;
146 | ResponseApplySnapshotChunk apply_snapshot_chunk = 15;
147 | ResponsePreprocessTxs preprocess_txs = 16;
148 | }
149 | }
150 |
151 | // nondeterministic
152 | message ResponseException {
153 | string error = 1;
154 | }
155 |
156 | message ResponseEcho {
157 | string message = 1;
158 | }
159 |
160 | message ResponseFlush {}
161 |
162 | message ResponseInfo {
163 | string data = 1;
164 |
165 | // this is the software version of the application. TODO: remove?
166 | string version = 2;
167 | uint64 app_version = 3;
168 |
169 | int64 last_block_height = 4;
170 | bytes last_block_app_hash = 5;
171 | }
172 |
173 | message ResponseInitChain {
174 | ConsensusParams consensus_params = 1;
175 | repeated ValidatorUpdate validators = 2 [(gogoproto.nullable) = false];
176 | bytes app_hash = 3;
177 | }
178 |
179 | message ResponseQuery {
180 | uint32 code = 1;
181 | // bytes data = 2; // use "value" instead.
182 | string log = 3; // nondeterministic
183 | string info = 4; // nondeterministic
184 | int64 index = 5;
185 | bytes key = 6;
186 | bytes value = 7;
187 | tendermint.crypto.ProofOps proof_ops = 8;
188 | int64 height = 9;
189 | string codespace = 10;
190 | }
191 |
192 | message ResponseBeginBlock {
193 | repeated Event events = 1
194 | [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"];
195 | }
196 |
197 | message ResponseCheckTx {
198 | uint32 code = 1;
199 | bytes data = 2;
200 | string log = 3; // nondeterministic
201 | string info = 4; // nondeterministic
202 | int64 gas_wanted = 5 [json_name = "gas_wanted"];
203 | int64 gas_used = 6 [json_name = "gas_used"];
204 | repeated Event events = 7
205 | [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"];
206 | string codespace = 8;
207 | }
208 |
209 | message ResponseDeliverTx {
210 | uint32 code = 1;
211 | bytes data = 2;
212 | string log = 3; // nondeterministic
213 | string info = 4; // nondeterministic
214 | int64 gas_wanted = 5 [json_name = "gas_wanted"];
215 | int64 gas_used = 6 [json_name = "gas_used"];
216 | repeated Event events = 7
217 | [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"];
218 | string codespace = 8;
219 | }
220 |
221 | message ResponseEndBlock {
222 | repeated ValidatorUpdate validator_updates = 1
223 | [(gogoproto.nullable) = false];
224 | ConsensusParams consensus_param_updates = 2;
225 | repeated Event events = 3
226 | [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"];
227 | }
228 |
229 | message ResponseCommit {
230 | // reserve 1
231 | bytes data = 2;
232 | int64 retain_height = 3;
233 | }
234 |
235 | message ResponseListSnapshots {
236 | repeated Snapshot snapshots = 1;
237 | }
238 |
239 | message ResponseOfferSnapshot {
240 | Result result = 1;
241 |
242 | enum Result {
243 | UNKNOWN = 0; // Unknown result, abort all snapshot restoration
244 | ACCEPT = 1; // Snapshot accepted, apply chunks
245 | ABORT = 2; // Abort all snapshot restoration
246 | REJECT = 3; // Reject this specific snapshot, try others
247 | REJECT_FORMAT = 4; // Reject all snapshots of this format, try others
248 | REJECT_SENDER = 5; // Reject all snapshots from the sender(s), try others
249 | }
250 | }
251 |
252 | message ResponseLoadSnapshotChunk {
253 | bytes chunk = 1;
254 | }
255 |
256 | message ResponseApplySnapshotChunk {
257 | Result result = 1;
258 | repeated uint32 refetch_chunks = 2; // Chunks to refetch and reapply
259 | repeated string reject_senders = 3; // Chunk senders to reject and ban
260 |
261 | enum Result {
262 | UNKNOWN = 0; // Unknown result, abort all snapshot restoration
263 | ACCEPT = 1; // Chunk successfully accepted
264 | ABORT = 2; // Abort all snapshot restoration
265 | RETRY = 3; // Retry chunk (combine with refetch and reject)
266 | RETRY_SNAPSHOT = 4; // Retry snapshot (combine with refetch and reject)
267 | REJECT_SNAPSHOT = 5; // Reject this snapshot, try others
268 | }
269 | }
270 |
271 | message ResponsePreprocessTxs {
272 | repeated bytes txs = 1;
273 | tendermint.types.Messages messages = 2;
274 | }
275 |
276 | //----------------------------------------
277 | // Misc.
278 |
279 | // ConsensusParams contains all consensus-relevant parameters
280 | // that can be adjusted by the abci app
281 | message ConsensusParams {
282 | BlockParams block = 1;
283 | tendermint.types.EvidenceParams evidence = 2;
284 | tendermint.types.ValidatorParams validator = 3;
285 | tendermint.types.VersionParams version = 4;
286 | }
287 |
288 | // BlockParams contains limits on the block size.
289 | message BlockParams {
290 | // Note: must be greater than 0
291 | int64 max_bytes = 1;
292 | // Note: must be greater or equal to -1
293 | int64 max_gas = 2;
294 | }
295 |
296 | message LastCommitInfo {
297 | int32 round = 1;
298 | repeated VoteInfo votes = 2 [(gogoproto.nullable) = false];
299 | }
300 |
301 | // Event allows application developers to attach additional information to
302 | // ResponseBeginBlock, ResponseEndBlock, ResponseCheckTx and ResponseDeliverTx.
303 | // Later, transactions may be queried using these events.
304 | message Event {
305 | string type = 1;
306 | repeated EventAttribute attributes = 2 [
307 | (gogoproto.nullable) = false,
308 | (gogoproto.jsontag) = "attributes,omitempty"
309 | ];
310 | }
311 |
312 | // EventAttribute is a single key-value pair, associated with an event.
313 | message EventAttribute {
314 | bytes key = 1;
315 | bytes value = 2;
316 | bool index = 3; // nondeterministic
317 | }
318 |
319 | // TxResult contains results of executing the transaction.
320 | //
321 | // One usage is indexing transaction results.
322 | message TxResult {
323 | int64 height = 1;
324 | uint32 index = 2;
325 | bytes tx = 3;
326 | ResponseDeliverTx result = 4 [(gogoproto.nullable) = false];
327 | bytes original_hash = 5;
328 | }
329 |
330 | //----------------------------------------
331 | // Blockchain Types
332 |
333 | // Validator
334 | message Validator {
335 | bytes address = 1; // The first 20 bytes of SHA256(public key)
336 | // PubKey pub_key = 2 [(gogoproto.nullable)=false];
337 | int64 power = 3; // The voting power
338 | }
339 |
340 | // ValidatorUpdate
341 | message ValidatorUpdate {
342 | tendermint.crypto.PublicKey pub_key = 1 [(gogoproto.nullable) = false];
343 | int64 power = 2;
344 | }
345 |
346 | // VoteInfo
347 | message VoteInfo {
348 | Validator validator = 1 [(gogoproto.nullable) = false];
349 | bool signed_last_block = 2;
350 | }
351 |
352 | enum EvidenceType {
353 | UNKNOWN = 0;
354 | DUPLICATE_VOTE = 1;
355 | LIGHT_CLIENT_ATTACK = 2;
356 | }
357 |
358 | message Evidence {
359 | EvidenceType type = 1;
360 | // The offending validator
361 | Validator validator = 2 [(gogoproto.nullable) = false];
362 | // The height when the offense occurred
363 | int64 height = 3;
364 | // The corresponding time where the offense occurred
365 | google.protobuf.Timestamp time = 4 [
366 | (gogoproto.nullable) = false,
367 | (gogoproto.stdtime) = true
368 | ];
369 | // Total voting power of the validator set in case the ABCI application does
370 | // not store historical validators.
371 | // https://github.com/tendermint/tendermint/issues/4581
372 | int64 total_voting_power = 5;
373 | }
374 |
375 | //----------------------------------------
376 | // State Sync Types
377 |
378 | message Snapshot {
379 | uint64 height = 1; // The height at which the snapshot was taken
380 | uint32 format = 2; // The application-specific snapshot format
381 | uint32 chunks = 3; // Number of chunks in the snapshot
382 | bytes hash = 4; // Arbitrary snapshot hash, equal only if identical
383 | bytes metadata = 5; // Arbitrary application metadata
384 | }
385 |
386 | //----------------------------------------
387 | // Service Definition
388 |
389 | service ABCIApplication {
390 | rpc Echo(RequestEcho) returns (ResponseEcho);
391 | rpc Flush(RequestFlush) returns (ResponseFlush);
392 | rpc Info(RequestInfo) returns (ResponseInfo);
393 | rpc DeliverTx(RequestDeliverTx) returns (ResponseDeliverTx);
394 | rpc CheckTx(RequestCheckTx) returns (ResponseCheckTx);
395 | rpc Query(RequestQuery) returns (ResponseQuery);
396 | rpc Commit(RequestCommit) returns (ResponseCommit);
397 | rpc InitChain(RequestInitChain) returns (ResponseInitChain);
398 | rpc BeginBlock(RequestBeginBlock) returns (ResponseBeginBlock);
399 | rpc EndBlock(RequestEndBlock) returns (ResponseEndBlock);
400 | rpc ListSnapshots(RequestListSnapshots) returns (ResponseListSnapshots);
401 | rpc OfferSnapshot(RequestOfferSnapshot) returns (ResponseOfferSnapshot);
402 | rpc LoadSnapshotChunk(RequestLoadSnapshotChunk) returns (ResponseLoadSnapshotChunk);
403 | rpc ApplySnapshotChunk(RequestApplySnapshotChunk) returns (ResponseApplySnapshotChunk);
404 | rpc PreprocessTxs(RequestPreprocessTxs) returns (ResponsePreprocessTxs);
405 | }
406 |
--------------------------------------------------------------------------------