From fd296e83e33f42327f4f8c0eb13a38b011e998cb Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Thu, 17 May 2018 17:19:00 -0400 Subject: [PATCH] Block 0 and txs being written into db, UI modifications --- blockExplorerApi/handler.go | 35 +++++++- blockExplorerApi/routes.go | 12 +++ cmd/geth/chaincmd.go | 9 +- core/genesis.go | 74 +++++++++++++++- shyftBlockExplorerUI/README.md | 2 +- shyftBlockExplorerUI/src/TestData/testdata.js | 30 ------- .../src/components/assets/incoming.png | Bin 0 -> 1335 bytes .../src/components/assets/out.png | Bin 0 -> 1479 bytes .../src/components/home/home.css | 10 +++ .../src/components/home/home.js | 6 ++ .../nav/accountHeaders/accountDetailHeader.js | 12 +++ .../nav/accountHeaders/accountHeader.js | 12 +++ .../components/table/accounts/accountRows.js | 51 +++++++++++ .../components/table/accounts/accounts.css | 65 ++++++++++++++ .../table/accounts/accountsTable.js | 21 +++++ .../table/accounts/detailAccountsRow.js | 48 +++++++++++ .../table/accounts/detailAccountsTable.js | 31 +++++++ .../components/table/accounts/errorMessage.js | 11 +++ .../src/components/table/accounts/table.css | 80 ++++++++++++++++++ .../src/components/table/blocks/blockTable.js | 3 +- .../table/transactions/transactionTable.js | 4 +- shyftBlockExplorerUI/src/containers/App.js | 58 +++++++++++-- shyftdb/shyft_database_util.go | 69 +++++++++++++++ 23 files changed, 592 insertions(+), 51 deletions(-) delete mode 100644 shyftBlockExplorerUI/src/TestData/testdata.js create mode 100644 shyftBlockExplorerUI/src/components/assets/incoming.png create mode 100644 shyftBlockExplorerUI/src/components/assets/out.png create mode 100644 shyftBlockExplorerUI/src/components/nav/accountHeaders/accountDetailHeader.js create mode 100644 shyftBlockExplorerUI/src/components/nav/accountHeaders/accountHeader.js create mode 100644 shyftBlockExplorerUI/src/components/table/accounts/accountRows.js create mode 100644 shyftBlockExplorerUI/src/components/table/accounts/accounts.css create mode 100644 shyftBlockExplorerUI/src/components/table/accounts/accountsTable.js create mode 100644 shyftBlockExplorerUI/src/components/table/accounts/detailAccountsRow.js create mode 100644 shyftBlockExplorerUI/src/components/table/accounts/detailAccountsTable.js create mode 100644 shyftBlockExplorerUI/src/components/table/accounts/errorMessage.js create mode 100644 shyftBlockExplorerUI/src/components/table/accounts/table.css diff --git a/blockExplorerApi/handler.go b/blockExplorerApi/handler.go index 2b5c3692c3..3ba6e5d672 100644 --- a/blockExplorerApi/handler.go +++ b/blockExplorerApi/handler.go @@ -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) diff --git a/blockExplorerApi/routes.go b/blockExplorerApi/routes.go index 58d0d3ebf9..e70f001cf2 100644 --- a/blockExplorerApi/routes.go +++ b/blockExplorerApi/routes.go @@ -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", diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 99e3786b1b..3f517a7bf0 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -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) } diff --git a/core/genesis.go b/core/genesis.go index b6d56dc601..1e39bfa094 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -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 } diff --git a/shyftBlockExplorerUI/README.md b/shyftBlockExplorerUI/README.md index 7c4919e18d..fa9d3a5538 100644 --- a/shyftBlockExplorerUI/README.md +++ b/shyftBlockExplorerUI/README.md @@ -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.
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) diff --git a/shyftBlockExplorerUI/src/TestData/testdata.js b/shyftBlockExplorerUI/src/TestData/testdata.js deleted file mode 100644 index 0ca867a3b0..0000000000 --- a/shyftBlockExplorerUI/src/TestData/testdata.js +++ /dev/null @@ -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, - }]; - - diff --git a/shyftBlockExplorerUI/src/components/assets/incoming.png b/shyftBlockExplorerUI/src/components/assets/incoming.png new file mode 100644 index 0000000000000000000000000000000000000000..94e53685434a313495c336607ddde506f6a95aa6 GIT binary patch literal 1335 zcmeAS@N?(olHy`uVBq!ia0vp^sz5Bl!3HF`c6{MxU|_7tbaoE#baqwWn z(3qH#xKo}p z+_XB$>ZYG%T2$%|Z`a+HYU5MP;jp z`$1#1jnVXMj zw#+zX!^T#Z&DNItoJ*)%=pkSFpJPrP@pIC0SQ0;57#eK2_xu0<%~H(Fzg5`U_6z_2 z|9|g`|Nr-QH-2M&{KkQgL8UzNK~J_2KLZ03Q)Wm+NrbPDRdRl=USdjqQmS4>ZUHc! z7#M6Stboki)RIJnirk#MVyg;UC9n!BAR8pCucQE0Qj%?}6yY17;GAESs$i;TqGzCF z$EBd4U{jQmW)z9|8>y;bpKhp88yV>WRp=I1 z=9MH?=;jqGLkxkLMfuL z^+7WFhI$72*tC^ors2>Al7VOg`wL>74ahL7fXs^2oJg0<+|;~cpwsM(jBLQRU`Qa` ziKHEamT!JGVtpXIyVo#cqpV$s7#!^I`*{{B7ckbmIVnPUs|mz@__ zCUEmmh!eiTTj~-~aUwx6hZC znBfp;HiO}Wtq=3WwhydKK*kRdo+&bseW!}z4sN)%mElENber7$tvuPa>P8hxKN(c^ zACgq@ms2<$nDe5{@U+1Z>$HQej-S?~%;Yg_Vp=P}9MO2?`ug<}5kKcjN|}f%Hi=9U zvF4hhb$@@%;SJwE=d;CrHDXI&(5#_br&%s?K`>{{eu-so?;iOu)v-tMs$T2E>-MLb zy0rS3thirvrSjbU{?2#y&Fx%wR)i6`U+qiKScQa?hox?0y vF}!LFMf}1mwwgycaX;akP%XipTr9z0^R+~Yd9$GbD4%({`njxgN@xNAR#o>o literal 0 HcmV?d00001 diff --git a/shyftBlockExplorerUI/src/components/assets/out.png b/shyftBlockExplorerUI/src/components/assets/out.png new file mode 100644 index 0000000000000000000000000000000000000000..e61f2dd1bc7c2affba0600618944d6ba6f504c41 GIT binary patch literal 1479 zcmeAS@N?(olHy`uVBq!ia0vp^DnKm4!3HFsR?RnMU|_7tbaoE#baqwWn z(3qH#xKo}p z+_XB$>ZYG%T2$%|Z`a+HYU5MP;jp z`$1#1jnVXMj zw#+zX!^T#Z&DNItoJ*)%=pkSFpJPrP@pIC0SQ0;57#eK2_xu0<%~H(Fzg5`U_6z_2 z|9|g`|Nr-QH-2M&{KkQgL8UzNK~J_2KQJCG?W zUP)qwZeFo6#1NP{E~&-IMVSR9nfZANAafIw@=Hr>m6Sjh!2!gbsTG+BoAQdG-U511 zA0(r1sAr%LHyfzc1|(_~kXezM6XBAXo0?Y)w8PHW%m%C+LjqwTlEz4cMk51cjYtwu zjW+rq=OcLs5>{YQU|`vC+33Rq-j3_Dxo9W@15>=Gi(`lf@7Za-8Nz`A$N&G%@$uN= z$=us+`omGvsrscZM_AVj(+Z9z_Lb`T3tOHkd{j;t8_uZYH|H#20CGI&EGTw}uyEL+6kvZ!D}uzLn;y4c~8DMoe6 zF0JquI>E5-Xoa`Eczb@ImiNR3B5ey^7>GW3`ng6~r)7HW>PtM#p>AJa?uq-x@G|*| zSd)7$V;1Mv^zy)Sbw<-Ze0z{6nPYF0#ox9m`vUul+_Tcj6TBiOo|RrKvFzB(rNwt# zb!WfhGQ9IV!Qt>vn`x$x>wlLCo;&p8=?T3q>!^8Ufr;E P0p)v7S3j3^P6 { const combinedClasses = ["btn", "btn-primary", classes.BlockButton] + const conjoinecdClasses = ["btn", "btn-primary", classes.AccountButton] return (
THIS IS A WIP +
+
+ +
+
); }; diff --git a/shyftBlockExplorerUI/src/components/nav/accountHeaders/accountDetailHeader.js b/shyftBlockExplorerUI/src/components/nav/accountHeaders/accountDetailHeader.js new file mode 100644 index 0000000000..097c84d2ea --- /dev/null +++ b/shyftBlockExplorerUI/src/components/nav/accountHeaders/accountDetailHeader.js @@ -0,0 +1,12 @@ +import React from 'react'; +import classes from '../nav.css'; + +const accountsDetailHeader = (props) => { + return ( +
+ Account# {props.addr} +
+ ) +} + +export default accountsDetailHeader; \ No newline at end of file diff --git a/shyftBlockExplorerUI/src/components/nav/accountHeaders/accountHeader.js b/shyftBlockExplorerUI/src/components/nav/accountHeaders/accountHeader.js new file mode 100644 index 0000000000..8013bd9442 --- /dev/null +++ b/shyftBlockExplorerUI/src/components/nav/accountHeaders/accountHeader.js @@ -0,0 +1,12 @@ +import React from 'react'; +import classes from '../nav.css'; + +const accountsHeader = (props) => { + return ( +
+ Accounts +
+ ) +} + +export default accountsHeader; \ No newline at end of file diff --git a/shyftBlockExplorerUI/src/components/table/accounts/accountRows.js b/shyftBlockExplorerUI/src/components/table/accounts/accountRows.js new file mode 100644 index 0000000000..99db9d6dbe --- /dev/null +++ b/shyftBlockExplorerUI/src/components/table/accounts/accountRows.js @@ -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 + }) + + let combinedClasses = ['responsive-table', classes.table]; + return ( + + + + + + + + + + + {table} +
RankAddressBalancePercentageTxCount
+ ); + } +} +export default AccountTable; diff --git a/shyftBlockExplorerUI/src/components/table/accounts/accounts.css b/shyftBlockExplorerUI/src/components/table/accounts/accounts.css new file mode 100644 index 0000000000..8aa8995a54 --- /dev/null +++ b/shyftBlockExplorerUI/src/components/table/accounts/accounts.css @@ -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; +} \ No newline at end of file diff --git a/shyftBlockExplorerUI/src/components/table/accounts/accountsTable.js b/shyftBlockExplorerUI/src/components/table/accounts/accountsTable.js new file mode 100644 index 0000000000..152dde6c42 --- /dev/null +++ b/shyftBlockExplorerUI/src/components/table/accounts/accountsTable.js @@ -0,0 +1,21 @@ +import React from 'react'; +import classes from './accounts.css'; +import { Link } from 'react-router-dom' + +const AccountsTable = (props) => { + return ( + + + 1 + props.detailAccountHandler(props.Addr)}> + {props.Addr} + + {props.Balance} + 12.01% + {props.TxCountAccount} + + + ) +} + +export default AccountsTable; diff --git a/shyftBlockExplorerUI/src/components/table/accounts/detailAccountsRow.js b/shyftBlockExplorerUI/src/components/table/accounts/detailAccountsRow.js new file mode 100644 index 0000000000..cec0b9e8de --- /dev/null +++ b/shyftBlockExplorerUI/src/components/table/accounts/detailAccountsRow.js @@ -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 + }else { + table = this.props.data.map((data, i) => { + return + }) + } + + let combinedClasses = ['responsive-table', classes.table]; + return ( + + + + + + + + + + + + + + {table} +
TxHashBlockAgeFromToValueTxFee
+ ); + } +} +export default AccountTransactionTable; diff --git a/shyftBlockExplorerUI/src/components/table/accounts/detailAccountsTable.js b/shyftBlockExplorerUI/src/components/table/accounts/detailAccountsTable.js new file mode 100644 index 0000000000..4b7cedb9d1 --- /dev/null +++ b/shyftBlockExplorerUI/src/components/table/accounts/detailAccountsTable.js @@ -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 ( + + + + props.detailTransactionHandler(props.txHash)}> + {props.txHash} + + {props.blockNumber} + {props.age} + {props.from} +
{ flag ? "IN" : "OUT" }
+ {props.to} + {props.value} + {props.cost} + + + ) +} + +export default DetailAccountsTable; diff --git a/shyftBlockExplorerUI/src/components/table/accounts/errorMessage.js b/shyftBlockExplorerUI/src/components/table/accounts/errorMessage.js new file mode 100644 index 0000000000..96c6cc12b1 --- /dev/null +++ b/shyftBlockExplorerUI/src/components/table/accounts/errorMessage.js @@ -0,0 +1,11 @@ +import React from 'react'; + +const errorMessage = (props) => { + return ( +
+ THIS IS AN ERROR +
+ ) +} + +export default errorMessage; \ No newline at end of file diff --git a/shyftBlockExplorerUI/src/components/table/accounts/table.css b/shyftBlockExplorerUI/src/components/table/accounts/table.css new file mode 100644 index 0000000000..0dd7b521e7 --- /dev/null +++ b/shyftBlockExplorerUI/src/components/table/accounts/table.css @@ -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; +} \ No newline at end of file diff --git a/shyftBlockExplorerUI/src/components/table/blocks/blockTable.js b/shyftBlockExplorerUI/src/components/table/blocks/blockTable.js index 0e5b11edf4..aa66bee9f2 100644 --- a/shyftBlockExplorerUI/src/components/table/blocks/blockTable.js +++ b/shyftBlockExplorerUI/src/components/table/blocks/blockTable.js @@ -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) => { diff --git a/shyftBlockExplorerUI/src/components/table/transactions/transactionTable.js b/shyftBlockExplorerUI/src/components/table/transactions/transactionTable.js index 3f6c4d9fc2..d978a82ed5 100644 --- a/shyftBlockExplorerUI/src/components/table/transactions/transactionTable.js +++ b/shyftBlockExplorerUI/src/components/table/transactions/transactionTable.js @@ -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) => { {props.blockNumber} {props.age} {props.from} - + arrow {props.to} {props.value} {props.cost} diff --git a/shyftBlockExplorerUI/src/containers/App.js b/shyftBlockExplorerUI/src/containers/App.js index 6029f37e68..f1561f6f63 100644 --- a/shyftBlockExplorerUI/src/containers/App.js +++ b/shyftBlockExplorerUI/src/containers/App.js @@ -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 ( @@ -65,6 +89,13 @@ class App extends Component { } /> + +
+ + +
} + /> +
-
} /> - + +
+ + +
} + />
); diff --git a/shyftdb/shyft_database_util.go b/shyftdb/shyft_database_util.go index 6dee4a5834..88b19df03e 100644 --- a/shyftdb/shyft_database_util.go +++ b/shyftdb/shyft_database_util.go @@ -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 } \ No newline at end of file