Explorar o código

script/research/blockchain-explorer/site: rest pages added, cleaned up code, licencing added

skoupidi %!s(int64=2) %!d(string=hai) anos
pai
achega
0890ebf458

+ 2 - 1
script/research/blockchain-explorer/site/README.md

@@ -18,7 +18,8 @@ First we start a `darkfid` localnet:
 
 It is advised to shutdown the `minerd` daemon after couple of blocks, to not waste resources.
 
-Now we start a `blockchain-explorer` daemon:
+Update the `blockchain-explorer` configuration to the localnet `darkfid` JSON-RPC endpoint
+and start a the daemon:
 
 ```
 % cd script/research/blockchain-explorer

+ 50 - 8
script/research/blockchain-explorer/site/app.py

@@ -1,17 +1,59 @@
-from flask import Flask, render_template
+# This file is part of DarkFi (https://dark.fi)
+#
+# Copyright (C) 2020-2024 Dyne.org foundation
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-import rpc
+import asyncio
+from flask import Flask, request, render_template
 
-# DarkFi blockchain-explorer daemon JSON-RPC configuration
-# TODO: make this configurable
-URL = "127.0.0.1"
-PORT = 14567
+import rpc
 
 app = Flask(__name__)
 
 @app.route('/')
 async def index():
-    blocks = await rpc.get_last_n_blocks(10, URL, PORT)
-    stats = await rpc.get_basic_statistics(URL, PORT)
+    blocks = await rpc.get_last_n_blocks("10")
+    stats = await rpc.get_basic_statistics()
     return render_template('index.html', blocks=blocks, stats=stats)
 
+@app.route('/search', methods=['GET', 'POST'])
+async def search():
+    search_hash = request.args.get('search_hash', '')
+    try:
+        block = await rpc.get_block(search_hash)
+        transactions = await rpc.get_block_transactions(search_hash)
+        return render_template('block.html', block=block, transactions=transactions)
+    except Exception:
+        transaction = await rpc.get_transaction(search_hash)
+        return render_template('transaction.html', transaction=transaction)
+
+@app.route('/block/<header_hash>')
+async def block(header_hash):
+    block = await rpc.get_block(header_hash)
+    transactions = await rpc.get_block_transactions(header_hash)
+    return render_template('block.html', block=block, transactions=transactions)
+
+@app.route('/transaction/<transaction_hash>')
+async def transaction(transaction_hash):
+    transaction = await rpc.get_transaction(transaction_hash)
+    return render_template('transaction.html', transaction=transaction)
+
+@app.errorhandler(404)
+def page_not_found(e):
+    return render_template('404.html'), 404
+
+@app.errorhandler(500)
+def page_not_found(e):
+    return render_template('500.html'), 500

+ 44 - 12
script/research/blockchain-explorer/site/rpc.py

@@ -1,8 +1,28 @@
+# This file is part of DarkFi (https://dark.fi)
+#
+# Copyright (C) 2020-2024 Dyne.org foundation
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
 import asyncio, json, random
 from flask import abort
 
-# TODO have a single channel for the whole app
-# Class representing the channel with the JSON-RPC server.
+# DarkFi blockchain-explorer daemon JSON-RPC configuration
+URL = "127.0.0.1"
+PORT = 14567
+
+# Class representing the channel with the JSON-RPC server
 class Channel:
     def __init__(self, reader, writer):
         self.reader = reader
@@ -40,10 +60,9 @@ async def create_channel(server_name, port):
     channel = Channel(reader, writer)
     return channel
 
-
 # Execute a request towards the JSON-RPC server
-async def query(method, params, server_name, port):
-    channel = await create_channel(server_name, port)
+async def query(method, params):
+    channel = await create_channel(URL, PORT)
     request = {
         "id": random.randint(0, 2**32),
         "method": method,
@@ -55,21 +74,34 @@ async def query(method, params, server_name, port):
     response = await channel.receive()
     # Closed connect returns None
     if response is None:
-        print("error: connection with server was closed", file=sys.stderr)
+        print("error: connection with server was closed")
         abort(500)
 
+    # Erroneous query is handled with not found
     if "error" in response:
         error = response["error"]
         errcode, errmsg = error["code"], error["message"]
-        print(f"error: {errcode} - {errmsg}", file=sys.stderr)
-        abort(500)
+        print(f"error: {errcode} - {errmsg}")
+        abort(404)
 
     return response["result"]
 
 # Retrieve last n blocks from blockchain-explorer daemon
-async def get_last_n_blocks(n, server_name, port):
-    return await query("blocks.get_last_n_blocks", [str(n)], server_name, int(port))
+async def get_last_n_blocks(n: str):
+    return await query("blocks.get_last_n_blocks", [n])
 
 # Retrieve basic statistics from blockchain-explorer daemon
-async def get_basic_statistics(server_name, port):
-    return await query("statistics.get_basic_statistics", [], server_name, int(port))
+async def get_basic_statistics():
+    return await query("statistics.get_basic_statistics", [])
+
+# Retrieve the block information of given header hash from blockchain-explorer daemon
+async def get_block(header_hash: str):
+    return await query("blocks.get_block_by_hash", [header_hash])
+
+# Retrieve the transactions of given block header hash from blockchain-explorer daemon
+async def get_block_transactions(header_hash: str):
+    return await query("transactions.get_transactions_by_header_hash", [header_hash])
+
+# Retrieve the transaction information of given hash from blockchain-explorer daemon
+async def get_transaction(transaction_hash: str):
+    return await query("transactions.get_transaction_by_hash", [transaction_hash])

BIN=BIN
script/research/blockchain-explorer/site/static/img/darkfi05.jpg


BIN=BIN
script/research/blockchain-explorer/site/static/img/darkfi25.jpg


+ 14 - 0
script/research/blockchain-explorer/site/static/style.css

@@ -828,3 +828,17 @@ h5 a:hover{
   display: none;
 }
 
+/* Container holding an image with text on top */
+.background-container {
+  position: relative;
+  text-align: center;
+  color: white;
+}
+
+/* Top centered text inside a background-container */
+.top-centered {
+  position: absolute;
+  top: 25%;
+  left: 50%;
+  transform: translate(-50%, -25%);
+}

+ 35 - 0
script/research/blockchain-explorer/site/templates/404.html

@@ -0,0 +1,35 @@
+<!--
+ This file is part of DarkFi (https://dark.fi)
+
+ Copyright (C) 2020-2024 Dyne.org foundation
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <https://www.gnu.org/licenses/>.
+-->
+
+{% extends "base.html" %}
+{% block title %}Not found!{% endblock %}
+
+{% block content %}
+
+    <div class="background-container">
+        <img src="../static/img/darkfi25.jpg" style="width:100%;">
+        <div class="top-centered">
+            <h1 class="display-4 text-white border-l3" style="font-family:'Weissrundgotisch';line-height:.9em;">
+                Is this what you are looking for?
+            </h1>
+        </div>
+    </div>
+    
+{% endblock %}
+

+ 35 - 0
script/research/blockchain-explorer/site/templates/500.html

@@ -0,0 +1,35 @@
+<!--
+ This file is part of DarkFi (https://dark.fi)
+
+ Copyright (C) 2020-2024 Dyne.org foundation
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <https://www.gnu.org/licenses/>.
+-->
+
+{% extends "base.html" %}
+{% block title %}Not found!{% endblock %}
+
+{% block content %}
+
+    <div class="background-container">
+        <img src="../static/img/darkfi05.jpg" style="width:100%;">
+        <div class="top-centered">
+            <h1 class="display-4 text-white border-l3" style="font-family:'Weissrundgotisch';line-height:.9em;">
+                Reality fractured beyond repair!
+            </h1>
+        </div>
+    </div>
+    
+{% endblock %}
+

+ 19 - 0
script/research/blockchain-explorer/site/templates/base.html

@@ -1,3 +1,22 @@
+<!--
+ This file is part of DarkFi (https://dark.fi)
+
+ Copyright (C) 2020-2024 Dyne.org foundation
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <https://www.gnu.org/licenses/>.
+-->
+
 <!DOCTYPE html>
 <html lang="en">
 

+ 55 - 0
script/research/blockchain-explorer/site/templates/block.html

@@ -0,0 +1,55 @@
+<!--
+ This file is part of DarkFi (https://dark.fi)
+
+ Copyright (C) 2020-2024 Dyne.org foundation
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <https://www.gnu.org/licenses/>.
+-->
+
+{% extends "base.html" %}
+{% block title %}Block {{ block[0] }}{% endblock %}
+
+{% block content %}
+
+    <div class="container-fluid pl-5 pb-5 pr-5 title-block" style="margin-top:90px;">
+	    <h1 class="display-4 text-white border-l3" style="font-family:'Weissrundgotisch';line-height:.9em;">Block {{ block[0] }}</h1>
+	</div>
+
+    <div class="row m-0 border-secondary border-top">
+        <div class="text-white mb-0 border-bottom border-secondary lead-text" style="width:100%;">
+            <ul>
+                <li>Version: {{ block[1] }}</li>
+                <li>Previous: <a href="../block/{{ block[2] }}">{{ block[2] }}</a></li>
+                <li>Height: {{ block[3] }}</li>
+                <li>Timestamp: {{ block[4] }}</li>
+                <li>Nonce: {{ block[5] }}</li>
+                <li>Root: {{ block[6] }}</li>
+                <li>Signature: {{ block[7] }}</li>
+            </ul>
+        </div>
+    </div>
+
+    <div class="row m-0 border-secondary border-top">
+        <div class="text-white mb-0 border-bottom border-secondary lead-text" style="width:100%;">
+            <h2 class="display-8 text-white border-l3" style="font-family:'Weissrundgotisch';line-height:.9em;">Transactions</h2>
+            <ul>
+	            {% for transaction in transactions %}
+                    <li><a href="../transaction/{{ transaction[0] }}">{{ transaction[0] }}</a></li>
+                {% endfor %}
+            </ul>
+        </div>
+    </div>
+    
+{% endblock %}
+

+ 56 - 27
script/research/blockchain-explorer/site/templates/index.html

@@ -1,38 +1,67 @@
+<!--
+ This file is part of DarkFi (https://dark.fi)
+
+ Copyright (C) 2020-2024 Dyne.org foundation
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <https://www.gnu.org/licenses/>.
+-->
+
 {% extends "base.html" %}
 {% block title %}Explorer{% endblock %}
 
 {% block content %}
+
     <div class="container-fluid pl-5 pb-5 pr-5 title-block" style="margin-top:90px;">
-	    <h1 class="display-4 text-white border-l3" style="font-family:'Weissrundgotisch';line-height:.9em;">Explorer</h1>
-	</div>
-
-    <div class="row m-0 border-secondary border-top"/>
-    <div class="col-md-7 text-white mb-0 border-right border-bottom border-secondary lead-text">
-        <h2 class="display-8 text-white border-l3" style="font-family:'Weissrundgotisch';line-height:.9em;">Latest Blocks</h2>
-	    <table>
-            <tr style="text-align: center;">
-                <th>Height</th>
-                <th>Hash</th>
-                <th>timestamp</th>
-            </tr>
-            {% for block in blocks %}
+        <h1 class="display-4 text-white border-l3" style="font-family:'Weissrundgotisch';line-height:.9em;">Explore</h1>
+        <div class="search-container">
+            <form action="/search">
+                <input type="text" placeholder="Search for a block or transaction.." name="search_hash">
+            </form>
+      </div>
+    </div>
+
+    <div class="row m-0 border-secondary border-top">
+        <div class="text-white mb-0 border-bottom border-secondary lead-text" style="width:100%;">
+            <h2 class="display-8 text-white border-l3" style="font-family:'Weissrundgotisch';line-height:.9em;">Latest Blocks</h2>
+           <table style="width:100%;">
                 <tr>
-                    <td>{{ block[3] }}</td>
-                    <td>{{ block[0] }}</td>
-                    <td>{{ block[4] }}</td>
+                    <th>Height</th>
+                    <th>Hash</th>
+                    <th>Timestamp</th>
                 </tr>
-            {% endfor %}
-        </table>
+                {% for block in blocks %}
+                    <tr>
+                        <td>{{ block[3] }}</td>
+                        <td><a href="block/{{ block[0] }}">{{ block[0] }}</a></td>
+                        <td>{{ block[4] }}</td>
+                    </tr>
+                {% endfor %}
+            </table>
+        </div>
     </div>
-    <div class="col-md-5 text-white m-0 border-secondary border-bottom lead-text">
-        <h2 class="display-8 text-white border-l3" style="font-family:'Weissrundgotisch';line-height:.9em;">Statistics</h2>
-        <ul>
-            <li>Height: {{ stats[0] }}</li>
-            <li>Epoch: {{ stats[1] }}</li>
-            <li>Last block: {{ stats[2] }}</li>
-            <li>Total blocks: {{ stats[3] }}</li>
-            <li>Total transactions: {{ stats[4] }}</li>
-        </ul>
+
+    <div class="row m-0 border-secondary border-top">
+        <div class="text-white mb-0 border-bottom border-secondary lead-text" style="width:100%;">
+            <h2 class="display-8 text-white border-l3" style="font-family:'Weissrundgotisch';line-height:.9em;">Statistics</h2>
+            <ul>
+                <li>Height: {{ stats[0] }}</li>
+                <li>Epoch: {{ stats[1] }}</li>
+                <li>Last block: <a href="block/{{ stats[2] }}">{{ stats[2] }}</a></li>
+                <li>Total blocks: {{ stats[3] }}</li>
+                <li>Total transactions: {{ stats[4] }}</li>
+            </ul>
+        </div>
     </div>
     
 {% endblock %}

+ 39 - 0
script/research/blockchain-explorer/site/templates/transaction.html

@@ -0,0 +1,39 @@
+<!--
+ This file is part of DarkFi (https://dark.fi)
+
+ Copyright (C) 2020-2024 Dyne.org foundation
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <https://www.gnu.org/licenses/>.
+-->
+
+{% extends "base.html" %}
+{% block title %}Transaction {{ transaction[0] }}{% endblock %}
+
+{% block content %}
+
+    <div class="container-fluid pl-5 pb-5 pr-5 title-block" style="margin-top:90px;">
+	    <h1 class="display-4 text-white border-l3" style="font-family:'Weissrundgotisch';line-height:.9em;">Transaction {{ transaction[0] }}</h1>
+	</div>
+
+    <div class="row m-0 border-secondary border-top">
+        <div class="text-white mb-0 border-bottom border-secondary lead-text" style="width:100%;">
+            <ul>
+                <li>Block: <a href="../block/{{ transaction[1] }}">{{ transaction[1] }}</a></li>
+                <li>Payload: {{ transaction[2] }}</li>
+            </ul>
+        </div>
+    </div>
+    
+{% endblock %}
+