Skip to content

Commit

Permalink
fix(world) remove money issues from any system
Browse files Browse the repository at this point in the history
  • Loading branch information
andriosrobert committed Sep 2, 2020
0 parents commit d352de4
Show file tree
Hide file tree
Showing 17 changed files with 1,002 additions and 0 deletions.
40 changes: 40 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Project related

# Java related
pom.xml
pom.xml.asc
*jar
*.class

# Leiningen
classes/
lib/
native/
checkouts/
target/
.lein-*
repl-port
.nrepl-port
.repl
profiles.clj

# Temp Files
*.orig
*~
.*.swp
.*.swo
*.tmp
*.bak

# OS X
.DS_Store

# Logging
*.log
/logs/

# Builds
out/
build/

dynamodb_data/
19 changes: 19 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FROM clojure AS builder

COPY project.clj /usr/src/app/

WORKDIR /usr/src/app

RUN lein deps

COPY . /usr/src/app/

RUN lein uberjar

FROM openjdk:8-jdk-buster

COPY --from=builder /usr/src/app/target/decimals-0.0.1-standalone.jar /decimals/app.jar

EXPOSE 8910

CMD ["java", "-jar", "/decimals/app.jar"]
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# decimals

```
jq -ncM 'while(true; .+1) | {method: "POST", header: {"x-api-key":["decimals"]}, url: "http://localhost:8890/v1/transactions", body: {amount: ., from: "Bob", to: "Alice", currency: "usd"} | @base64 }' | \
vegeta attack -rate=50/s -lazy -format=json -duration=30s | \
tee results.bin | \
vegeta report
```

FIXME

## Getting Started

1. Start the application: `lein run`
2. Go to [localhost:8080](http://localhost:8080/) to see: `Hello World!`
3. Read your app's source code at src/decimals/service.clj. Explore the docs of functions
that define routes and responses.
4. Run your app's tests with `lein test`. Read the tests at test/decimals/service_test.clj.
5. Learn more! See the [Links section below](#links).


## Configuration

To configure logging see config/logback.xml. By default, the app logs to stdout and logs/.
To learn more about configuring Logback, read its [documentation](http://logback.qos.ch/documentation.html).


## Developing your service

1. Start a new REPL: `lein repl`
2. Start your service in dev-mode: `(def dev-serv (run-dev))`
3. Connect your editor to the running REPL session.
Re-evaluated code will be seen immediately in the service.

### [Docker](https://www.docker.com/) container support

1. Configure your service to accept incoming connections (edit service.clj and add ::http/host "0.0.0.0" )
2. Build an uberjar of your service: `lein uberjar`
3. Build a Docker image: `sudo docker build -t decimals .`
4. Run your Docker image: `docker run -p 8080:8080 decimals`

### [OSv](http://osv.io/) unikernel support with [Capstan](http://osv.io/capstan/)

1. Build and run your image: `capstan run -f "8080:8080"`

Once the image it built, it's cached. To delete the image and build a new one:

1. `capstan rmi decimals; capstan build`


## Links
* [Other Pedestal examples](http://pedestal.io/samples)
52 changes: 52 additions & 0 deletions config/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<!-- Logback configuration. See http://logback.qos.ch/manual/index.html -->
<!-- Scanning is currently turned on; This will impact performance! -->
<configuration scan="true" scanPeriod="10 seconds">
<!-- Silence Logback's own status messages about config parsing
<statusListener class="ch.qos.logback.core.status.NopStatusListener" /> -->

<!-- Simple file output -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- encoder defaults to ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %X{io.pedestal} - %msg%n</pattern>
</encoder>

<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>logs/decimals-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- or whenever the file size reaches 64 MB -->
<maxFileSize>64 MB</maxFileSize>
</rollingPolicy>

<!-- Safely log to the same file from multiple JVMs. Degrades performance! -->
<prudent>true</prudent>
</appender>


<!-- Console output -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoder defaults to ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
<encoder>
<pattern>%-5level %logger{36} %X{io.pedestal} - %msg%n</pattern>
</encoder>
<!-- Only log level INFO and above -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
</appender>


<!-- Enable FILE and STDOUT appenders for all log messages.
By default, only log at level INFO and above. -->
<root level="INFO">
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
</root>

<!-- For loggers in the these namespaces, log at all levels. -->
<logger name="user" level="ALL" />
<!-- To log pedestal internals, enable this and change ThresholdFilter to DEBUG
<logger name="io.pedestal" level="ALL" />
-->

</configuration>
13 changes: 13 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: '3'

volumes:
dynamodb_data:

services:
dynamodb:
image: amazon/dynamodb-local
command: -jar DynamoDBLocal.jar -sharedDb -dbPath /home/dynamodblocal/data/
ports:
- "8000:8000"
volumes:
- ./dynamodb_data:/home/dynamodblocal/data
84 changes: 84 additions & 0 deletions docs/dynamodb.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{
"ModelName": "sequence",
"ModelMetadata": {
"Author": "",
"DateCreated": "Jun 24, 2020, 09:10 PM",
"DateLastModified": "Sep 02, 2020, 02:19 PM",
"Description": "",
"Version": "1.0"
},
"DataModel": [
{
"TableName": "sequence",
"KeyAttributes": {
"PartitionKey": {
"AttributeName": "PK",
"AttributeType": "S"
},
"SortKey": {
"AttributeName": "SK",
"AttributeType": "S"
}
},
"NonKeyAttributes": [
{
"AttributeName": "GSI1_PK",
"AttributeType": "S"
},
{
"AttributeName": "GSI1_SK",
"AttributeType": "S"
},
{
"AttributeName": "currency",
"AttributeType": "S"
},
{
"AttributeName": "timestamp",
"AttributeType": "S"
},
{
"AttributeName": "LSI1_SK",
"AttributeType": "S"
}
],
"GlobalSecondaryIndexes": [
{
"IndexName": "LSI1",
"KeyAttributes": {
"PartitionKey": {
"AttributeName": "PK",
"AttributeType": "S"
},
"SortKey": {
"AttributeName": "LSI1_SK",
"AttributeType": "S"
}
},
"Projection": {
"ProjectionType": "ALL"
}
},
{
"IndexName": "GSI1",
"KeyAttributes": {
"PartitionKey": {
"AttributeName": "GSI1_PK",
"AttributeType": "S"
},
"SortKey": {
"AttributeName": "GSI1_SK",
"AttributeType": "S"
}
},
"Projection": {
"ProjectionType": "ALL"
}
}
],
"DataAccess": {
"MySql": {}
}
}
]
}
36 changes: 36 additions & 0 deletions project.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
(defproject decimals "0.0.1"
:description "An immutable, scalable, minimalist ledger API"
:url "https://github.com/decimals/sequence"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.10.1"]
[io.pedestal/pedestal.service "0.5.8"]
[io.pedestal/pedestal.jetty "0.5.8"]

;; custom
[org.clojure/data.json "1.0.0"]
[com.taoensso/faraday "1.11.0-alpha1"]
[clojure.java-time "0.3.2"]
[clj-http "3.10.1"]
[environ "1.2.0"]
[mount "0.1.16"]
[org.clojure/core.async "1.2.603"]
[metosin/spec-tools "0.10.3"]
[org.clojure/tools.logging "1.1.0"]
[circleci/analytics-clj "0.8.0"]

[ch.qos.logback/logback-classic "1.2.3" :exclusions [org.slf4j/slf4j-api]]
[org.slf4j/jul-to-slf4j "1.7.26"]
[org.slf4j/jcl-over-slf4j "1.7.26"]
[org.slf4j/log4j-over-slf4j "1.7.26"]]
:plugins [[lein-environ "1.2.0"]]
:min-lein-version "2.0.0"
:resource-paths ["config", "resources"]
:profiles {:dev [:dev-common :dev-overrides]
:dev-common {:dependencies [[io.pedestal/pedestal.service-tools "0.5.8"]
[org.clojure/test.check "0.9.0"]
[nubank/mockfn "0.6.1"]]
:aliases {"run-dev" ["trampoline" "run" "-m" "decimals.transport/run-dev"]}}
:dev-overrides {}
:uberjar {:aot [decimals.transport]}}
:main ^{:skip-aot true} decimals.transport)
17 changes: 17 additions & 0 deletions src/decimals/analytics.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
(ns decimals.analytics
(:require [environ.core :refer [env]]
[circleci.analytics-clj.core :as a]
[mount.core :refer [defstate]]
[clojure.tools.logging :as log]))

(defstate analytics :start (try
(a/initialize (env :segment-key))
(catch Exception e (log/warnf "failed to initialize analytics: %s" (.message e)))))

(defn track [context event traits]
(if-let [email (get-in context [:customer :email])]
(a/track analytics email event traits)))

(defn identify [context]
(when-let [email (get-in context [:customer :email])]
(a/identify analytics email {:email email})))
74 changes: 74 additions & 0 deletions src/decimals/balances.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
(ns decimals.balances
(:require [decimals.dynamodb :as db]
[clojure.tools.logging :as log]
[decimals.crypto :as crypto]
[clojure.data.json :as json]
[clojure.spec.alpha :as s]
[java-time :as t]))

(defn ctx->id
([context]
(conj {:public-key (get-in context [:customer :public-key])}
{:currency (get-in context [:tx :currency])}
{:account (get-in context [:request :query-params :account])}))
([context party]
(conj {:public-key (get-in context [:customer :public-key])}
{:currency (get-in context [:tx :currency])}
{:account (get-in context [:tx party])})))

(defn id->pk [id]
(str (:public-key id) "#" (:account id)))

(defn list-balances [query]
(when-let [balances (db/list-balances query)]
balances))

(defn balance [query]
(log/debug "querying " query)
(when-let [balance (db/query-balance (id->pk query) (:currency query))]
(if (s/valid? ::balance-tx balance)
balance
(log/warn "invalid balance in database: " balance (s/explain-data ::balance-tx balance)))))

(defn account->genesis [account party]
(let [acc-id (party account)
currency (:currency account)]
{:id (str acc-id "#" currency)
:public-key (:public-key account)
:party party
:from acc-id
:to acc-id
:amount 0
:currency currency
:date (str (t/instant))
:timestamp (str (- (t/to-millis-from-epoch (t/instant)) 1))
:type :genesis
:balance 0}))

(defn context->account [context party]
(let [tx (:tx context)
cust (:customer context)
party (select-keys tx [party])
currency (select-keys tx [:currency])
pub-key (select-keys cust [:public-key])
account (conj party pub-key currency)]
account))

(defn is-genesis [account]
(= (:public-key account) (:from account)))

(defn genesis [context]
(let [tx (:tx context)
account (context->account context :from)]

(when (is-genesis account)
(if (and (contains? context :from) (contains? (:from context) :balance))

(let [genesis-balance (get-in context [:from :balance])
genesis-funds (assoc genesis-balance :balance (+ (:balance genesis-balance)
(* 2 (:amount tx))))]
genesis-funds)

(let [genesis-tx (account->genesis account :from)
genesis-funds (assoc genesis-tx :balance (* 2 (:amount tx)))]
genesis-funds)))))
Loading

0 comments on commit d352de4

Please sign in to comment.