Block 0 and txs being written into db, UI modifications

This commit is contained in:
Dustin Brickwood 2018-05-17 17:19:00 -04:00
parent 573cb28a43
commit fd296e83e3
23 changed files with 592 additions and 51 deletions

View file

@ -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)

View file

@ -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",

View file

@ -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)
} }

View file

@ -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
} }

View file

@ -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)

View file

@ -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,
}];

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -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;
}

View file

@ -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>
); );
}; };

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -0,0 +1,11 @@
import React from 'react';
const errorMessage = (props) => {
return (
<div>
THIS IS AN ERROR
</div>
)
}
export default errorMessage;

View 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;
}

View file

@ -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) => {

View file

@ -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>

View file

@ -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>
); );

View file

@ -773,4 +773,73 @@ func GetAllAccounts(sqldb *sql.DB) string {
accountsArr = accountsFmt accountsArr = accountsFmt
} }
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
} }