mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 18:02:24 +00:00
Block 0 and txs being written into db, UI modifications
This commit is contained in:
parent
573cb28a43
commit
fd296e83e3
23 changed files with 592 additions and 51 deletions
|
|
@ -61,8 +61,6 @@ func GetAllTransactions(w http.ResponseWriter, r *http.Request) {
|
|||
func GetAccount(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
address := vars["address"]
|
||||
//addressBytes := []byte(address)
|
||||
fmt.Println("ADDRESS FROM ROUTE", address)
|
||||
connStr := "user=postgres dbname=shyftdb sslmode=disable"
|
||||
blockExplorerDb, err := sql.Open("postgres", connStr)
|
||||
if err != nil {
|
||||
|
|
@ -82,6 +80,29 @@ func GetAccount(w http.ResponseWriter, r *http.Request) {
|
|||
fmt.Fprintln(w, getAccountBalance)
|
||||
}
|
||||
|
||||
// GetAccount gets balance
|
||||
func GetAccountTxs(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
address := vars["address"]
|
||||
connStr := "user=postgres dbname=shyftdb sslmode=disable"
|
||||
blockExplorerDb, err := sql.Open("postgres", connStr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
getAccountTxs := shyftdb.GetAccountTxs(blockExplorerDb, address)
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
fmt.Fprintln(w, getAccountTxs)
|
||||
}
|
||||
|
||||
// GetAllAccounts gets balances
|
||||
func GetAllAccounts(w http.ResponseWriter, r *http.Request) {
|
||||
connStr := "user=postgres dbname=shyftdb sslmode=disable"
|
||||
|
|
@ -140,6 +161,16 @@ func GetAllBlocks(w http.ResponseWriter, r *http.Request) {
|
|||
fmt.Fprintln(w, block3)
|
||||
}
|
||||
|
||||
//func GetRecentBlock(w http.ResponseWriter, r *http.Request) {
|
||||
// connStr := "user=postgres dbname=shyftdb sslmode=disable"
|
||||
// blockExplorerDb, err := sql.Open("postgres", connStr)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
//
|
||||
//}
|
||||
|
||||
//GetInternalTransactions gets internal txs
|
||||
func GetInternalTransactions(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,12 @@ var routes = Routes{
|
|||
"/api/get_account/{address}",
|
||||
GetAccount,
|
||||
},
|
||||
Route{
|
||||
"GetAccountTxs",
|
||||
"GET",
|
||||
"/api/get_account_txs/{address}",
|
||||
GetAccountTxs,
|
||||
},
|
||||
Route{
|
||||
"GetAllAccounts",
|
||||
"GET",
|
||||
|
|
@ -51,6 +57,12 @@ var routes = Routes{
|
|||
"/api/get_transaction/{txHash}",
|
||||
GetTransaction,
|
||||
},
|
||||
Route{
|
||||
Name: "GetRecentBlock",
|
||||
Method: "GET",
|
||||
Pattern: "/api/get_recent_block",
|
||||
HandlerFunc: GetRecentBlock,
|
||||
},
|
||||
Route{
|
||||
"GetInternalTransactions",
|
||||
"GET",
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/syndtr/goleveldb/leveldb/util"
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -168,7 +169,13 @@ func initGenesis(ctx *cli.Context) error {
|
|||
if err != nil {
|
||||
utils.Fatalf("Failed to open database: %v", err)
|
||||
}
|
||||
_, hash, err := core.SetupGenesisBlock(chaindb, genesis, nil)
|
||||
// @NOTE:shyft instantiate BlockExplorerDB here
|
||||
connStr := "user=postgres dbname=shyftdb sslmode=disable"
|
||||
blockExplorerDb, err := sql.Open("postgres", connStr)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
_, hash, err := core.SetupGenesisBlock(chaindb, genesis, blockExplorerDb)
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to write genesis block: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ import (
|
|||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"database/sql"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
//go:generate gencodec -type Genesis -field-override genesisSpecMarshaling -out gen_genesis.go
|
||||
|
|
@ -140,7 +142,7 @@ func (e *GenesisMismatchError) Error() string {
|
|||
|
||||
//WriteShyftGen writes the genesis block to Shyft db
|
||||
//@NOTE:SHYFT
|
||||
func WriteShyftGen(sqldb *sql.DB, gen *Genesis) {
|
||||
func WriteShyftGen(sqldb *sql.DB, gen *Genesis, block *types.Block) {
|
||||
if sqldb == nil {
|
||||
log.Info("Initializing Shyft Postgres DB")
|
||||
connStr := "user=postgres dbname=shyftdb sslmode=disable"
|
||||
|
|
@ -156,18 +158,80 @@ func WriteShyftGen(sqldb *sql.DB, gen *Genesis) {
|
|||
switch {
|
||||
case err == sql.ErrNoRows:
|
||||
for k, v := range gen.Alloc {
|
||||
number := block.Header().Number.String()
|
||||
gasUsed := block.Header().GasUsed
|
||||
gasLimit := block.Header().GasLimit
|
||||
addr := k.String()
|
||||
txCountAccount := v.Nonce +1
|
||||
i, err := strconv.ParseInt(block.Time().String(), 10, 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
age := time.Unix(i, 0)
|
||||
Genesis := []string{"GENESIS_", addr}
|
||||
GENESIS := "GENESIS"
|
||||
txHash := strings.Join(Genesis, addr)
|
||||
|
||||
sqlStatement := `INSERT INTO accounts(addr, balance, txCountAccount) VALUES(($1), ($2), ($3)) RETURNING addr`
|
||||
insertErr := sqldb.QueryRow(sqlStatement, addr, v.Balance.String(), txCountAccount).Scan(&addr)
|
||||
if insertErr != nil {
|
||||
panic(insertErr)
|
||||
}
|
||||
|
||||
var retNonce string
|
||||
sqlGenTxStatement := `INSERT INTO txs(txhash, from_addr, to_addr, blockhash, blockNumber, amount, gas, gasLimit, nonce,age) VALUES(($1), ($2), ($3), ($4), ($5), ($6), ($7), ($8), ($9), ($10)) RETURNING nonce`
|
||||
insertError := sqldb.QueryRow(sqlGenTxStatement, txHash, GENESIS, addr, block.Header().Hash().Hex(), number, v.Balance.String(), gasUsed, gasLimit, txCountAccount, age).Scan(&retNonce)
|
||||
if insertError != nil {
|
||||
panic(insertError)
|
||||
}
|
||||
}
|
||||
default:
|
||||
log.Info("Found Genesis Block")
|
||||
}}}
|
||||
|
||||
func WriteShyftBlockZero(sqldb *sql.DB, block *types.Block) error {
|
||||
if sqldb == nil {
|
||||
log.Info("Initializing Shyft Postgres DB")
|
||||
connStr := "user=postgres dbname=shyftdb sslmode=disable"
|
||||
blockExplorerDb, _ := sql.Open("postgres", connStr)
|
||||
sqldb = blockExplorerDb
|
||||
}
|
||||
|
||||
coinbase := block.Header().Coinbase.String()
|
||||
number := block.Header().Number.String()
|
||||
gasUsed := block.Header().GasUsed
|
||||
gasLimit := block.Header().GasLimit
|
||||
txCount := block.Transactions().Len()
|
||||
uncleCount := len(block.Uncles())
|
||||
parentHash := block.ParentHash().String()
|
||||
uncleHash := block.UncleHash().String()
|
||||
blockDifficulty := block.Difficulty().String()
|
||||
blockSize := block.Size().String()
|
||||
blockNonce := block.Nonce()
|
||||
|
||||
i, err := strconv.ParseInt(block.Time().String(), 10, 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
age := time.Unix(i, 0)
|
||||
|
||||
var response string
|
||||
sqlExistsStatement := `SELECT hash from blocks WHERE hash= ($1)`
|
||||
err = sqldb.QueryRow(sqlExistsStatement, block.Header().Hash().Hex()).Scan(&response)
|
||||
switch {
|
||||
case err == sql.ErrNoRows:
|
||||
sqlStatement := `INSERT INTO blocks(hash, coinbase, number, gasUsed, gasLimit, txCount, uncleCount, age, parentHash, uncleHash, difficulty, size, nonce) VALUES(($1), ($2), ($3), ($4), ($5), ($6), ($7), ($8), ($9), ($10), ($11), ($12),($13)) RETURNING number`
|
||||
qerr := sqldb.QueryRow(sqlStatement, block.Header().Hash().Hex(), coinbase, number, gasUsed, gasLimit, txCount, uncleCount, age, parentHash, uncleHash, blockDifficulty, blockSize, blockNonce).Scan(&number)
|
||||
if qerr != nil {
|
||||
panic(qerr)
|
||||
}
|
||||
case err != nil:
|
||||
panic(err)
|
||||
default:
|
||||
log.Info("Block zero written to DB")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// SetupGenesisBlock writes or updates the genesis block in db.
|
||||
// The block that will be used is:
|
||||
//
|
||||
|
|
@ -185,7 +249,6 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis, sqldb *sql.DB) (*par
|
|||
if genesis != nil && genesis.Config == nil {
|
||||
return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig
|
||||
}
|
||||
|
||||
// Just commit the new block if there is no stored genesis block.
|
||||
stored := GetCanonicalHash(db, 0)
|
||||
if (stored == common.Hash{}) {
|
||||
|
|
@ -194,10 +257,13 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis, sqldb *sql.DB) (*par
|
|||
genesis = DefaultGenesisBlock()
|
||||
} else {
|
||||
log.Info("Writing custom genesis block")
|
||||
//@NOTE:SHYFT WRITE TO DB
|
||||
WriteShyftGen(sqldb, genesis)
|
||||
}
|
||||
block, err := genesis.Commit(db)
|
||||
//@NOTE:SHYFT WRITE TO BLOCK ZERO DB
|
||||
WriteShyftBlockZero(sqldb, block)
|
||||
//@NOTE:SHYFT WRITE TO DB
|
||||
WriteShyftGen(sqldb, genesis, block)
|
||||
|
||||
return genesis.Config, block.Hash(), err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ This project was bootstrapped with [Create React App](https://github.com/faceboo
|
|||
Below you will find some information on how to perform common tasks.<br>
|
||||
You can find the most recent version of this guide [here](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md).
|
||||
|
||||
## TransactionTable of Contents
|
||||
## DetailAccountsTable of Contents
|
||||
|
||||
- [Updating to New Releases](#updating-to-new-releases)
|
||||
- [Sending Feedback](#sending-feedback)
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
export const TxData =
|
||||
[{
|
||||
TxHash: "0x0346d5d68e3de730d40158d6166ed03d7da65587059565fd7fdc4bdaea00d137",
|
||||
Block: 5445429,
|
||||
Age: "1 min ago",
|
||||
From: "0x2fcc226c1dd2f6cd9de10e4054dfd69ed131d030",
|
||||
To: "0xf3586684107ce0859c44aa2b2e0fb8cd8731a15a",
|
||||
Value: "1.99 Ether",
|
||||
TxFee: 0.00197424,
|
||||
}
|
||||
, {
|
||||
TxHash: "0x0346d5d68e3de730d40158d6166ed03d7da65587059565fd7fdc4bdaea00d137",
|
||||
Block: 5445429,
|
||||
Age: "1 min ago",
|
||||
From: "0x2fcc226c1dd2f6cd9de10e4054dfd69ed131d030",
|
||||
To: "0xf3586684107ce0859c44aa2b2e0fb8cd8731a15a",
|
||||
Value: "1.99 Ether",
|
||||
TxFee: 0.00197424,
|
||||
}
|
||||
, {
|
||||
TxHash: "0x0346d5d68e3de730d40158d6166ed03d7da65587059565fd7fdc4bdaea00d137",
|
||||
Block: 5445429,
|
||||
Age: "1 min ago",
|
||||
From: "0x2fcc226c1dd2f6cd9de10e4054dfd69ed131d030",
|
||||
To: "0xf3586684107ce0859c44aa2b2e0fb8cd8731a15a",
|
||||
Value: "1.99 Ether",
|
||||
TxFee: 0.00197424,
|
||||
}];
|
||||
|
||||
|
||||
BIN
shyftBlockExplorerUI/src/components/assets/incoming.png
Normal file
BIN
shyftBlockExplorerUI/src/components/assets/incoming.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
BIN
shyftBlockExplorerUI/src/components/assets/out.png
Normal file
BIN
shyftBlockExplorerUI/src/components/assets/out.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
|
|
@ -27,5 +27,15 @@
|
|||
.Blocks {
|
||||
display: inline-block;
|
||||
font-size: 1rem;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.Accounts {
|
||||
display: inline-block;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.AccountButton {
|
||||
background-color: forestgreen;
|
||||
border-color: forestgreen;
|
||||
}
|
||||
|
|
@ -5,15 +5,21 @@ import { Link } from 'react-router-dom'
|
|||
const home = props => {
|
||||
|
||||
const combinedClasses = ["btn", "btn-primary", classes.BlockButton]
|
||||
const conjoinecdClasses = ["btn", "btn-primary", classes.AccountButton]
|
||||
return (
|
||||
<div className={classes.Home}>
|
||||
<span className={classes.Greeting}>THIS IS A WIP</span>
|
||||
<div className={classes.ButtonNav}>
|
||||
<div className={classes.Transactions}>
|
||||
<Link to="/transactions"><button className="btn btn-primary">Transactions</button></Link>
|
||||
</div>
|
||||
<div className={classes.Blocks}>
|
||||
<Link to="/blocks"><button className={combinedClasses.join(" ")}>Blocks</button></Link>
|
||||
</div>
|
||||
<div className={classes.Accounts}>
|
||||
<Link to="/accounts"><button className={conjoinecdClasses.join(" ")}>Accounts</button></Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
import React from 'react';
|
||||
import classes from '../nav.css';
|
||||
|
||||
const accountsDetailHeader = (props) => {
|
||||
return (
|
||||
<div className={classes.Secondary}>
|
||||
<span className={classes.Transactions}>Account# {props.addr}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default accountsDetailHeader;
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import React from 'react';
|
||||
import classes from '../nav.css';
|
||||
|
||||
const accountsHeader = (props) => {
|
||||
return (
|
||||
<div className={classes.Secondary}>
|
||||
<span className={classes.Transactions}>Accounts</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default accountsHeader;
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
import React, { Component } from 'react';
|
||||
import AccountsTable from './accountsTable';
|
||||
import classes from './accounts.css';
|
||||
import axios from "axios/index";
|
||||
|
||||
class AccountTable extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
data: []
|
||||
};
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
try {
|
||||
const response = await axios.get("http://localhost:8080/api/get_all_accounts")
|
||||
await this.setState({data: response.data});
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const table = this.state.data.map((data, i) => {
|
||||
return <AccountsTable
|
||||
key={`${data.addr}${i}`}
|
||||
Addr={data.Addr}
|
||||
Balance={data.Balance}
|
||||
TxCountAccount={data.TxCountAccount}
|
||||
detailAccountHandler={this.props.detailAccountHandler}
|
||||
/>
|
||||
})
|
||||
|
||||
let combinedClasses = ['responsive-table', classes.table];
|
||||
return (
|
||||
<table className={combinedClasses.join(' ')}>
|
||||
<thead className={classes.tHead}>
|
||||
<tr>
|
||||
<th scope="col">Rank</th>
|
||||
<th scope="col">Address</th>
|
||||
<th scope="col">Balance</th>
|
||||
<th scope="col">Percentage</th>
|
||||
<th scope="col">TxCount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{table}
|
||||
</table>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default AccountTable;
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
.table {
|
||||
border-spacing: 100rem;
|
||||
width: 100%;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.tHead {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: aliceblue;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
td {
|
||||
padding-left: 5px;
|
||||
font-size: .5rem;
|
||||
}
|
||||
|
||||
.addressTag {
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
width: 132px;
|
||||
}
|
||||
|
||||
.ageTag{
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.fromTag{
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.toTag{
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.valueTag{
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import React from 'react';
|
||||
import classes from './accounts.css';
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
const AccountsTable = (props) => {
|
||||
return (
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td className={classes.addressTag}><Link to="/account/detail" onClick={() => props.detailAccountHandler(props.Addr)}>
|
||||
{props.Addr}
|
||||
</Link></td>
|
||||
<td>{props.Balance}</td>
|
||||
<td>12.01%</td>
|
||||
<td>{props.TxCountAccount}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
)
|
||||
}
|
||||
|
||||
export default AccountsTable;
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
import React, { Component } from 'react';
|
||||
import DetailAccountsTable from './detailAccountsTable';
|
||||
import ErrorHandler from "./errorMessage";
|
||||
import classes from './table.css';
|
||||
|
||||
class AccountTransactionTable extends Component {
|
||||
render() {
|
||||
let table;
|
||||
if(this.props.data.length <= 1) {
|
||||
return <ErrorHandler />
|
||||
}else {
|
||||
table = this.props.data.map((data, i) => {
|
||||
return <DetailAccountsTable
|
||||
key={`${data.TxHash}${i}`}
|
||||
age={data.Age}
|
||||
txHash={data.TxHash}
|
||||
blockNumber={data.BlockNumber}
|
||||
to={data.To}
|
||||
from={data.From}
|
||||
value={data.Amount}
|
||||
cost={data.Cost}
|
||||
addr={this.props.addr}
|
||||
detailTransactionHandler={this.props.transactionDetailHandler}
|
||||
/>
|
||||
})
|
||||
}
|
||||
|
||||
let combinedClasses = ['responsive-table', classes.table];
|
||||
return (
|
||||
<table key={this.props.data.TxHash} className={combinedClasses.join(' ')}>
|
||||
<thead className={classes.tHead}>
|
||||
<tr>
|
||||
<th scope="col">TxHash</th>
|
||||
<th scope="col">Block</th>
|
||||
<th scope="col">Age</th>
|
||||
<th scope="col">From</th>
|
||||
<th scope="col"></th>
|
||||
<th scope="col">To</th>
|
||||
<th scope="col">Value</th>
|
||||
<th scope="col">TxFee</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{table}
|
||||
</table>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default AccountTransactionTable;
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import React from 'react';
|
||||
import classes from './table.css';
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
const DetailAccountsTable = (props) => {
|
||||
let flag;
|
||||
if(props.addr === props.to) {
|
||||
flag = true
|
||||
}else {
|
||||
flag = false
|
||||
}
|
||||
return (
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className={classes.addressTag}>
|
||||
<Link to="/transaction/details" onClick={() => props.detailTransactionHandler(props.txHash)}>
|
||||
{props.txHash}</Link>
|
||||
</td>
|
||||
<td>{props.blockNumber}</td>
|
||||
<td>{props.age}</td>
|
||||
<td className={classes.fromTag}>{props.from}</td>
|
||||
<td><div className={ flag ? classes.incoming : classes.out }>{ flag ? "IN" : "OUT" }</div></td>
|
||||
<td>{props.to}</td>
|
||||
<td>{props.value}</td>
|
||||
<td>{props.cost}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
)
|
||||
}
|
||||
|
||||
export default DetailAccountsTable;
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import React from 'react';
|
||||
|
||||
const errorMessage = (props) => {
|
||||
return (
|
||||
<div>
|
||||
THIS IS AN ERROR
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default errorMessage;
|
||||
80
shyftBlockExplorerUI/src/components/table/accounts/table.css
Normal file
80
shyftBlockExplorerUI/src/components/table/accounts/table.css
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
.table {
|
||||
border-spacing: 100rem;
|
||||
width: 100%;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.tHead {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: aliceblue;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.addressTag {
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
width: 132px;
|
||||
}
|
||||
|
||||
.ageTag{
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.fromTag{
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.toTag{
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.valueTag{
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.incoming {
|
||||
height: 25px;
|
||||
width: 35px;
|
||||
border: 1px forestgreen;
|
||||
border-radius: 5px;
|
||||
background-color: forestgreen;
|
||||
color: white;
|
||||
font-size: 1rem;
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.out {
|
||||
height: 25px;
|
||||
width: 35px;
|
||||
border: 1px orangered;
|
||||
border-radius: 5px;
|
||||
background-color: orangered;
|
||||
color: white;
|
||||
font-size: .8rem;
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import React from 'react';
|
||||
import classes from './table.css';
|
||||
import arrow from '../../assets/arrow_right.png';
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
const BlockTable = (props) => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { Component } from 'react';
|
||||
import React from 'react';
|
||||
import classes from './table.css';
|
||||
import arrow from '../../assets/arrow_right.png';
|
||||
import { Link } from 'react-router-dom'
|
||||
|
|
@ -14,7 +14,7 @@ const TransactionTable = (props) => {
|
|||
<td>{props.blockNumber}</td>
|
||||
<td>{props.age}</td>
|
||||
<td className={classes.fromTag}>{props.from}</td>
|
||||
<td><img className={classes.arrow} src={arrow}/></td>
|
||||
<td><img className={classes.arrow} src={arrow} alt="arrow"/></td>
|
||||
<td className={classes.toTag}>{props.to}</td>
|
||||
<td>{props.value}</td>
|
||||
<td>{props.cost}</td>
|
||||
|
|
|
|||
|
|
@ -1,23 +1,37 @@
|
|||
import React, { Component } from "react";
|
||||
import axios from 'axios';
|
||||
import Nav from "../components/nav/nav";
|
||||
import { BrowserRouter, Route, Link } from 'react-router-dom'
|
||||
import { BrowserRouter, Route } from 'react-router-dom'
|
||||
|
||||
///**LANDING PAGE**///
|
||||
import Home from '../components/home/home';
|
||||
|
||||
///**TRANSACTIONS**///
|
||||
import TransactionRow from '../components/table/transactions/transactionRow';
|
||||
import BlocksRow from '../components/table/blocks/blockRows';
|
||||
import DetailBlockHeader from '../components/table/blocks/blocksDetailsRow';
|
||||
import TransactionHeader from "../components/nav/transactionHeader/transactionHeader";
|
||||
import TransactionDetailHeader from "../components/nav/transactionHeader/transactionDetailHeader";
|
||||
import DetailTransactionTable from "../components/table/transactions/transactionDetailsRow";
|
||||
///**BLOCKS**///
|
||||
import BlocksRow from '../components/table/blocks/blockRows';
|
||||
import DetailBlockTable from '../components/table/blocks/blocksDetailsRow';
|
||||
import BlockDetailHeader from "../components/nav/blockHeaders/blockDetailHeader";
|
||||
import BlockHeader from "../components/nav/blockHeaders/blockHeader";
|
||||
import Home from '../components/home/home';
|
||||
import DetailTransactionTable from "../components/table/transactions/transactionDetailsRow";
|
||||
|
||||
///**ACCOUNTS**///
|
||||
import AccountsRow from '../components/table/accounts/accountRows';
|
||||
import DetailAccountsTable from "../components/table/accounts/detailAccountsRow";
|
||||
import AccountHeader from "../components/nav/accountHeaders/accountHeader";
|
||||
import AccountDetailHeader from "../components/nav/accountHeaders/accountDetailHeader";
|
||||
|
||||
|
||||
class App extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
blockDetailData: [],
|
||||
transactionDetailData: []
|
||||
transactionDetailData: [],
|
||||
accountDetailData: [],
|
||||
reqAccount: ''
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -33,7 +47,7 @@ class App extends Component {
|
|||
|
||||
detailTransactionHandler = async(txHash) => {
|
||||
try {
|
||||
const response = await axios.get(`http://localhost:8080/api/get_transaction/${txHash}`)
|
||||
const response = await axios.get(`http://localhost:8080/api/get_transaction/${txHash}`);
|
||||
await this.setState({ transactionDetailData: response.data })
|
||||
}
|
||||
catch(error) {
|
||||
|
|
@ -41,6 +55,16 @@ class App extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
detailAccountHandler = async(addr) => {
|
||||
try {
|
||||
const response = await axios.get(`http://localhost:8080/api/get_account_txs/${addr}`)
|
||||
await this.setState({ accountDetailData: response.data, reqAccount: addr })
|
||||
}
|
||||
catch(error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
|
|
@ -65,6 +89,13 @@ class App extends Component {
|
|||
</div>}
|
||||
/>
|
||||
|
||||
<Route path="/accounts" exact render={({match}) =>
|
||||
<div>
|
||||
<AccountHeader/>
|
||||
<AccountsRow detailAccountHandler={this.detailAccountHandler}/>
|
||||
</div>}
|
||||
/>
|
||||
|
||||
<Route path="/transaction/details" exact render={({match}) =>
|
||||
<div>
|
||||
<TransactionDetailHeader
|
||||
|
|
@ -78,12 +109,21 @@ class App extends Component {
|
|||
<div>
|
||||
<BlockDetailHeader
|
||||
blockNumber={this.state.blockDetailData.Number}/>
|
||||
<DetailBlockHeader
|
||||
<DetailBlockTable
|
||||
data={this.state.blockDetailData}/>
|
||||
</div>}
|
||||
/>
|
||||
|
||||
|
||||
<Route path="/account/detail" exact render={({match}) =>
|
||||
<div>
|
||||
<AccountDetailHeader
|
||||
addr={this.state.reqAccount}/>
|
||||
<DetailAccountsTable
|
||||
transactionDetailHandler={this.detailTransactionHandler}
|
||||
addr={this.state.reqAccount}
|
||||
data={this.state.accountDetailData}/>
|
||||
</div>}
|
||||
/>
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -773,4 +773,73 @@ func GetAllAccounts(sqldb *sql.DB) string {
|
|||
accountsArr = accountsFmt
|
||||
}
|
||||
return accountsArr
|
||||
}
|
||||
|
||||
//GetAccount returns account balances
|
||||
func GetAccountTxs(sqldb *sql.DB, address string) string {
|
||||
var arr txRes
|
||||
var txx string
|
||||
sqlStatement := `SELECT * FROM txs WHERE to_addr=$1 OR from_addr=$1;`
|
||||
rows, err := sqldb.Query(sqlStatement, address)
|
||||
if err != nil {
|
||||
fmt.Println("err")
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var txhash string
|
||||
var to_addr string
|
||||
var from_addr string
|
||||
var blockhash string
|
||||
var blocknumber string
|
||||
var amount uint64
|
||||
var gasprice uint64
|
||||
var gas uint64
|
||||
var gasLimit uint64
|
||||
var txfee uint64
|
||||
var nonce uint64
|
||||
var status string
|
||||
var isContract bool
|
||||
var age time.Time
|
||||
var data []byte
|
||||
err = rows.Scan(
|
||||
&txhash,
|
||||
&to_addr,
|
||||
&from_addr,
|
||||
&blockhash,
|
||||
&blocknumber,
|
||||
&amount,
|
||||
&gasprice,
|
||||
&gas,
|
||||
&gasLimit,
|
||||
&txfee,
|
||||
&nonce,
|
||||
&status,
|
||||
&isContract,
|
||||
&age,
|
||||
&data,
|
||||
)
|
||||
|
||||
arr.TxEntry = append(arr.TxEntry, ShyftTxEntryPretty{
|
||||
TxHash: txhash,
|
||||
To: to_addr,
|
||||
From: from_addr,
|
||||
BlockHash: blockhash,
|
||||
BlockNumber: blocknumber,
|
||||
Amount: amount,
|
||||
GasPrice: gasprice,
|
||||
Gas: gas,
|
||||
GasLimit: gasLimit,
|
||||
Cost: txfee,
|
||||
Nonce: nonce,
|
||||
Status: status,
|
||||
IsContract: isContract,
|
||||
Age: age,
|
||||
Data: data,
|
||||
})
|
||||
|
||||
tx, _ := json.Marshal(arr.TxEntry)
|
||||
newtx := string(tx)
|
||||
txx = newtx
|
||||
}
|
||||
return txx
|
||||
}
|
||||
Loading…
Reference in a new issue