Merge branch 'shyftBlockExplorer' of github.com:ShyftNetwork/shyft_go-ethereum into shyftBlockExplorer

This commit is contained in:
greg 2018-06-03 10:06:28 -04:00
commit bd5849a786
32 changed files with 575 additions and 72 deletions

View file

@ -74,13 +74,34 @@ func GetAllTransactionsFromBlock(w http.ResponseWriter, r *http.Request) {
return return
} }
w.Header().Set("Content-Type", "application/json; charset=UTF-8") w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, txsFromBlock) fmt.Fprintln(w, txsFromBlock)
} }
func GetAllBlocksMinedByAddress(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
coinbase := vars["coinbase"]
connStr := "user=postgres dbname=shyftdb sslmode=disable"
blockExplorerDb, err := sql.Open("postgres", connStr)
if err != nil {
return
}
blocksMined := shyftdb.GetAllBlocksMinedByAddress(blockExplorerDb, coinbase)
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, blocksMined)
}
// GetAccount gets balance // GetAccount gets balance
func GetAccount(w http.ResponseWriter, r *http.Request) { func GetAccount(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r) vars := mux.Vars(r)

View file

@ -69,6 +69,12 @@ var routes = Routes{
Pattern: "/api/get_all_transactions_from_block/{blockNumber}", Pattern: "/api/get_all_transactions_from_block/{blockNumber}",
HandlerFunc: GetAllTransactionsFromBlock, HandlerFunc: GetAllTransactionsFromBlock,
}, },
Route{
Name: "GetAllBlocksMinedByAddress",
Method: "GET",
Pattern: "/api/get_blocks_mined/{coinbase}",
HandlerFunc: GetAllBlocksMinedByAddress,
},
Route{ Route{
"GetInternalTransactions", "GetInternalTransactions",
"GET", "GET",

View file

@ -161,6 +161,11 @@ func WriteShyftGen(sqldb *sql.DB, gen *Genesis, block *types.Block) {
number := block.Header().Number.String() number := block.Header().Number.String()
gasUsed := block.Header().GasUsed gasUsed := block.Header().GasUsed
gasLimit := block.Header().GasLimit gasLimit := block.Header().GasLimit
gasPrice := 0
txFee := 0
txStatus := ""
isContract := false
data:= ""
addr := k.String() addr := k.String()
txCountAccount := v.Nonce +1 txCountAccount := v.Nonce +1
i, err := strconv.ParseInt(block.Time().String(), 10, 64) i, err := strconv.ParseInt(block.Time().String(), 10, 64)
@ -179,8 +184,8 @@ func WriteShyftGen(sqldb *sql.DB, gen *Genesis, block *types.Block) {
} }
var retNonce string 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` sqlGenTxStatement := `INSERT INTO txs(txhash, from_addr, to_addr, blockhash, blockNumber, amount,gasPrice, gas, gasLimit,txFee,nonce,txstatus, iscontract,age, data) VALUES(($1), ($2), ($3), ($4), ($5), ($6), ($7), ($8), ($9), ($10), ($11), ($12), ($13), ($14), ($15)) RETURNING nonce`
insertError := sqldb.QueryRow(sqlGenTxStatement, txHash, GENESIS, addr, block.Header().Hash().Hex(), number, v.Balance.String(), gasUsed, gasLimit, txCountAccount, age).Scan(&retNonce) insertError := sqldb.QueryRow(sqlGenTxStatement, txHash, GENESIS, addr, block.Header().Hash().Hex(), number, v.Balance.String(), gasPrice, gasUsed, gasLimit, txFee,txCountAccount,txStatus, isContract, age, data).Scan(&retNonce)
if insertError != nil { if insertError != nil {
panic(insertError) panic(insertError)
} }

View file

@ -21,7 +21,7 @@
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>React App</title> <title>Block Explorer</title>
</head> </head>
<body> <body>
<noscript> <noscript>

View file

@ -0,0 +1,67 @@
.Loader,
.Loader:before,
.Loader:after {
border-radius: 50%;
}
.Loader {
color: #521751;
font-size: 11px;
text-indent: -99999em;
margin: 55px auto;
position: relative;
width: 10em;
height: 10em;
box-shadow: inset 0 0 0 1em;
-webkit-transform: translateZ(0);
-ms-transform: translateZ(0);
transform: translateZ(0);
}
.Loader:before,
.Loader:after {
position: absolute;
content: '';
}
.Loader:before {
width: 5.2em;
height: 10.2em;
background: #fff;
border-radius: 10.2em 0 0 10.2em;
top: -0.1em;
left: -0.1em;
-webkit-transform-origin: 5.2em 5.1em;
transform-origin: 5.2em 5.1em;
-webkit-animation: load2 2s infinite ease 1.5s;
animation: load2 2s infinite ease 1.5s;
}
.Loader:after {
width: 5.2em;
height: 10.2em;
background: #fff;
border-radius: 0 10.2em 10.2em 0;
top: -0.1em;
left: 5.1em;
-webkit-transform-origin: 0px 5.1em;
transform-origin: 0px 5.1em;
-webkit-animation: load2 2s infinite ease;
animation: load2 2s infinite ease;
}
@-webkit-keyframes load2 {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes load2 {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}

View file

@ -0,0 +1,8 @@
import React from 'react';
import classes from './loading.css';
const loading = () => (
<div className={classes.Loader}>Loading...</div>
);
export default loading;

View file

@ -10,6 +10,8 @@
} }
.Greeting { .Greeting {
padding-top: 5%;
padding-bottom: 5%;
display: block; display: block;
} }

View file

@ -9,7 +9,7 @@ const home = props => {
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>
<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>

View file

@ -2,11 +2,15 @@ import React from 'react';
import classes from '../nav.css'; import classes from '../nav.css';
const accountsDetailHeader = (props) => { const accountsDetailHeader = (props) => {
const total = props.data
.map(num => Number(num.Amount) / 10000000000000000000)
.reduce((acc, cur) => acc + cur ,0);
return ( return (
<div className={classes.Secondary}> <div className={classes.Secondary}>
<span className={classes.Transactions}>Account# {props.addr}</span> <span className={classes.Transactions}>Account# {props.addr}</span>
<span className={classes.Transactions}>Total Value: {total}</span>
</div> </div>
) )
} };
export default accountsDetailHeader; export default accountsDetailHeader;

View file

@ -0,0 +1,12 @@
import React from 'react';
import classes from '../nav.css';
const blocksCoinbaseHeader = (props) => {
return (
<div className={classes.Secondary}>
<span className={classes.Transactions}>Coinbase: {props.coinbase}</span>
</div>
)
};
export default blocksCoinbaseHeader;

View file

@ -21,15 +21,27 @@ class AccountTable extends Component {
} }
render() { render() {
const table = this.state.data.map((data, i) => {
let startNum = 1;
const sorted = [...this.state.data];
sorted.sort((a, b) => Number(a.Balance) > Number(b.Balance));
console.log(sorted);
const table = sorted.reverse().map((data, i) => {
const conversion = Number(data.Balance) / 10000000000000000000;
const total = sorted
.map(num => Number(num.Balance) / 10000000000000000000)
.reduce((acc, cur) => acc + cur ,0);
const percentage = ( (conversion / total) *100);
return <AccountsTable return <AccountsTable
key={`${data.addr}${i}`} key={`${data.addr}${i}`}
Rank={startNum++}
Percentage={percentage.toFixed(2)}
Addr={data.Addr} Addr={data.Addr}
Balance={data.Balance} Balance={conversion}
TxCountAccount={data.TxCountAccount} TxCountAccount={data.TxCountAccount}
detailAccountHandler={this.props.detailAccountHandler} detailAccountHandler={this.props.detailAccountHandler}
/> />
}) });
let combinedClasses = ['responsive-table', classes.table]; let combinedClasses = ['responsive-table', classes.table];
return ( return (

View file

@ -6,16 +6,16 @@ const AccountsTable = (props) => {
return ( return (
<tbody> <tbody>
<tr> <tr>
<td>1</td> <td>{props.Rank}</td>
<td className={classes.addressTag}><Link to="/account/detail" onClick={() => props.detailAccountHandler(props.Addr)}> <td className={classes.addressTag}><Link to="/account/detail" onClick={() => props.detailAccountHandler(props.Addr)}>
{props.Addr} {props.Addr}
</Link></td> </Link></td>
<td>{props.Balance}</td> <td>{props.Balance}</td>
<td>12.01%</td> <td>{props.Percentage}%</td>
<td>{props.TxCountAccount}</td> <td>{props.TxCountAccount}</td>
</tr> </tr>
</tbody> </tbody>
) )
} };
export default AccountsTable; export default AccountsTable;

View file

@ -10,6 +10,8 @@ class AccountTransactionTable extends Component {
return <ErrorHandler /> return <ErrorHandler />
}else { }else {
table = this.props.data.map((data, i) => { table = this.props.data.map((data, i) => {
const costConversion = data.Cost / 10000000000000000000;
const amountConversion = data.Amount / 10000000000000000000;
return <DetailAccountsTable return <DetailAccountsTable
key={`${data.TxHash}${i}`} key={`${data.TxHash}${i}`}
age={data.Age} age={data.Age}
@ -17,8 +19,8 @@ class AccountTransactionTable extends Component {
blockNumber={data.BlockNumber} blockNumber={data.BlockNumber}
to={data.To} to={data.To}
from={data.From} from={data.From}
value={data.Amount} value={amountConversion}
cost={data.Cost} cost={costConversion}
addr={this.props.addr} addr={this.props.addr}
detailTransactionHandler={this.props.transactionDetailHandler} detailTransactionHandler={this.props.transactionDetailHandler}
/> />

View file

@ -9,11 +9,17 @@ const DetailAccountsTable = (props) => {
}else { }else {
flag = false flag = false
} }
let genFlag;
if(props.txHash.indexOf("GENESIS") !== -1) {
genFlag = false
}else {
genFlag = true
}
return ( return (
<tbody> <tbody>
<tr> <tr>
<td className={classes.addressTag}> <td className={classes.addressTag}>
<Link to="/transaction/details" onClick={() => props.detailTransactionHandler(props.txHash)}> <Link to="/transaction/details" className={genFlag ? "" : classes.disabled} onClick={() => props.detailTransactionHandler(props.txHash)}>
{props.txHash}</Link> {props.txHash}</Link>
</td> </td>
<td>{props.blockNumber}</td> <td>{props.blockNumber}</td>
@ -26,6 +32,6 @@ const DetailAccountsTable = (props) => {
</tr> </tr>
</tbody> </tbody>
) )
} };
export default DetailAccountsTable; export default DetailAccountsTable;

View file

@ -78,3 +78,8 @@ th {
text-align: center; text-align: center;
vertical-align: middle; vertical-align: middle;
} }
.disabled {
pointer-events: none;
color: black;
}

View file

@ -1,5 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import BlockTable from './blockTable'; import BlockTable from './blockTable';
import Loading from '../../UI materials/loading'
import classes from './table.css'; import classes from './table.css';
import axios from "axios/index"; import axios from "axios/index";
@ -13,7 +14,7 @@ class BlocksTable extends Component {
async componentDidMount() { async componentDidMount() {
try { try {
const response = await axios.get("http://localhost:8080/api/get_all_blocks") const response = await axios.get("http://localhost:8080/api/get_all_blocks");
await this.setState({data: response.data}); await this.setState({data: response.data});
} catch (err) { } catch (err) {
console.log(err); console.log(err);
@ -23,6 +24,7 @@ class BlocksTable extends Component {
render() { render() {
const table = this.state.data.map((data, i) => { const table = this.state.data.map((data, i) => {
const conversion = data.Rewards / 10000000000000000000;
return <BlockTable return <BlockTable
key={`${data.TxHash}${i}`} key={`${data.TxHash}${i}`}
Hash={data.Hash} Hash={data.Hash}
@ -33,9 +35,11 @@ class BlocksTable extends Component {
GasLimit={data.GasLimit} GasLimit={data.GasLimit}
UncleCount={data.UncleCount} UncleCount={data.UncleCount}
TxCount={data.TxCount} TxCount={data.TxCount}
Reward={conversion}
detailBlockHandler={this.props.detailBlockHandler} detailBlockHandler={this.props.detailBlockHandler}
getBlocksMined={this.props.getBlocksMined}
/> />
}) });
let combinedClasses = ['responsive-table', classes.table]; let combinedClasses = ['responsive-table', classes.table];
return ( return (

View file

@ -13,11 +13,11 @@ const BlockTable = (props) => {
<td>{props.Age}</td> <td>{props.Age}</td>
<td>{props.TxCount}</td> <td>{props.TxCount}</td>
<td>{props.UncleCount}</td> <td>{props.UncleCount}</td>
<td className={classes.addressTag}>{props.Coinbase}</td> <td className={classes.addressTag}><Link to="/mined/blocks" onClick={() => props.getBlocksMined(props.Coinbase)}>{props.Coinbase}</Link></td>
<td>{props.GasUsed}</td> <td>{props.GasUsed}</td>
<td>{props.GasLimit}</td> <td>{props.GasLimit}</td>
<td>12.01</td> <td>TBD</td>
<td>3.2</td> <td>{props.Reward}</td>
</tr> </tr>
</tbody> </tbody>
) )

View file

@ -1,10 +1,11 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import classes from './table.css'; import classes from './table.css';
import { Link } from 'react-router-dom'
class DetailBlockTable extends Component { class DetailBlockTable extends Component {
render() { render() {
let data = this.props.data let data = this.props.data;
let combinedClasses = ['responsive-table', classes.table]; let combinedClasses = ['responsive-table', classes.table];
return ( return (
<table className={combinedClasses.join(' ')}> <table className={combinedClasses.join(' ')}>
@ -19,7 +20,7 @@ class DetailBlockTable extends Component {
</tr> </tr>
<tr> <tr>
<th scope="col">Txn:</th> <th scope="col">Txn:</th>
<td>{data.TxCount} transactions</td> <td><Link to="/block/transactions" onClick={() => this.props.getBlockTransactions(data.Number)}>{data.TxCount} transactions</Link></td>
</tr> </tr>
<tr> <tr>
<th scope="col">Block Hash:</th> <th scope="col">Block Hash:</th>
@ -67,7 +68,7 @@ class DetailBlockTable extends Component {
</tr> </tr>
<tr> <tr>
<th scope="col">Reward:</th> <th scope="col">Reward:</th>
<td>TBD</td> <td>{data.Rewards}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View file

@ -0,0 +1,55 @@
import React, { Component } from 'react';
import MinedBlockTable from './blocksMinedTable';
import Loading from '../../UI materials/loading'
import classes from './table.css';
class BlocksMinedTable extends Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
render() {
const table = this.props.data.map((data, i) => {
const conversion = data.Rewards / 10000000000000000000;
return <MinedBlockTable
key={`${data.Hash}${i}`}
Hash={data.Hash}
Number={data.Number}
Coinbase={data.Coinbase}
Age={data.Age}
GasUsed={data.GasUsed}
GasLimit={data.GasLimit}
UncleCount={data.UncleCount}
TxCount={data.TxCount}
Reward={conversion}
detailBlockHandler={this.props.detailBlockHandler}
getBlocksMined={this.props.getBlocksMined}
/>
});
let combinedClasses = ['responsive-table', classes.table];
return (
<table className={combinedClasses.join(' ')}>
<thead className={classes.tHead}>
<tr>
<th scope="col">Height</th>
<th scope="col">Block Hash</th>
<th scope="col">Age</th>
<th scope="col">Txn</th>
<th scope="col">Uncles</th>
<th scope="col">Coinbase</th>
<th scope="col">GasUsed</th>
<th scope="col">GasLimit</th>
<th scope="col">Avg.GasPrice</th>
<th scope="col">Reward</th>
</tr>
</thead>
{table}
</table>
);
}
}
export default BlocksMinedTable;

View file

@ -0,0 +1,26 @@
import React from 'react';
import classes from './table.css';
import { Link } from 'react-router-dom'
const MinedBlockTable = (props) => {
return (
<tbody>
<tr>
<td><Link to="/blocks/detail" onClick={() => props.detailBlockHandler(props.Number)}>
{props.Number}
</Link></td>
<td className={classes.addressTag}>{props.Hash}</td>
<td>{props.Age}</td>
<td>{props.TxCount}</td>
<td>{props.UncleCount}</td>
<td className={classes.addressTag}>{props.Coinbase}</td>
<td>{props.GasUsed}</td>
<td>{props.GasLimit}</td>
<td>TBD</td>
<td>{props.Reward}</td>
</tr>
</tbody>
)
};
export default MinedBlockTable;

View file

@ -0,0 +1,51 @@
import React, { Component } from 'react';
import TransactionsTable from './transactionTable';
import classes from './table.css';
class BlockTransactionTable extends Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
render() {
const table = this.props.data.map((data, i) => {
const conversion = data.Cost / 10000000000000000000;
return <TransactionsTable
key={`${data.TxHash}${i}`}
age={data.Age}
txHash={data.TxHash}
blockNumber={data.BlockNumber}
to={data.To}
from={data.From}
value={data.Amount}
cost={conversion}
getBlockTransactions={this.props.getBlockTransactions}
detailTransactionHandler={this.props.detailTransactionHandler}
detailAccountHandler={this.props.detailAccountHandler}
/>
})
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 BlockTransactionTable;

View file

@ -6,6 +6,7 @@ class DetailTransactionTable extends Component {
render() { render() {
let data = this.props.data let data = this.props.data
let combinedClasses = ['responsive-table', classes.table]; let combinedClasses = ['responsive-table', classes.table];
const conversion = data.Cost / 10000000000000000000;
return ( return (
<table className={combinedClasses.join(' ')}> <table className={combinedClasses.join(' ')}>
<tbody> <tbody>
@ -51,7 +52,7 @@ class DetailTransactionTable extends Component {
</tr> </tr>
<tr> <tr>
<th scope="col">Actual Tx Cost/Fee:</th> <th scope="col">Actual Tx Cost/Fee:</th>
<td>{data.Cost}</td> <td>{conversion}</td>
</tr> </tr>
<tr> <tr>
<th scope="col">Nonce:</th> <th scope="col">Nonce:</th>

View file

@ -25,6 +25,7 @@ class TransactionTable extends Component {
render() { render() {
const table = this.state.data.map((data, i) => { const table = this.state.data.map((data, i) => {
const conversion = data.Cost / 10000000000000000000;
return <TransactionsTable return <TransactionsTable
key={`${data.TxHash}${i}`} key={`${data.TxHash}${i}`}
age={data.Age} age={data.Age}
@ -33,8 +34,10 @@ class TransactionTable extends Component {
to={data.To} to={data.To}
from={data.From} from={data.From}
value={data.Amount} value={data.Amount}
cost={data.Cost} cost={conversion}
getBlockTransactions={this.props.getBlockTransactions}
detailTransactionHandler={this.props.detailTransactionHandler} detailTransactionHandler={this.props.detailTransactionHandler}
detailAccountHandler={this.props.detailAccountHandler}
/> />
}) })

View file

@ -5,7 +5,7 @@ import { Link } from 'react-router-dom'
const TransactionTable = (props) => { const TransactionTable = (props) => {
let flag; let flag;
if(props.txHash.indexOf("GENESIS") != -1) { if(props.txHash.indexOf("GENESIS") !== -1) {
flag = false flag = false
}else { }else {
flag = true flag = true
@ -18,11 +18,11 @@ const TransactionTable = (props) => {
<Link to="/transaction/details" className={flag ? "" : classes.disabled} onClick={() => props.detailTransactionHandler(props.txHash)}> <Link to="/transaction/details" className={flag ? "" : classes.disabled} onClick={() => props.detailTransactionHandler(props.txHash)}>
{props.txHash}</Link> {props.txHash}</Link>
</td> </td>
<td>{props.blockNumber}</td> <td><Link to="/block/transactions" onClick={() => props.getBlockTransactions(props.blockNumber)}>{props.blockNumber}</Link></td>
<td>{props.age}</td> <td>{props.age}</td>
<td className={classes.fromTag}>{props.from}</td> <td className={flag ? classes.fromTag : classes.disabled }><Link to="/account/detail" onClick={() => props.detailAccountHandler(props.from)}>{props.from}</Link></td>
<td><img className={classes.arrow} src={arrow} alt="arrow"/></td> <td><img className={classes.arrow} src={arrow} alt="arrow"/></td>
<td className={classes.toTag}>{props.to}</td> <td className={classes.toTag}><Link to="/account/detail" onClick={() => props.detailAccountHandler(props.to)}>{props.to}</Link></td>
<td>{props.value}</td> <td>{props.value}</td>
<td>{props.cost}</td> <td>{props.cost}</td>
</tr> </tr>

View file

@ -11,12 +11,15 @@ import TransactionRow from '../components/table/transactions/transactionRow';
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"; import DetailTransactionTable from "../components/table/transactions/transactionDetailsRow";
import BlockTxs from "../components/table/transactions/blockTx";
///**BLOCKS**/// ///**BLOCKS**///
import BlocksRow from '../components/table/blocks/blockRows'; import BlocksRow from '../components/table/blocks/blockRows';
import DetailBlockTable from '../components/table/blocks/blocksDetailsRow'; 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 BlocksMinedTable from "../components/table/blocks/blocksMined";
import BlockCoinbaseHeader from "../components/nav/blockHeaders/blockCoinbaseHeader";
///**ACCOUNTS**/// ///**ACCOUNTS**///
import AccountsRow from '../components/table/accounts/accountRows'; import AccountsRow from '../components/table/accounts/accountRows';
import DetailAccountsTable from "../components/table/accounts/detailAccountsRow"; import DetailAccountsTable from "../components/table/accounts/detailAccountsRow";
@ -31,6 +34,8 @@ class App extends Component {
blockDetailData: [], blockDetailData: [],
transactionDetailData: [], transactionDetailData: [],
accountDetailData: [], accountDetailData: [],
blocksMined: [],
blockTransactions: [],
reqAccount: '' reqAccount: ''
}; };
} }
@ -43,7 +48,7 @@ class App extends Component {
catch(error) { catch(error) {
console.log(error) console.log(error)
} }
} };
detailTransactionHandler = async(txHash) => { detailTransactionHandler = async(txHash) => {
try { try {
@ -53,7 +58,7 @@ class App extends Component {
catch(error) { catch(error) {
console.log(error) console.log(error)
} }
} };
detailAccountHandler = async(addr) => { detailAccountHandler = async(addr) => {
try { try {
@ -63,7 +68,27 @@ class App extends Component {
catch(error) { catch(error) {
console.log(error) console.log(error)
} }
};
getBlockTransactions = async(blockNumber) => {
try {
const response = await axios.get(`http://localhost:8080/api/get_all_transactions_from_block/${blockNumber}`)
await this.setState({ blockTransactions: response.data, reqBlockNum: blockNumber })
} }
catch(error) {
console.log(error)
}
};
getBlocksMined = async(coinbase) => {
try {
const response = await axios.get(`http://localhost:8080/api/get_blocks_mined/${coinbase}`)
await this.setState({ blocksMined: response.data, reqCoinbase: coinbase })
}
catch(error) {
console.log(error)
}
};
render() { render() {
return ( return (
@ -78,14 +103,20 @@ class App extends Component {
<Route path="/transactions" render={({match}) => <Route path="/transactions" render={({match}) =>
<div> <div>
<TransactionHeader /> <TransactionHeader />
<TransactionRow detailTransactionHandler={this.detailTransactionHandler}/> <TransactionRow
getBlockTransactions={this.getBlockTransactions}
detailTransactionHandler={this.detailTransactionHandler}
detailAccountHandler={this.detailAccountHandler}/>
</div>} </div>}
/> />
<Route path="/blocks" exact render={({match}) => <Route path="/blocks" exact render={({match}) =>
<div> <div>
<BlockHeader/> <BlockHeader/>
<BlocksRow detailBlockHandler={this.detailBlockHandler}/> <BlocksRow
getBlocksMined={this.getBlocksMined}
getBlockTransactions={this.getBlockTransactions}
detailBlockHandler={this.detailBlockHandler}/>
</div>} </div>}
/> />
@ -110,14 +141,40 @@ class App extends Component {
<BlockDetailHeader <BlockDetailHeader
blockNumber={this.state.blockDetailData.Number}/> blockNumber={this.state.blockDetailData.Number}/>
<DetailBlockTable <DetailBlockTable
getBlockTransactions={this.getBlockTransactions}
data={this.state.blockDetailData}/> data={this.state.blockDetailData}/>
</div>} </div>}
/> />
<Route path="/block/transactions" exact render={({match}) =>
<div>
<BlockDetailHeader
blockNumber={this.state.reqBlockNum}/>
<BlockTxs
data={this.state.blockTransactions}
getBlockTransactions={this.getBlockTransactions}
detailTransactionHandler={this.detailTransactionHandler}
detailAccountHandler={this.detailAccountHandler}/>
</div>}
/>
<Route path="/mined/blocks" exact render={({match}) =>
<div>
<BlockCoinbaseHeader
coinbase={this.state.reqCoinbase}/>
<BlocksMinedTable
getBlockTransactions={this.getBlockTransactions}
getBlocksMined={this.getBlocksMined}
data={this.state.blocksMined}/>
</div>}
/>
<Route path="/account/detail" exact render={({match}) => <Route path="/account/detail" exact render={({match}) =>
<div> <div>
<AccountDetailHeader <AccountDetailHeader
addr={this.state.reqAccount}/> addr={this.state.reqAccount}
data={this.state.accountDetailData}/>
<DetailAccountsTable <DetailAccountsTable
transactionDetailHandler={this.detailTransactionHandler} transactionDetailHandler={this.detailTransactionHandler}
addr={this.state.reqAccount} addr={this.state.reqAccount}

View file

@ -11,6 +11,7 @@ CREATE TABLE IF NOT EXISTS blocks (
difficulty bigint, difficulty bigint,
size text, size text,
nonce numeric, nonce numeric,
rewards numeric,
number bigint number bigint
); );

View file

@ -22,7 +22,7 @@ type SBlock struct {
Number string Number string
GasUsed string GasUsed string
GasLimit string GasLimit string
TxCount stringgit@github.com:ShyftNetwork/shyft_go-ethereum.git TxCount string
UncleCount string UncleCount string
Age string Age string
ParentHash string ParentHash string
@ -30,6 +30,7 @@ type SBlock struct {
Difficulty string Difficulty string
Size string Size string
Nonce string Nonce string
Rewards string
} }
//blockRes struct //blockRes struct
@ -76,10 +77,10 @@ type ShyftTxEntryPretty struct {
From string From string
BlockHash string BlockHash string
BlockNumber string BlockNumber string
Amount uint64 Amount string
GasPrice uint64 GasPrice uint64
Gas uint64 Gas uint64
GasLimit uint64 GasLimit string
Cost uint64 Cost uint64
Nonce uint64 Nonce uint64
Status string Status string
@ -104,12 +105,7 @@ type SendAndReceive struct {
//WriteBlock writes to block info to sql db //WriteBlock writes to block info to sql db
func WriteBlock(sqldb *sql.DB, block *types.Block, receipts []*types.Receipt) error { func WriteBlock(sqldb *sql.DB, block *types.Block, receipts []*types.Receipt) error {
//Need to create field in postgres db isContract : True || False rewards := WriteMinerRewards(sqldb,block)
//Need to fix nonce numeric issue (attempt to reproduce and record)
//Need to update tx To Field where null with Contract Address
//Need to update account table with that Contract Address
//Need to update AccountNonce and Balance of Tx To field || Contract Address
WriteMinerRewards(sqldb,block)
coinbase := block.Header().Coinbase.String() coinbase := block.Header().Coinbase.String()
number := block.Header().Number.String() number := block.Header().Number.String()
gasUsed := block.Header().GasUsed gasUsed := block.Header().GasUsed
@ -128,15 +124,14 @@ func WriteBlock(sqldb *sql.DB, block *types.Block, receipts []*types.Receipt) er
} }
age := time.Unix(i, 0) age := time.Unix(i, 0)
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` sqlStatement := `INSERT INTO blocks(hash, coinbase, number, gasUsed, gasLimit, txCount, uncleCount, age, parentHash, uncleHash, difficulty, size, rewards, nonce) VALUES(($1), ($2), ($3), ($4), ($5), ($6), ($7), ($8), ($9), ($10), ($11), ($12),($13), ($14)) RETURNING number`
qerr := sqldb.QueryRow(sqlStatement, block.Header().Hash().Hex(), coinbase, number, gasUsed, gasLimit, txCount, uncleCount, age, parentHash, uncleHash, blockDifficulty, blockSize, blockNonce).Scan(&number) qerr := sqldb.QueryRow(sqlStatement, block.Header().Hash().Hex(), coinbase, number, gasUsed, gasLimit, txCount, uncleCount, age, parentHash, uncleHash, blockDifficulty, blockSize, rewards, blockNonce).Scan(&number)
if qerr != nil { if qerr != nil {
panic(qerr) panic(qerr)
} }
if block.Transactions().Len() > 0 { if block.Transactions().Len() > 0 {
for _, tx := range block.Transactions() { for _, tx := range block.Transactions() {
//WriteMinerRewards(sqldb, block)
WriteTransactions(sqldb, tx, block.Header().Hash(), block.Header().Number.String(), receipts, age, gasLimit) WriteTransactions(sqldb, tx, block.Header().Hash(), block.Header().Number.String(), receipts, age, gasLimit)
if block.Transactions()[0].To() != nil { if block.Transactions()[0].To() != nil {
WriteFromBalance(sqldb, tx) WriteFromBalance(sqldb, tx)
@ -411,7 +406,7 @@ func WriteBalanceHelper(sqldb *sql.DB, tx *types.Transaction) (SendAndReceive, s
// uncle blocks, account balance updates based on reorgs, diverges that get dropped. // uncle blocks, account balance updates based on reorgs, diverges that get dropped.
// Reason for this is because the accounts are not deterministic like the block and tx hashes. // Reason for this is because the accounts are not deterministic like the block and tx hashes.
// @TODO: Calculate reorg // @TODO: Calculate reorg
func WriteMinerRewards(sqldb *sql.DB, block *types.Block) { func WriteMinerRewards(sqldb *sql.DB, block *types.Block) string {
minerAddr := block.Coinbase().String() minerAddr := block.Coinbase().String()
shyftConduitAddress := Rewards.ShyftNetworkConduitAddress.String() shyftConduitAddress := Rewards.ShyftNetworkConduitAddress.String()
// Calculate the total gas used in the block // Calculate the total gas used in the block
@ -443,9 +438,18 @@ func WriteMinerRewards(sqldb *sql.DB, block *types.Block) {
StoreReward(sqldb, minerAddr, totalMinerReward) StoreReward(sqldb, minerAddr, totalMinerReward)
StoreReward(sqldb, shyftConduitAddress, Rewards.ShyftNetworkBlockReward) StoreReward(sqldb, shyftConduitAddress, Rewards.ShyftNetworkBlockReward)
var uncRewards = new(big.Int)
for i := 0; i < len(uncleAddrs); i++ { for i := 0; i < len(uncleAddrs); i++ {
uncRewards := uncleRewards[i]
fmt.Println(uncRewards)
StoreReward(sqldb, uncleAddrs[i], uncleRewards[i]) StoreReward(sqldb, uncleAddrs[i], uncleRewards[i])
} }
fullRewardValue := new(big.Int)
fullRewardValue.Add(totalMinerReward, Rewards.ShyftNetworkBlockReward)
fullRewardValue.Add(fullRewardValue, uncRewards)
return fullRewardValue.String()
} }
func StoreReward(sqldb *sql.DB, address string, reward *big.Int) { func StoreReward(sqldb *sql.DB, address string, reward *big.Int) {
@ -497,16 +501,7 @@ func GetAllBlocks(sqldb *sql.DB) string {
var arr blockRes var arr blockRes
var blockArr string var blockArr string
rows, err := sqldb.Query(` rows, err := sqldb.Query(`
SELECT SELECT * FROM blocks`)
hash,
coinbase,
gasused,
gaslimit,
txcount,
unclecount,
age,
number
FROM blocks`)
if err != nil { if err != nil {
fmt.Println("err") fmt.Println("err")
} }
@ -520,6 +515,12 @@ func GetAllBlocks(sqldb *sql.DB) string {
var txCount string var txCount string
var uncleCount string var uncleCount string
var age string var age string
var parentHash string
var uncleHash string
var difficulty string
var size string
var nonce string
var rewards string
var num string var num string
err = rows.Scan( err = rows.Scan(
@ -530,8 +531,13 @@ func GetAllBlocks(sqldb *sql.DB) string {
&txCount, &txCount,
&uncleCount, &uncleCount,
&age, &age,
&num, &parentHash,
) &uncleHash,
&difficulty,
&size,
&nonce,
&rewards,
&num,)
arr.Blocks = append(arr.Blocks, SBlock{ arr.Blocks = append(arr.Blocks, SBlock{
Hash: hash, Hash: hash,
@ -541,6 +547,12 @@ func GetAllBlocks(sqldb *sql.DB) string {
TxCount: txCount, TxCount: txCount,
UncleCount: uncleCount, UncleCount: uncleCount,
Age: age, Age: age,
ParentHash:parentHash,
UncleHash:uncleHash,
Difficulty:difficulty,
Size: size,
Nonce:nonce,
Rewards: rewards,
Number: num, Number: num,
}) })
@ -568,6 +580,7 @@ func GetBlock(sqldb *sql.DB, blockNumber string) string {
var difficulty string var difficulty string
var size string var size string
var nonce string var nonce string
var rewards string
var num string var num string
row.Scan( row.Scan(
&hash, &hash,
@ -582,6 +595,7 @@ func GetBlock(sqldb *sql.DB, blockNumber string) string {
&difficulty, &difficulty,
&size, &size,
&nonce, &nonce,
&rewards,
&num,) &num,)
block := SBlock{ block := SBlock{
@ -597,6 +611,7 @@ func GetBlock(sqldb *sql.DB, blockNumber string) string {
Difficulty:difficulty, Difficulty:difficulty,
Size: size, Size: size,
Nonce:nonce, Nonce:nonce,
Rewards: rewards,
Number: num, Number: num,
} }
json, _ := json.Marshal(block) json, _ := json.Marshal(block)
@ -618,6 +633,7 @@ func GetRecentBlock(sqldb *sql.DB) string {
var difficulty string var difficulty string
var size string var size string
var nonce string var nonce string
var rewards string
var num string var num string
row.Scan( row.Scan(
&hash, &hash,
@ -632,6 +648,7 @@ func GetRecentBlock(sqldb *sql.DB) string {
&difficulty, &difficulty,
&size, &size,
&nonce, &nonce,
&rewards,
&num,) &num,)
block := SBlock{ block := SBlock{
@ -647,6 +664,7 @@ func GetRecentBlock(sqldb *sql.DB) string {
Difficulty:difficulty, Difficulty:difficulty,
Size: size, Size: size,
Nonce:nonce, Nonce:nonce,
Rewards: rewards,
Number: num, Number: num,
} }
json, _ := json.Marshal(block) json, _ := json.Marshal(block)
@ -656,7 +674,7 @@ func GetRecentBlock(sqldb *sql.DB) string {
func GetAllTransactionsFromBlock(sqldb *sql.DB, blockNumber string) string { func GetAllTransactionsFromBlock(sqldb *sql.DB, blockNumber string) string {
var arr txRes var arr txRes
var txx string var txx string
sqlStatement := `SELECT * FROM txs WHERE blockNumber=$1` sqlStatement := `SELECT * FROM txs WHERE blocknumber=$1`
rows, err := sqldb.Query(sqlStatement, blockNumber) rows, err := sqldb.Query(sqlStatement, blockNumber)
if err != nil { if err != nil {
fmt.Println("err") fmt.Println("err")
@ -668,10 +686,10 @@ func GetAllTransactionsFromBlock(sqldb *sql.DB, blockNumber string) string {
var from_addr string var from_addr string
var blockhash string var blockhash string
var blocknumber string var blocknumber string
var amount uint64 var amount string
var gasprice uint64 var gasprice uint64
var gas uint64 var gas uint64
var gasLimit uint64 var gasLimit string
var txfee uint64 var txfee uint64
var nonce uint64 var nonce uint64
var status string var status string
@ -721,6 +739,72 @@ func GetAllTransactionsFromBlock(sqldb *sql.DB, blockNumber string) string {
return txx return txx
} }
func GetAllBlocksMinedByAddress(sqldb *sql.DB, coinbase string) string {
var arr blockRes
var blockArr string
sqlStatement := `SELECT * FROM blocks WHERE coinbase=$1`
rows, err := sqldb.Query(sqlStatement, coinbase)
if err != nil {
fmt.Println("err")
}
defer rows.Close()
for rows.Next() {
var hash string
var coinbase string
var gasUsed string
var gasLimit string
var txCount string
var uncleCount string
var age string
var parentHash string
var uncleHash string
var difficulty string
var size string
var nonce string
var rewards string
var num string
err = rows.Scan(
&hash,
&coinbase,
&gasUsed,
&gasLimit,
&txCount,
&uncleCount,
&age,
&parentHash,
&uncleHash,
&difficulty,
&size,
&nonce,
&rewards,
&num,)
arr.Blocks = append(arr.Blocks, SBlock{
Hash: hash,
Coinbase: coinbase,
GasUsed: gasUsed,
GasLimit: gasLimit,
TxCount: txCount,
UncleCount: uncleCount,
Age: age,
ParentHash:parentHash,
UncleHash:uncleHash,
Difficulty:difficulty,
Size: size,
Nonce:nonce,
Rewards: rewards,
Number: num,
})
blocks, _ := json.Marshal(arr.Blocks)
blocksFmt := string(blocks)
blockArr = blocksFmt
}
return blockArr
}
//GetAllTransactions getter fn for API //GetAllTransactions getter fn for API
func GetAllTransactions(sqldb *sql.DB) string { func GetAllTransactions(sqldb *sql.DB) string {
var arr txRes var arr txRes
@ -737,10 +821,10 @@ func GetAllTransactions(sqldb *sql.DB) string {
var from_addr string var from_addr string
var blockhash string var blockhash string
var blocknumber string var blocknumber string
var amount uint64 var amount string
var gasprice uint64 var gasprice uint64
var gas uint64 var gas uint64
var gasLimit uint64 var gasLimit string
var txfee uint64 var txfee uint64
var nonce uint64 var nonce uint64
var status string var status string
@ -799,10 +883,10 @@ func GetTransaction(sqldb *sql.DB, txHash string) string {
var from_addr string var from_addr string
var blockhash string var blockhash string
var blocknumber string var blocknumber string
var amount uint64 var amount string
var gasprice uint64 var gasprice uint64
var gas uint64 var gas uint64
var gasLimit uint64 var gasLimit string
var txfee uint64 var txfee uint64
var nonce uint64 var nonce uint64
var status string var status string
@ -924,10 +1008,10 @@ func GetAccountTxs(sqldb *sql.DB, address string) string {
var from_addr string var from_addr string
var blockhash string var blockhash string
var blocknumber string var blocknumber string
var amount uint64 var amount string
var gasprice uint64 var gasprice uint64
var gas uint64 var gas uint64
var gasLimit uint64 var gasLimit string
var txfee uint64 var txfee uint64
var nonce uint64 var nonce uint64
var status string var status string

View file

@ -0,0 +1,9 @@
`npm install`
run `node deploy.js` to deploy the contract.
this will log out a contract in the geth logs.
set the ADDR environment variable to this contract address.
ie `export ADDR=<contract_addr>`
then run `node calltx.js`

View file

@ -0,0 +1,9 @@
var Web3 = require('web3')
var web3 = new Web3(new Web3.providers.HttpProvider("http://127.0.0.1:8545"));
var contract_address = process.env.ADDR
var mytokenContract = web3.eth.contract([{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"initialSupply","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]).at(contract_address)
console.log(mytokenContract.balanceOf('0x43EC6d0942f7fAeF069F7F63D0384a27f529B062'))
mytokenContract.transfer.sendTransaction('0x9e602164C5826ebb5A6B68E4AFD9Cd466043dc4A', 3, {from: '0x43EC6d0942f7fAeF069F7F63D0384a27f529B062', gas: 3000000})

View file

@ -0,0 +1,17 @@
var Web3 = require('web3')
var web3 = new Web3(new Web3.providers.HttpProvider("http://127.0.0.1:8545"));
var initialSupply = 50000
var mytokenContract = web3.eth.contract([{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"initialSupply","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]);
var mytoken = mytokenContract.new(
initialSupply,
{
from: web3.eth.accounts[0],
data: '0x608060405234801561001057600080fd5b5060405160208061033583398101806040528101908080519060200190929190505050806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550506102af806100866000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806370a0823114610051578063a9059cbb146100a8575b600080fd5b34801561005d57600080fd5b50610092600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506100f5565b6040518082815260200191505060405180910390f35b3480156100b457600080fd5b506100f3600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061010d565b005b60006020528060005260406000206000915090505481565b806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015151561015a57600080fd5b6000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401101515156101e757600080fd5b806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555050505600a165627a7a72305820c12ed9899b0830fb3b1c8938b12a5e3ee651fb5e6febea7863ea990d72ab04420029',
gas: '4700000'
}, function (e, contract){
console.log(e, contract);
if (typeof contract.address !== 'undefined') {
console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
}
})

View file

@ -0,0 +1,14 @@
{
"name": "token_contract",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"web3": "^0.20.5"
}
}

View file

@ -0,0 +1,21 @@
pragma solidity ^0.4.20;
contract MyToken {
/* This creates an array with all balances */
mapping (address => uint256) public balanceOf;
/* Initializes contract with initial supply tokens to the creator of the contract */
function MyToken(
uint256 initialSupply
) public {
balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens
}
/* Send coins */
function transfer(address _to, uint256 _value) public {
require(balanceOf[msg.sender] >= _value); // Check if the sender has enough
require(balanceOf[_to] + _value >= balanceOf[_to]); // Check for overflows
balanceOf[msg.sender] -= _value; // Subtract from the sender
balanceOf[_to] += _value; // Add the same to the recipient
}
}