{"id":13414401,"url":"https://github.com/6thc/tendermint-cas-demo","last_synced_at":"2025-03-14T21:32:42.634Z","repository":{"id":57505370,"uuid":"153936752","full_name":"6thc/tendermint-cas-demo","owner":"6thc","description":"A demo application built on the Tendermint ABCI. Tech owner: Peter Bourgon.","archived":false,"fork":false,"pushed_at":"2018-10-23T16:20:53.000Z","size":4176,"stargazers_count":35,"open_issues_count":0,"forks_count":6,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-07-31T21:52:58.674Z","etag":null,"topics":["experimental"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/6thc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-10-20T18:39:36.000Z","updated_at":"2023-11-27T12:06:21.000Z","dependencies_parsed_at":"2022-08-22T08:50:52.775Z","dependency_job_id":null,"html_url":"https://github.com/6thc/tendermint-cas-demo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/6thc%2Ftendermint-cas-demo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/6thc%2Ftendermint-cas-demo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/6thc%2Ftendermint-cas-demo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/6thc%2Ftendermint-cas-demo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/6thc","download_url":"https://codeload.github.com/6thc/tendermint-cas-demo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221509017,"owners_count":16834813,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["experimental"],"created_at":"2024-07-30T21:00:20.630Z","updated_at":"2024-10-26T07:31:12.330Z","avatar_url":"https://github.com/6thc.png","language":"Go","funding_links":[],"categories":["Tutorials"],"sub_categories":[],"readme":"# Tendermint CAS demo [![Travis CI](https://travis-ci.org/6thc/tendermint-cas-demo.svg?branch=master)](https://travis-ci.org/6thc/tendermint-cas-demo)\n\nThis repository is a tutorial for building a complete application on top of the\nTendermint ABCI, implementing a key-value store with a compare-and-swap API.\n\n1. [The goal](#the-goal)\n1. [Tendermint v Cosmos](#tendermint-v-cosmos)\n1. [Tendermint concepts](#tendermint-concepts)\n1. [ABCI methods](#abci-methods)\n1. [Our demo application](#our-demo-application)\n1. [The abci-cli](#the-abci-cli)\n1. [System architecture](#system-architecture)\n1. [Operations](#operations)\n1. [Building and running](#building-and-running)\n\n\n## The goal\n\nWe're going to build a distributed system in Go. Each node will have an HTTP API\nimplementing compare-and-swap semantics for a key-value store. The keys and\nvalues will be reliably and consistently replicated between nodes by Tendermint.\n\n```\n$ curl -Ss -XPOST 'http://localhost:10001/x?new=foo'\n{\n    \"key\": \"x\",\n    \"value: \"foo\"\n}\n$ curl -Ss -XPOST 'http://localhost:10002/x?old=foo\u0026new=bar'\n{\n    \"key\": \"x\",\n    \"value: \"bar\"\n}\n$ curl -Ss -XGET 'http://localhost:10003/key'\n{\n    \"key\": \"x\",\n    \"value: \"bar\"\n}\n```\n\nHopefully, this exercise will expose you to enough of the Tendermint programming\nmodel that you can confidently build your own Tendermint ABCI applications.\n\n\n## Tendermint v Cosmos\n\n[Tendermint][tendermint] is a distributed, byzantine fault-tolerant consensus\nsystem designed to replicate arbitrary state machines. You can build on top of\nTendermint by plugging into it at different levels of abstraction, depending on\nwhat kind of application you're building.\n\n[tendermint]: https://www.tendermint.com\n\nAt the lowest level, Tendermint defines an API, called the Application\nBlockChain Interface, or ABCI. Applications that implement the ABCI can be\nreplicated with the Tendermint protocol.\n\nOne level above Tendermint is [Cosmos][cosmos], a federated network of\nblockchains; or, more accurately, the [Cosmos SDK][sdk], which allows users to\nbuild Cosmos-compatible applications. The [Basecoin][basecoin] demo application \nis built on the Cosmos SDK.\n\n[cosmos]: https://cosmos.network\n[sdk]: https://cosmos.network/docs/getting-started/installation.html\n[basecoin]: https://cosmos.network/docs/sdk/core/app5.html\n\n```\n+------------+\n| Basecoin   |\n+------------+ +------------+\n| Cosmos SDK | | This repo  |\n+------------+-+------------+\n| ABCI                      |\n+---------------------------+\n| Tendermint                |\n+---------------------------+\n```\n\n\n## Tendermint concepts\n\n### Understanding ABCI\n\nA picture is worth a thousand words; [this diagram][diagram] provides a great\nconceptual overview of all of the interacting components in a Tendermint\nnetwork. In the full node, we're going to implement the blue box titled ABCI\nApp. To do that, we need to implement [the ABCI interface][application].\n\n[diagram]: https://drive.google.com/file/d/1yR2XpRi9YCY9H9uMfcw8-RMJpvDyvjz9/view\n[application]: https://godoc.org/github.com/tendermint/tendermint/abci/types#Application\n\n```go\ntype Application interface {\n\tInfo(RequestInfo) ResponseInfo\n\tSetOption(RequestSetOption) ResponseSetOption\n\tQuery(RequestQuery) ResponseQuery\n\tCheckTx(tx []byte) ResponseCheckTx\n\tInitChain(RequestInitChain) ResponseInitChain\n\tBeginBlock(RequestBeginBlock) ResponseBeginBlock\n\tDeliverTx(tx []byte) ResponseDeliverTx\n\tEndBlock(RequestEndBlock) ResponseEndBlock\n\tCommit() ResponseCommit\n}\n```\n\nUnderstanding these methods requires understanding the Tendermint state machine.\nLet's understand things at a high level first, and then describe each method in\ndetail.\n\n### Writing application state\n\nIt's expected that your application wraps some state, which Tendermint\ntransactions (Tx) manipulate. Furthermore, it's expected that your application\nstate has a notion of a commit, which should \n\n- **Count** the number of commits made\n- **Persist** the state to long-term storage\n- **Hash** the complete state at the time of commit\n\nTendermint takes care of delivering transactions to your application via\nDeliverTx. Those transactions are guaranteed to come in the same order to all\ninstances of your application, on all nodes in the network. Each transaction\nmust have the same deterministic effect on application state on all nodes.\n\nTransactions are bundled into blocks, demarcated by BeginBlock and EndBlock\ncalls. One block will contain zero or more transactions, delivered via\nDeliverTx. After EndBlock, Tendermint will always call Commit, which should\ntrigger the commit steps enumerated above. Tendermint is guaranteed to call\n(BeginBlock, DeliverTx, DeliverTx, ..., EndBlock, Commit) in exactly the same\norder, with exactly the same data, on all nodes.\n\nAll changes to state must occur via DeliverTx exclusively.\n\n### Reading application state\n\nThe Tendermint ABCI method Query is used to read application state. Your\napplication has a lot of leeway to decide how to create, interpret, and service\nQuery requests. The only thing that Tendermint stipulates is that some query\npaths (a string field in the query request) are reserved. Otherwise, the only\ncontract is that queries must not mutate state.\n\n### Initialization\n\nWe've talked about how state is written to and read from. But how is the\nstate machine itself initialized?\n\nThe abstract, global state machine replicated by Tendermint is created in an\nevent known as genesis. Genesis involves creating a chain ID, which uniquely\nidentifies the state machine, as well as other parameters, like the initial set\nof participating nodes. This configuration information is collected into a genesis\nfile, which must be securely distributed to each initial node in the Tendermint\nnetwork. All nodes must share exactly the same genesis file.\n\nThe concrete, specific state machine instance managed by a given Tendermint node \nis created at process start. If the node is starting for the first time, it will\nhave an empty application state; if the node has e.g. rebooted, it should load its\napplication state from persistent storage into memory.\n\nThree ABCI methods manage state machine initialization.\n\nInitChain is called once, when a node starts for the first time. It tells the\napplication about some aspects of the state machine, or chain, from Tendermint's\nperspective, including the chain ID, consensus parameters, and any initial\napplication state that's been provided by the network operator. The application\ncan use this information to make itself ready to receive transactions.\n\nSetOption may be called to set arbitrary application configuration parameters.\nThis is only done if by user request, and Tendermint doesn't interpret these\ncommands, or route them through its consensus system. This means that any\nchanges made via SetOption may be different on different nodes, and therefore\nmust not have any effect on how transactions or queries are processed. This is\nsometimes referred to as being non-consensus-critical or non-deterministic.\n\nInfo is called at each process start, after the application has restored any\napplication state from persistent storage, so that Tendermint can know the last\nblock height (a.k.a. the commit count) and app state hash of the application.\nTendermint will calculate the diff between what your application reports in\nInfo, and what Tendermint knows the current state of the global state machine to\nbe, and will replay blocks of transactions to your application, until the block\nheight and app hash match.\n\n### Connections\n\nTendermint speaks to your application exclusively through the ABCI interface,\nbut it does so through three independent connections. Calls are serialized on\neach connection, but may be concurrent across different connections. Each\nconnection only calls a subset of the ABCI methods.\n\nThe **query** connection is responsible for read operations by calling Query. It\nalso handles initialization, calling InitChain, SetOption, and Info.\n\nThe **consensus** connection is responsible for write operations, calling\nBeginBlock, DeliverTx, EndBlock, and Commit. \n\nThere is a third connection which introduces a new concept to your application\nstate. When a transaction arrives at a Tendermint node, before it's given to the\nconsensus machinery and replicated to the rest of the network, it's first sent\nto the local application, over the **mempool** connection, to the CheckTx\nmethod. This is ultimately an optimization step, giving the application the\nopportunity to validate the transaction (for example, checking that the\ntransaction body is properly encoded) and stop invalid transactions before\nthey're broadcast. If the application needs to implement replay protection (for\nexample, to protect against double-spend attacks) it should also perform that\naccounting in CheckTx.\n\nTo support CheckTx and the mempool connection, it's recommended that\napplications actually keep two separate in-memory representations of their\nstate: the consensus state, updated by DeliverTx; and the mempool state, updated\nby CheckTx. The mempool state should be updated by CheckTx transactions in the\nsame way the consensus state is updated by DeliverTx transactions, with one\nimportant difference: when the consensus state is committed by Commit, it should\nbe copied to and fully overwrite the mempool state. This is because Tendermint\nmay deliver the same transaction via CheckTx more than once, though it will only\ndo so if that transaction is checked but doesn't make it in to the consensus\nblock.\n\nTo be clear, this step is optional. Applications may choose to skip managing a\nseparate mempool state, and simply return an OK result for every CheckTx call.\nThis should not affect correctness, only efficiency.\n\n### RPC\n\nAll user requests must be routed to the application through Tendermint via\nTendermint's RPC mechanism. Requests must never hit the application or its state\ndirectly. To make RPC requests through Tendermint to our application, we use an\nRPC client. The relevant part of that interface is [ABCIClient][abciclient].\n\n[abciclient]: https://godoc.org/github.com/tendermint/tendermint/rpc/client#ABCIClient\n\n```go\ntype ABCIClient interface {\n\tABCIInfo() (*ctypes.ResultABCIInfo, error)\n\tABCIQuery(path string, data cmn.HexBytes) (*ctypes.ResultABCIQuery, error)\n\tABCIQueryWithOptions(path string, data cmn.HexBytes, opts ABCIQueryOptions) (*ctypes.ResultABCIQuery, error)\n\n\tBroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error)\n\tBroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error)\n\tBroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error)\n}\n```\n\nWe never need to implement an ABCIClient, we just need to construct one. That\nclient should be taken as a dependency to our user-facing API, and all user\nrequests should be proxied through it. Reads should go through ABCIQuery, and\nwrites should go through one of the BroadcastTx methods. The difference between\nthose methods relates to how long they block before returning a result.\nBroadcastTxCommit blocks the longest, and waits until the transaction has been\ncommitted into a block by a quorum of nodes in the network. BroadcastTxSync\nwaits until the transaction has been accepted by the consensus connection, but\nnot necessarily committed. BroadcastTxAsync only waits until the Tendermint\nmachinery has received the transaction, and returns before it's been received by\nany node.\n\n\n## ABCI methods\n\nNow that we have a high-level understanding of Tendermint, let's get into detail\nabout each ABCI method.\n\n### Info\n\nRequestInfo\n\n- **Version**: The version of Tendermint, e.g. \"0.25.0\".\n\nResponseInfo\n- **Data**: An arbitrary string containing information about the application,\n  not parsed by Tendermint. Optional.\n- **Version**: An arbitrary string containing the version of the application,\n  used in the [Tendermint version handshake][versionhandshake]. Optional.\n- **LastBlockHeight**: The height of the blockchain (number of commits) on this\n  node. Taken from persisted consensus state. Required.\n- **LastBlockAppHash**: The SHA256 hash of the last committed application state\n  on this node. Taken from persisted consensus state. Required.\n\n[versionhandshake]: https://github.com/tendermint/tendermint/blob/master/docs/spec/p2p/peer.md#tendermint-version-handshake\n\nSee [Initialization](#initialization).\n\n### SetOption\n\nRequestSetOption\n\n- **Key**: An arbitrary string defining the option key.\n- **Value**: An arbitrary string defining the option value.\n\nResponseSetOption\n\n- **Code**: Response code; zero for OK, non-zero for error. Required.\n- **Log**: Arbitrary string containing non-deterministic data intended for\n  literal output via the application's logger. Optional.\n- **Info**: Arbitrary string containing non-deterministic data in addition to\n  log. Optional.\n\nSee [Initialization](#initialization).\n\n### InitChain\n\nRequestInitChain\n\n- **Time**: The timestamp in the genesis file.\n- **ChainId**: The chain ID string in the genesis file.\n- **ConsensusParams**: Parameters that govern Tendermint's consensus behavior.\n- **Validators**: The current set of validator nodes in the network.\n- **AppStateBytes**: Initial state, provided in the genesis file, that a node\n  starting for the first time may need to make itself ready to receive\n  transactions.\n\nResponseInitChain\n\n- **ConsensusParams**: Any changes to the proposed consensus parameters that\n  this node would like to propose. Optional.\n- **Validators**: Any changes to the set of validators that this node would like\n  to propose. Optional.\n\nSee [Initialization](#initialization). ConsensusParams and Validators are beyond\nthe scope of this document, see the official documentation for details.\n\n### Query\n\nRequestQuery\n\n- **Data**: The byte array from the user request.\n- **Path**: The path string from the user request.\n- **Height**: The desired height of the blockchain (in effect, the version of\n  the state) against which the query should be run. A height of zero means the\n  most recent state. To support this parameter, state needs to be implemented\n  using a version-aware data structure, e.g. [this IAVL tree][iavl].\n- **Prove**: If true, include a Merkle proof of the query results in the\n  response.\n\n[iavl]: https://github.com/tendermint/iavl\n\nResponseQuery\n\n- **Code**: Response code; zero for OK, non-zero for error. Required.\n- **Log**: Arbitrary string containing non-deterministic data intended for\n  literal output via the application's logger. Optional.\n- **Info**: Arbitrary string containing non-deterministic data in addition to\n  log. Optional.\n- **Index**: Related to the Merkle proof, if requested. Optional.\n- **Key**: A byte array containing the key that's returned. Optional.\n- **Value**: A byte array containing the data of the query response. Optional.\n- **Proof**: A byte array containing the Merkle proof of the query, if\n  requested. Optional.\n- **Height**: The height of the blockchain (in effect, the version of the state)\n  against which the query was run. Optional.\n\nSee [Reading application state](#reading-application-state) and\n[Connections](#connections). Note that our demo application doesn't implement\nHeight, Prove, or Proof. Merkle proofs are beyond the scope of this document,\nsee the official documentation for details.\n\nQuery will probably want to read consensus state, for the most reliable and\nup-to-date view of the world. In some cases, it may want to read committed\nstate, for example if a application-specific flag is defined in the query body,\nin order to return data that is guaranteed to be persistent in case of node\nfailure. Or, it may want to read mempool state, to yield the most bleeding-edge\nversion of events, with some risk of that state being rendered invalid in the\nfuture. These are all application decisions.\n\n### BeginBlock\n\nRequestBeginBlock\n\n- **Hash**: The hash of the block.\n- **Header**: The header details for the block.\n- **LastCommitInfo**: Details about the most recent (previous) commit.\n- **ByzantineValidators**: Evidence of malicious validators, if any, during the\n  most recent (previous) commit.\n\nResponseBeginBlock\n\n- **Tags**: A set of key-value pairs that can be used to denote properties about\n  this block, which can later be searched. Optional.\n\nSee [Writing application state](#writing-application-state). See also\n[Application Development Guide: BeginBlock][beginblock].\n\n[beginblock]: https://www.tendermint.com/docs/app-dev/app-development.html#beginblock\n\n### CheckTx\n\nThe only argument is an opaque byte slice, proxied without modification from the\nRPC connection's BroadcastTx methods to the application.\n\nResponseCheckTx\n\n- **Code**: Response code; zero for OK, non-zero for error. Required.\n- **Data**: Arbitrary byte array containing any result from the transaction.\n  Optional.\n- **Log**: Arbitrary string containing non-deterministic data intended for\n  literal output via the application's logger. Optional.\n- **Info**: Arbitrary string containing non-deterministic data in addition to\n  log. Optional.\n- **GasWanted**: Amount of gas request for the transaction. Optional.\n- **GasUsed**: Amount of gas consumed by the transaction. Optional.\n- **Tags**: A set of key-value pairs that can be used to denote properties about\n  this transaction, which can later be searched. Optional.\n\nSee [Connections](#connections). See also [Mempool Connection][mempoolconn].\nObserve that CheckTx has exactly the same signature as DeliverTx; the only\ndifference is how to interpret the transaction body, i.e. which state (if any)\nto update.\n\n[mempoolconn]: https://www.tendermint.com/docs/app-dev/app-development.html#mempool-connection\n\n### DeliverTx\n\nThe only argument is an opaque byte slice, proxied without modification from the\nRPC connection BroadcastTx methods to the application.\n\nResponseDeliverTx\n\n- **Code**: Response code; zero for OK, non-zero for error. Required.\n- **Data**: Arbitrary byte array containing any result from the transaction.\n  Optional.\n- **Log**: Arbitrary string containing non-deterministic data intended for\n  literal output via the application's logger. Optional.\n- **Info**: Arbitrary string containing non-deterministic data in addition to\n  log. Optional.\n- **GasWanted**: Amount of gas request for the transaction. Optional.\n- **GasUsed**: Amount of gas consumed by the transaction. Optional.\n- **Tags**: A set of key-value pairs that can be used to denote properties about\n  this transaction, which can later be searched. Optional.\n\nSee [Writing application state](#writing-application-state) and\n[Connections](#connections). See also [DeliverTx][delivertx]. Observe that\nDeliverTx has exactly the same signature as CheckTx; the only difference is how\nto interpret the transaction body, i.e. which state (if any) to update.\n\n[delivertx]: https://www.tendermint.com/docs/app-dev/app-development.html#delivertx\n\n### EndBlock\n\nRequestEndBlock\n\n- **Height**: The height of the block.\n\nResponseEndBlock\n\n- **ValidatorUpdates**: Updates to the set of validators, if any. Optional.\n- **ConsensusParamsUpdate**: Updates to the consensus parameters, if any.\n  Optional.\n- **Tags**: A set of key-value pairs that can be used to denote properties about\n  this block, which can later be searched. Optional.\n\nSee [Writing application state](#writing-application-state) and\n[Connections](#connections). See also [EndBlock][endblock]. \n\n[endblock]: https://www.tendermint.com/docs/app-dev/app-development.html#endblock\n\n### Commit\n\nCommit requests have no parameters.\n\nResponseCommit\n\n- **Data**: A deterministic (Merkle) hash of the state root of the application.\n  Required.\n\nSee [Writing application state](#writing-application-state) and\n[Connections](#connections). See also [Commit][commit]. It's expected that the\napplication persist its state to disk during commit.\n\n[commit]: https://www.tendermint.com/docs/app-dev/app-development.html#commit\n\n\n## Our demo application\n\nThe code for the ABCI application, implementing our key-value store with compare-and-swap semantics,\nis available in [internal/cas/application.go][application]. The code for the state layer\nis available in [internal/cas/state.go][state].\n\n[application]: https://github.com/6thc/tendermint-cas-demo/blob/master/internal/cas/application.go\n[state]: https://github.com/6thc/tendermint-cas-demo/blob/master/internal/cas/state.go\n\n\n## The abci-cli\n\nOnce you have a type implementing the ABCI application interface, you can do\nbasic tests by wrapping it with an [abci/server.NewServer][abcinewserver] and\ncalling it with a tool called [`abci-cli`][abcicli]. \n\n[abcinewserver]: https://godoc.org/github.com/tendermint/tendermint/abci/server#NewServer\n[abcicli]: https://tendermint.com/docs/app-dev/abci-cli.html\n\nThe code to mount your application will look something like this.\n\n```go\nfunc main() {\n\tapp := newMyApplication()\n\tserver, err := server.NewServer(\"127.0.0.1:8080\", \"socket\", app)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tserver.Start()\n}\n```\n\nSee [the `abci-cli` documentation][abcicli] for more details.\n\n\n## System architecture\n\nNow you have a working ABCI application. How can you connect it to the\nTendermint machinery, so that it can communicate with other, identical nodes in\na network?\n\nRecall the original [Tendermint architecture diagram][diagram]. The Tendermint\nnode, the green box, handles the heavy work of consensus. The validator signer,\nthe purple box, can also be provided by Tendermint, and validates blocks, moving\nconsensus forward. Our ABCI application, the blue box, is connected to the node\nexclusively. And our user API, in the diagram represented by Cosmos Voyager and\nthe Light Client Daemon, is also connected only to the node.\n\nThese are the logical components, and they can be deployed in different physical\narrangements depending on your needs. In the diagram, the Tendermint core node,\nthe ABCI application, and the validator signer are all co-located on the same\ncircle, representing a full node. The lines between them indicate communication,\nbut that communication can occur in different ways. The components can be built\ninto the same binary, executed as a single process, and the communication occur\nexclusively in-memory. Or, the components can be built into separate binaries,\nexecuted as different processes on the same machine, and the communication occur\nover e.g. UNIX domain sockets. Or, the components could be deployed to different\nphysical machines, and the communication occur over e.g. TCP connections. \n\nSimilarly, in the diagram, the user is expected to interact with the network by\nusing the Cosmos Voyager web application, deployed adjacent to a Light Client\nDaemon on the user's machine, speaking REST (HTTP) to each other. The Light\nClient Daemon connects to a Tendermint core node over HTTP, and performs the\ne.g. ABCIQuery and BroadcastTx requests that way.\n\nThe diagram has things arranged in this way, but you don't necessarily need to\ncopy it. For example, a more secure deployment might move the validators onto\ntheir own single-purpose machines, heavily firewalled from the rest of the\ninternet, with only a single connection to a different, larger set of full\nnodes, running only Tendermint core and your ABCI application. \n\nFor our demo, we'll model the user API as a separate HTTP API, but built into\nthe same binary as all the other components, and run in the same process. The\nHTTP API is defined in [cmd/tendermint-cas-demo/cas_api.go][casapi], and all of\nthe components are wired together in [cmd/tendermint-cas-demo/main.go][main].\n\n[casapi]: https://github.com/6thc/tendermint-cas-demo/blob/master/cmd/tendermint-cas-demo/cas_api.go\n[main]: https://github.com/6thc/tendermint-cas-demo/blob/master/cmd/tendermint-cas-demo/main.go\n\n\n## Operations\n\nThe Tendermint node requires quite a lot of configuration to successfully start,\nincluding several files in well-defined locations on disk, such as the JSON\ngenesis file, a TOML configuration file, and cryptographic keys for the node\nitself and its validators. The helper scripts [bootstrap_1][bootstrap1] and\n[bootstrap_3][bootstrap3] create these file structures for one- and three-node\nclusters on the local machine respectively. Studying them should give you a\ngood start toward scripting your own deployment.\n\n[bootstrap1]: https://github.com/6thc/tendermint-cas-demo/blob/master/bootstrap_1.sh\n[bootstrap3]: https://github.com/6thc/tendermint-cas-demo/blob/master/bootstrap_3.sh\n\n\n## Building and running\n\nBuilding this repository requires [a working Go installation](https://golang.org).\nMost operating system package managers ship a reasonably up-to-date version of the\nGo development environment. If you're on a Mac and using Homebrew, I recommend\n\n```\n$ brew install go\n```\n\nClone this repo into the correct location in your GOPATH.\n\n```\n$ mkdir -p $(go env GOPATH)/src/github.com/6thc\n$ cd $(go env GOPATH)/src/github.com/6thc\n$ git clone git@github.com:6thc/tendermint-cas-demo\n$ cd tendermint-cas-demo\n```\n\nThen, build the binary.\n\n```\n$ make\n$ ./tendermint-cas-demo -h\nUSAGE\n  tendermint-cas-demo [flags]\n\nFLAGS\n  -api-addr 127.0.0.1:8081    HTTP API address\n  -app-file db.json           application persistence file\n  -app-verbose false          verbose logging of application information\n  -tendermint-dir tendermint  Tendermint directory (config, data, etc.)\n  -tendermint-verbose false   verbose logging of Tendermint information\n```\n\nYou can also use the Makefile to bootstrap a 1- or 3-node-cluster on your local\nmachine. Once everything is set up, it will print instructions on how to start\nthe cluster.\n\n```\n$ make bootstrap_3\ndownloading tendermint_0.25.0_darwin_amd64.zip...\nArchive:  tendermint_0.25.0_darwin_amd64.zip\ntendermint_0c9c3292c918617624f6f3fbcd95eceade18bcd5_darwin_amd64\n extracting: tendermint\nclearing any old state...\ninitializing three nodes...\ncapturing validators...\ncapturing peer addresses...\nbuilding a common genesis file...\nwriting common genesis file...\nproducing config files...\nnow you can run three nodes\n\n    ./tendermint-cas-demo -api-addr 127.0.0.1:8081 -app-file a.json -tendermint-dir tendermint_a\n    ./tendermint-cas-demo -api-addr 127.0.0.1:8082 -app-file b.json -tendermint-dir tendermint_b\n    ./tendermint-cas-demo -api-addr 127.0.0.1:8083 -app-file c.json -tendermint-dir tendermint_c\n\nother fun things to try\n\n    watch -n1 -- cat ?.json                            # watch state being updated\n    curl -Ss -XPOST 'localhost:8081/x?new=one'         # set x=one\n    curl -Ss -XPOST 'localhost:8082/x?old=one\u0026new=two' # set x=two\n    curl -Ss -XGET  'localhost:8083/x'                 # get x\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F6thc%2Ftendermint-cas-demo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F6thc%2Ftendermint-cas-demo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F6thc%2Ftendermint-cas-demo/lists"}