Commit 9585b23e authored by Cédric F.'s avatar Cédric F.

Add support for BTC

parent 95caf079
......@@ -5,3 +5,25 @@
[TRAPPIST-1](http://www.trappist.one/#about) is a planetary system located 12 parsecs away from the Solar system.
But before we get to explore another planetary system, we can explore our very own blockchain in the Solar system and since the number zero is preceding one:
`TRAPPIST-1 -> TRAPPIST-0 -> TRAPPIST0 -> Trappist0 -> Trappisto`. Yeah I know.
## Development
Dependencies:
```
npm i -g elm
npm i -g elm-test
npm i -g uglify-js
```
Build:
```
make
```
Test:
```
make test
```
/usr/bin/bitcoin-qt -par=-1 -server -txindex -rpcuser=Ijxzsrmsrlqhddgkfj55fgkceMcstsoazikasesuc -rpcpassword=sta2bjbfyqctytqujolcatbvvksjulrUqrzc6wuMc
......@@ -18,7 +18,7 @@ http {
include /etc/nginx/mime.types;
proxy_cache_path nginx/cache/rpc levels=1:2 keys_zone=rpc:10m max_size=10g inactive=365d use_temp_path=off;
proxy_cache_path nginx/cache/rpc levels=1:2 keys_zone=rpc:100m max_size=10g inactive=1y use_temp_path=off;
limit_req_zone $binary_remote_addr zone=default:10m rate=5r/s;
......@@ -79,14 +79,17 @@ http {
proxy_set_header Host $host;
proxy_cache rpc;
proxy_cache_key $request_body;
proxy_cache_key $proxy_host#$request_body;
proxy_cache_methods GET HEAD POST;
proxy_cache_valid any 60s;
proxy_cache_use_stale error timeout;
# proxy_cache_bypass $http_pragma; # set Pragma:no-cache to bypass cache
add_header X-Cache-Status $upstream_cache_status;
proxy_pass https://localhost:9109;
# proxy_pass https://localhost:9109/; # dcrd
proxy_pass http://localhost:8332/; # bitcoind
}
location / {
......
<!DOCTYPE html>
<html lang="en">
<head>
<title>Trappisto - Decred Interactive Block Explorer</title>
<title>Trappisto - Interactive Block Explorer</title>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="Trappisto - Decred Interactive Block Explorer">
<meta name="description" content="Trappisto - Interactive Block Explorer">
<meta name="application-name" content="Trappisto">
<meta property="og:url" content="https://localhost">
<meta property="og:title" content="Trappisto">
<meta property="og:description" content="Trappisto - Decred Interactive Block Explorer">
<meta property="og:description" content="Trappisto - Interactive Block Explorer">
<meta property="og:image" content="https://localhost/assets/images/logo.png">
<link rel="icon" href="assets/images/favicon/favicon.ico">
......@@ -91,7 +91,7 @@
window.addEventListener('load', () => {
const elmAppDiv = document.querySelector('#elm-app');
const elmApp = Elm.Trappisto.embed(elmAppDiv);
const elmApp = Elm.Trappisto.embed(elmAppDiv, { coin: 'BTC' });
elmApp.ports.elmToJs.subscribe((command) => {
console.log('Received command: ' + command);
......
......@@ -6,7 +6,6 @@ import Http exposing (Error)
import Json.Encode as Encode
import Json.Decode as Decode
import Lib.JsonRpc as JsonRpc
import Lib.Decred exposing (..)
import Trappisto.Helpers exposing (..)
import Components.Transaction as Transaction
......@@ -62,26 +61,11 @@ view model =
[ text <| "Only the " ++ toString maxTransactionCount ++ " most recent transactions are shown below." ]
]
else
[ dl [ class "row" ]
(List.concat <|
List.map
(\( label, amount ) ->
case amount of
Nothing ->
[ dt [ class "col-3 text-right" ] [ text label ]
, dd [ class "col-9" ] [ text "?" ]
]
Just amount ->
[ dt [ class "col-3 text-right" ] [ text label ]
, dd [ class "col-9" ] [ text <| dcrAmount amount ]
]
)
[ ( "total received", totalReceived model )
, ( "total sent", totalSent model )
, ( "balance", balance model )
]
)
[ dlBuilder <|
[ ( "total received", Maybe.map dcrAmount <| totalReceived model )
, ( "total sent", Maybe.map dcrAmount <| totalSent model )
, ( "balance", Maybe.map dcrAmount <| balance model )
]
]
in
div [ class "row" ]
......@@ -180,8 +164,8 @@ searchRawTransactions model address =
-- count
, Encode.int maxTransactionCount
-- vinextra
, Encode.int 0
-- vinextra to get prevOut addresses
, Encode.int 1
-- reverse
, Encode.bool True
......
......@@ -10,7 +10,6 @@ import Json.Decode.Pipeline as Pipeline
import Time exposing (Time)
import Lib.TimeExtra as TimeExtra
import Lib.JsonRpc as JsonRpc
import Lib.Decred as Decred
import Trappisto.Helpers exposing (..)
......@@ -20,7 +19,7 @@ type alias Model =
, time : Time
, confirmations : Int
, size : Int
, ticketPrice : Float
, ticketPrice : Maybe Float
, transactions : List String
, tickets : List String
, previousBlockHash : Maybe String
......@@ -37,7 +36,7 @@ initialModel =
, time = -1
, confirmations = -1
, size = -1
, ticketPrice = -1
, ticketPrice = Nothing
, transactions = []
, tickets = []
, previousBlockHash = Nothing
......@@ -53,7 +52,7 @@ type alias JsonModel =
, time : Int
, confirmations : Int
, size : Int
, ticketPrice : Float
, ticketPrice : Maybe Float
, transactions : List String
, tickets : List String
, previousBlockHash : Maybe String
......@@ -70,65 +69,64 @@ type Msg
view : Model -> Html Msg
view model =
div [ class "row align-items-center" ]
[ div [ class "col-2 text-right" ]
[ a
[ class "btn btn-secondary"
, href "javascript:void(0)"
, onClick (GetBlock "000000000000006fa9bf10d4a39d0cbc6ef8dc2f2db3e7841fd33b7ad973811a")
]
[ text "<" ]
let
transactions =
[ dt [ class "col-3 text-right" ] [ text "stake transactions" ]
, dd [ class "col-9" ]
((span [ class "mr-2" ] [ text (toString <| List.length model.tickets) ])
:: (List.map
(\tx ->
a
[ href tx, class "badge badge-secondary ml-1" ]
[ text <| shortHash tx ]
)
model.tickets
)
)
, dt [ class "col-3 text-right" ] [ text "normal transactions" ]
, dd [ class "col-9" ]
((span [ class "mr-2" ] [ text (toString <| List.length model.transactions) ])
:: (List.map
(\tx ->
a
[ href tx, class "badge badge-light ml-1" ]
[ text <| shortHash tx ]
)
model.transactions
)
)
]
, div [ class "col-8" ]
[ div
[ class "card bg-dark" ]
[ h5 [ class "card-header" ]
[ span [] [ text <| "Block " ++ model.hash ]
, dcrDataLink <| "block" ++ model.hash
in
div [ class "row align-items-center" ]
[ div [ class "col-2 text-right" ]
[ a
[ class "btn btn-secondary"
, href "javascript:void(0)"
, onClick (GetBlock "000000000000006fa9bf10d4a39d0cbc6ef8dc2f2db3e7841fd33b7ad973811a")
]
, div [ class "card-body" ]
[ p [ class "card-text" ]
[ dl [ class "row" ]
[ dt [ class "col-3 text-right" ] [ text "height" ]
, dd [ class "col-9" ] [ text <| toString model.height ]
, dt [ class "col-3 text-right" ] [ text "time" ]
, dd [ class "col-9" ] [ text <| TimeExtra.toISOString model.time ]
, dt [ class "col-3 text-right" ] [ text "confirmations" ]
, dd [ class "col-9" ] [ text <| toString model.confirmations ]
, dt [ class "col-3 text-right" ] [ text "size" ]
, dd [ class "col-9" ] [ text <| toString model.size ++ " bytes" ]
, dt [ class "col-3 text-right" ] [ text "ticket price" ]
, dd [ class "col-9" ] [ text <| toString model.ticketPrice ++ " DCR" ]
, dt [ class "col-3 text-right" ] [ text "stake transactions" ]
, dd [ class "col-9" ]
((span [ class "mr-2" ] [ text (toString <| List.length model.tickets) ])
:: (List.map
(\tx ->
a
[ href tx, class "badge badge-secondary ml-1" ]
[ text <| Decred.shortHash tx ]
)
model.tickets
)
)
, dt [ class "col-3 text-right" ] [ text "normal transactions" ]
, dd [ class "col-9" ]
((span [ class "mr-2" ] [ text (toString <| List.length model.transactions) ])
:: (List.map
(\tx ->
a
[ href tx, class "badge badge-light ml-1" ]
[ text <| Decred.shortHash tx ]
)
model.transactions
)
)
[ text "<" ]
]
, div [ class "col-8" ]
[ div
[ class "card bg-dark" ]
[ h5 [ class "card-header" ]
[ span [] [ text <| "Block " ++ model.hash ]
, dcrDataLink <| "block" ++ model.hash
]
, div [ class "card-body" ]
[ p [ class "card-text" ]
[ dlBuilder <|
[ ( "height", Just <| toString model.height )
, ( "time", Just <| TimeExtra.toISOString model.time )
, ( "confirmations", Just <| toString model.confirmations )
, ( "size", Just <| toString model.size ++ " bytes" )
, ( "ticket price", Maybe.map dcrAmount model.ticketPrice )
]
]
]
]
]
]
]
update : Msg -> Model -> ( Model, Cmd Msg )
......@@ -228,7 +226,7 @@ decodeGetBlock =
|> Pipeline.requiredAt [ "result", "time" ] Decode.int
|> Pipeline.requiredAt [ "result", "confirmations" ] Decode.int
|> Pipeline.requiredAt [ "result", "size" ] Decode.int
|> Pipeline.requiredAt [ "result", "sbits" ] Decode.float
|> Pipeline.optionalAt [ "result", "sbits" ] (Decode.maybe Decode.float) Nothing
|> Pipeline.requiredAt [ "result", "tx" ] (Decode.list Decode.string)
|> Pipeline.optionalAt [ "result", "stx" ] (Decode.list Decode.string) []
|> Pipeline.optionalAt [ "result", "previousblockhash" ] (Decode.maybe Decode.string) Nothing
......
......@@ -10,7 +10,6 @@ import Time exposing (Time)
import Regex
import Lib.TimeExtra as TimeExtra
import Lib.JsonRpc as JsonRpc
import Lib.Decred exposing (..)
import Trappisto.Helpers exposing (..)
......@@ -106,12 +105,18 @@ view model =
span [ class "badge badge badge-success" ] [ text type_ ]
formatBlock hash height =
case hash of
Nothing ->
case ( hash, height ) of
( Nothing, Nothing ) ->
span [] [ text "N/A (unconfirmed)" ]
Just hash ->
a [ href hash ] [ text <| toString <| Maybe.withDefault -1 height ]
( Just hash, Nothing ) ->
a [ href hash ] [ text hash ]
( Nothing, Just height ) ->
a [ href <| toString height ] [ text <| toString height ]
( Just hash, Just height ) ->
a [ href hash ] [ text <| toString height ]
formatAddresses scriptPubKey =
div [] <|
......@@ -294,7 +299,7 @@ decodeVIn =
-- no txid for coinbase txs
|> Pipeline.optionalAt [ "txid" ] (Decode.maybe Decode.string |> Decode.andThen zeroToNothing) Nothing
|> Pipeline.optionalAt [ "coinbase" ] (Decode.maybe Decode.string) Nothing
|> Pipeline.requiredAt [ "amountin" ] Decode.float
|> Pipeline.optionalAt [ "amountin" ] Decode.float 0
|> Pipeline.optionalAt [ "blockheight" ] (Decode.maybe Decode.int) Nothing
......
module Lib.Decred exposing (..)
dcrAmount : Float -> String
dcrAmount float =
let
rounded =
-- remove any floating point arithmetic errors
float * 1.0e8 |> round |> toFloat |> (flip (/)) 1.0e8
in
(toString rounded) ++ " DCR"
shortHash : String -> String
shortHash hash =
String.concat [ String.left 2 hash, "...", String.right 2 hash ]
......@@ -6,9 +6,9 @@ import Trappisto.Update exposing (init, update, subscriptions)
import Trappisto.View exposing (view)
main : Program Never Trappisto.Model.Model Trappisto.Model.Msg
main : Program Trappisto.Model.Config Trappisto.Model.Model Trappisto.Model.Msg
main =
Navigation.program Trappisto.Model.NewUrl
Navigation.programWithFlags Trappisto.Model.NewUrl
{ init = init
, view = view
, update = update
......
......@@ -16,6 +16,38 @@ pluralize count singular =
phrase ++ "s"
dcrAmount : Float -> String
dcrAmount float =
let
rounded =
-- remove any floating point arithmetic errors
float * 1.0e8 |> round |> toFloat |> (flip (/)) 1.0e8
in
(toString rounded) ++ " DCR"
shortHash : String -> String
shortHash hash =
String.concat [ String.left 2 hash, "...", String.right 2 hash ]
dlBuilder : List ( String, Maybe String ) -> Html a
dlBuilder list =
let
filter ( label, value ) =
case value of
Nothing ->
Nothing
Just value ->
Just <|
[ dt [ class "col-3 text-right" ] [ text label ]
, dd [ class "col-9" ] [ text value ]
]
in
dl [ class "row" ] (List.concat <| List.filterMap filter list)
dcrDataLink : String -> Html a
dcrDataLink path =
a
......
......@@ -10,6 +10,10 @@ import Components.Block as BlockComponent
import Components.Transaction as TransactionComponent
type alias Config =
{ coin : String }
type Template
= Status
| Address
......@@ -18,7 +22,8 @@ type Template
type alias Model =
{ keys : Keys
{ config : Config
, keys : Keys
, window : Window.Size
, statusModel : StatusComponent.Model
, addressModel : AddressComponent.Model
......@@ -35,7 +40,8 @@ type alias Model =
initialModel : Model
initialModel =
{ keys = Keys False False False False False False
{ config = Config "BTC"
, keys = Keys False False False False False False
, window = Window.Size 0 0
, statusModel = StatusComponent.initialModel
, addressModel = AddressComponent.initialModel
......
......@@ -18,19 +18,22 @@ port elmToJs : String -> Cmd msg
port jsToElm : (String -> msg) -> Sub msg
init : Navigation.Location -> ( Model, Cmd Msg )
init location =
init : Config -> Navigation.Location -> ( Model, Cmd Msg )
init config location =
let
query =
extractQuery location
( model, msg ) =
model =
{ initialModel | config = config, query = query }
( updatedModel, msg ) =
if String.isEmpty query then
update FetchStatus { initialModel | query = query }
update FetchStatus model
else
update (Query query) { initialModel | query = query }
update (Query query) model
in
( model
( updatedModel
, Cmd.batch
[ elmToJs "focus"
, msg
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment