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) {
|
func GetAccount(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
address := vars["address"]
|
address := vars["address"]
|
||||||
//addressBytes := []byte(address)
|
|
||||||
fmt.Println("ADDRESS FROM ROUTE", address)
|
|
||||||
connStr := "user=postgres dbname=shyftdb sslmode=disable"
|
connStr := "user=postgres dbname=shyftdb sslmode=disable"
|
||||||
blockExplorerDb, err := sql.Open("postgres", connStr)
|
blockExplorerDb, err := sql.Open("postgres", connStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -82,6 +80,29 @@ func GetAccount(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprintln(w, getAccountBalance)
|
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
|
// GetAllAccounts gets balances
|
||||||
func GetAllAccounts(w http.ResponseWriter, r *http.Request) {
|
func GetAllAccounts(w http.ResponseWriter, r *http.Request) {
|
||||||
connStr := "user=postgres dbname=shyftdb sslmode=disable"
|
connStr := "user=postgres dbname=shyftdb sslmode=disable"
|
||||||
|
|
@ -140,6 +161,16 @@ func GetAllBlocks(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprintln(w, block3)
|
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
|
//GetInternalTransactions gets internal txs
|
||||||
func GetInternalTransactions(w http.ResponseWriter, r *http.Request) {
|
func GetInternalTransactions(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,12 @@ var routes = Routes{
|
||||||
"/api/get_account/{address}",
|
"/api/get_account/{address}",
|
||||||
GetAccount,
|
GetAccount,
|
||||||
},
|
},
|
||||||
|
Route{
|
||||||
|
"GetAccountTxs",
|
||||||
|
"GET",
|
||||||
|
"/api/get_account_txs/{address}",
|
||||||
|
GetAccountTxs,
|
||||||
|
},
|
||||||
Route{
|
Route{
|
||||||
"GetAllAccounts",
|
"GetAllAccounts",
|
||||||
"GET",
|
"GET",
|
||||||
|
|
@ -51,6 +57,12 @@ var routes = Routes{
|
||||||
"/api/get_transaction/{txHash}",
|
"/api/get_transaction/{txHash}",
|
||||||
GetTransaction,
|
GetTransaction,
|
||||||
},
|
},
|
||||||
|
Route{
|
||||||
|
Name: "GetRecentBlock",
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/api/get_recent_block",
|
||||||
|
HandlerFunc: GetRecentBlock,
|
||||||
|
},
|
||||||
Route{
|
Route{
|
||||||
"GetInternalTransactions",
|
"GetInternalTransactions",
|
||||||
"GET",
|
"GET",
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/syndtr/goleveldb/leveldb/util"
|
"github.com/syndtr/goleveldb/leveldb/util"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
|
"database/sql"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -168,7 +169,13 @@ func initGenesis(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Failed to open database: %v", err)
|
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 {
|
if err != nil {
|
||||||
utils.Fatalf("Failed to write genesis block: %v", err)
|
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/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate gencodec -type Genesis -field-override genesisSpecMarshaling -out gen_genesis.go
|
//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
|
//WriteShyftGen writes the genesis block to Shyft db
|
||||||
//@NOTE:SHYFT
|
//@NOTE:SHYFT
|
||||||
func WriteShyftGen(sqldb *sql.DB, gen *Genesis) {
|
func WriteShyftGen(sqldb *sql.DB, gen *Genesis, block *types.Block) {
|
||||||
if sqldb == nil {
|
if sqldb == nil {
|
||||||
log.Info("Initializing Shyft Postgres DB")
|
log.Info("Initializing Shyft Postgres DB")
|
||||||
connStr := "user=postgres dbname=shyftdb sslmode=disable"
|
connStr := "user=postgres dbname=shyftdb sslmode=disable"
|
||||||
|
|
@ -156,18 +158,80 @@ func WriteShyftGen(sqldb *sql.DB, gen *Genesis) {
|
||||||
switch {
|
switch {
|
||||||
case err == sql.ErrNoRows:
|
case err == sql.ErrNoRows:
|
||||||
for k, v := range gen.Alloc {
|
for k, v := range gen.Alloc {
|
||||||
|
number := block.Header().Number.String()
|
||||||
|
gasUsed := block.Header().GasUsed
|
||||||
|
gasLimit := block.Header().GasLimit
|
||||||
addr := k.String()
|
addr := k.String()
|
||||||
txCountAccount := v.Nonce +1
|
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`
|
sqlStatement := `INSERT INTO accounts(addr, balance, txCountAccount) VALUES(($1), ($2), ($3)) RETURNING addr`
|
||||||
insertErr := sqldb.QueryRow(sqlStatement, addr, v.Balance.String(), txCountAccount).Scan(&addr)
|
insertErr := sqldb.QueryRow(sqlStatement, addr, v.Balance.String(), txCountAccount).Scan(&addr)
|
||||||
if insertErr != nil {
|
if insertErr != nil {
|
||||||
panic(insertErr)
|
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:
|
default:
|
||||||
log.Info("Found Genesis Block")
|
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.
|
// SetupGenesisBlock writes or updates the genesis block in db.
|
||||||
// The block that will be used is:
|
// 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 {
|
if genesis != nil && genesis.Config == nil {
|
||||||
return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig
|
return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just commit the new block if there is no stored genesis block.
|
// Just commit the new block if there is no stored genesis block.
|
||||||
stored := GetCanonicalHash(db, 0)
|
stored := GetCanonicalHash(db, 0)
|
||||||
if (stored == common.Hash{}) {
|
if (stored == common.Hash{}) {
|
||||||
|
|
@ -194,10 +257,13 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis, sqldb *sql.DB) (*par
|
||||||
genesis = DefaultGenesisBlock()
|
genesis = DefaultGenesisBlock()
|
||||||
} else {
|
} else {
|
||||||
log.Info("Writing custom genesis block")
|
log.Info("Writing custom genesis block")
|
||||||
//@NOTE:SHYFT WRITE TO DB
|
|
||||||
WriteShyftGen(sqldb, genesis)
|
|
||||||
}
|
}
|
||||||
block, err := genesis.Commit(db)
|
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
|
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>
|
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).
|
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)
|
- [Updating to New Releases](#updating-to-new-releases)
|
||||||
- [Sending Feedback](#sending-feedback)
|
- [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 {
|
.Blocks {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 1rem;
|
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 home = props => {
|
||||||
|
|
||||||
const combinedClasses = ["btn", "btn-primary", classes.BlockButton]
|
const combinedClasses = ["btn", "btn-primary", classes.BlockButton]
|
||||||
|
const conjoinecdClasses = ["btn", "btn-primary", classes.AccountButton]
|
||||||
return (
|
return (
|
||||||
<div className={classes.Home}>
|
<div className={classes.Home}>
|
||||||
<span className={classes.Greeting}>THIS IS A WIP</span>
|
<span className={classes.Greeting}>THIS IS A WIP</span>
|
||||||
|
<div className={classes.ButtonNav}>
|
||||||
<div className={classes.Transactions}>
|
<div className={classes.Transactions}>
|
||||||
<Link to="/transactions"><button className="btn btn-primary">Transactions</button></Link>
|
<Link to="/transactions"><button className="btn btn-primary">Transactions</button></Link>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.Blocks}>
|
<div className={classes.Blocks}>
|
||||||
<Link to="/blocks"><button className={combinedClasses.join(" ")}>Blocks</button></Link>
|
<Link to="/blocks"><button className={combinedClasses.join(" ")}>Blocks</button></Link>
|
||||||
</div>
|
</div>
|
||||||
|
<div className={classes.Accounts}>
|
||||||
|
<Link to="/accounts"><button className={conjoinecdClasses.join(" ")}>Accounts</button></Link>
|
||||||
|
</div>
|
||||||
|
</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 classes from './table.css';
|
||||||
import arrow from '../../assets/arrow_right.png';
|
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
|
|
||||||
const BlockTable = (props) => {
|
const BlockTable = (props) => {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { Component } from 'react';
|
import React from 'react';
|
||||||
import classes from './table.css';
|
import classes from './table.css';
|
||||||
import arrow from '../../assets/arrow_right.png';
|
import arrow from '../../assets/arrow_right.png';
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
|
|
@ -14,7 +14,7 @@ const TransactionTable = (props) => {
|
||||||
<td>{props.blockNumber}</td>
|
<td>{props.blockNumber}</td>
|
||||||
<td>{props.age}</td>
|
<td>{props.age}</td>
|
||||||
<td className={classes.fromTag}>{props.from}</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 className={classes.toTag}>{props.to}</td>
|
||||||
<td>{props.value}</td>
|
<td>{props.value}</td>
|
||||||
<td>{props.cost}</td>
|
<td>{props.cost}</td>
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,37 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import Nav from "../components/nav/nav";
|
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 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 TransactionHeader from "../components/nav/transactionHeader/transactionHeader";
|
||||||
import TransactionDetailHeader from "../components/nav/transactionHeader/transactionDetailHeader";
|
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 BlockDetailHeader from "../components/nav/blockHeaders/blockDetailHeader";
|
||||||
import BlockHeader from "../components/nav/blockHeaders/blockHeader";
|
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 {
|
class App extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
blockDetailData: [],
|
blockDetailData: [],
|
||||||
transactionDetailData: []
|
transactionDetailData: [],
|
||||||
|
accountDetailData: [],
|
||||||
|
reqAccount: ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,7 +47,7 @@ class App extends Component {
|
||||||
|
|
||||||
detailTransactionHandler = async(txHash) => {
|
detailTransactionHandler = async(txHash) => {
|
||||||
try {
|
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 })
|
await this.setState({ transactionDetailData: response.data })
|
||||||
}
|
}
|
||||||
catch(error) {
|
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() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
|
|
@ -65,6 +89,13 @@ class App extends Component {
|
||||||
</div>}
|
</div>}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Route path="/accounts" exact render={({match}) =>
|
||||||
|
<div>
|
||||||
|
<AccountHeader/>
|
||||||
|
<AccountsRow detailAccountHandler={this.detailAccountHandler}/>
|
||||||
|
</div>}
|
||||||
|
/>
|
||||||
|
|
||||||
<Route path="/transaction/details" exact render={({match}) =>
|
<Route path="/transaction/details" exact render={({match}) =>
|
||||||
<div>
|
<div>
|
||||||
<TransactionDetailHeader
|
<TransactionDetailHeader
|
||||||
|
|
@ -78,12 +109,21 @@ class App extends Component {
|
||||||
<div>
|
<div>
|
||||||
<BlockDetailHeader
|
<BlockDetailHeader
|
||||||
blockNumber={this.state.blockDetailData.Number}/>
|
blockNumber={this.state.blockDetailData.Number}/>
|
||||||
<DetailBlockHeader
|
<DetailBlockTable
|
||||||
data={this.state.blockDetailData}/>
|
data={this.state.blockDetailData}/>
|
||||||
</div>}
|
</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>
|
</div>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -774,3 +774,72 @@ func GetAllAccounts(sqldb *sql.DB) string {
|
||||||
}
|
}
|
||||||
return accountsArr
|
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