From 775b015173a6b8f9fb11adeabe8f47d7e64ee70b Mon Sep 17 00:00:00 2001 From: Zach Date: Thu, 17 May 2018 01:57:28 -0400 Subject: [PATCH] docs: add diagram, closes #1565 (#1577) --- docs/app-architecture.rst | 40 +++++++++++++++---------- docs/assets/tm-application-example.png | Bin 0 -> 26691 bytes 2 files changed, 24 insertions(+), 16 deletions(-) create mode 100644 docs/assets/tm-application-example.png diff --git a/docs/app-architecture.rst b/docs/app-architecture.rst index e7a0d0e74..4a7c414ec 100644 --- a/docs/app-architecture.rst +++ b/docs/app-architecture.rst @@ -66,15 +66,14 @@ and possibly await a response). And one method to query app-specific data from the ABCI application. Pros: -* Server code already written -* Access to block headers to validate merkle proofs (nice for light clients) -* Basic read/write functionality is supported + +- Server code already written +- Access to block headers to validate merkle proofs (nice for light clients) +- Basic read/write functionality is supported Cons: -* Limited interface to app. All queries must be serialized into -[]byte (less expressive than JSON over HTTP) and there is no way to push -data from ABCI app to the client (eg. notify me if account X receives a -transaction) + +- Limited interface to app. All queries must be serialized into []byte (less expressive than JSON over HTTP) and there is no way to push data from ABCI app to the client (eg. notify me if account X receives a transaction) Custom ABCI server ~~~~~~~~~~~~~~~~~~ @@ -92,14 +91,19 @@ store. For "reads", we can do any queries we wish that are supported by our architecture, using any web technology that is useful. The general architecture is shown in the following diagram: -Pros: \* Separates application logic from blockchain logic \* Allows -much richer, more flexible client-facing API \* Allows pub-sub, watching -certain fields, etc. +.. figure:: assets/tm-application-example.png + +Pros: + +- Separates application logic from blockchain logic +- Allows much richer, more flexible client-facing API +- Allows pub-sub, watching certain fields, etc. -Cons: \* Access to ABCI app can be dangerous (be VERY careful not to -write unless it comes from the validator node) \* No direct access to -the blockchain headers to verify tx \* You must write your own API (but -maybe that's a pro...) +Cons: + +- Access to ABCI app can be dangerous (be VERY careful not to write unless it comes from the validator node) +- No direct access to the blockchain headers to verify tx +- You must write your own API (but maybe that's a pro...) Hybrid solutions ~~~~~~~~~~~~~~~~ @@ -108,9 +112,13 @@ Likely the least secure but most versatile. The client can access both the tendermint node for all blockchain info, as well as a custom app server, for complex queries and pub-sub on the abci app. -Pros: All from both above solutions +Pros: + +- All from both above solutions + +Cons: -Cons: Even more complexity; even more attack vectors (less +- Even more complexity; even more attack vectors (less security) Scalability diff --git a/docs/assets/tm-application-example.png b/docs/assets/tm-application-example.png new file mode 100644 index 0000000000000000000000000000000000000000..47d4e928cb7bc9c696814fa01f7b62cd37e1d7c0 GIT binary patch literal 26691 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 H?9cxINgZ4^ literal 0 HcmV?d00001