diff --git a/blockExplorerApi/handler.go b/blockExplorerApi/handler.go index 1c55261cd5..7303aed137 100644 --- a/blockExplorerApi/handler.go +++ b/blockExplorerApi/handler.go @@ -54,25 +54,47 @@ func GetAllTransactions(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, txs) } -// GetBalance gets balance -func GetBalance(w http.ResponseWriter, r *http.Request) { - // vars := mux.Vars(r) - // address := vars["address"] +// GetAccount gets balance +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 { + return + } + + getAccountBalance := shyftdb.GetAccount(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, "Get Balances", addresses) + fmt.Fprintln(w, getAccountBalance) } -// GetBalances gets balances -func GetBalances(w http.ResponseWriter, r *http.Request) { - +// GetAllAccounts gets balances +func GetAllAccounts(w http.ResponseWriter, r *http.Request) { + connStr := "user=postgres dbname=shyftdb sslmode=disable" + blockExplorerDb, err := sql.Open("postgres", connStr) + if err != nil { + return + } + allAccounts := shyftdb.GetAllAccounts(blockExplorerDb) + 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, "Get Balances", addresses) + fmt.Fprintln(w, allAccounts) } //GetBlock returns block json @@ -98,23 +120,18 @@ func GetBlock(w http.ResponseWriter, r *http.Request) { // GetAllBlocks response func GetAllBlocks(w http.ResponseWriter, r *http.Request) { - connStr := "user=postgres dbname=shyftdb sslmode=disable" blockExplorerDb, err := sql.Open("postgres", connStr) if err != nil { return } - block3 := shyftdb.GetAllBlocks(blockExplorerDb) - 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, block3) } diff --git a/blockExplorerApi/routes.go b/blockExplorerApi/routes.go index dcd5831d8b..f2468a0b08 100644 --- a/blockExplorerApi/routes.go +++ b/blockExplorerApi/routes.go @@ -16,16 +16,16 @@ type Routes []Route var routes = Routes{ Route{ - "GetBalance", + "GetAccount", "GET", - "/api/get_balance/", - GetBalance, + "/api/get_account/{address}", + GetAccount, }, Route{ - "GetBalances", + "GetAllAccounts", "GET", - "/api/get_balances/{addresses}", - GetBalances, + "/api/get_all_accounts", + GetAllAccounts, }, Route{ "GetAllBlocks", diff --git a/shyftDb/postgres_setup/create_tables.psql b/shyftDb/postgres_setup/create_tables.psql index 59f9730587..16506fa497 100644 --- a/shyftDb/postgres_setup/create_tables.psql +++ b/shyftDb/postgres_setup/create_tables.psql @@ -5,9 +5,9 @@ CREATE TABLE IF NOT EXISTS blocks ( ); CREATE TABLE IF NOT EXISTS txs ( - txHash text primary key, - to_addr text references accounts(addr), - from_addr text references accounts(addr), + txHash text, + to_addr text, + from_addr text, blockhash text references blocks(hash), amount numeric, gasprice numeric, diff --git a/shyftDb/postgres_setup/drop_tables.psql b/shyftDb/postgres_setup/drop_tables.psql index 2a985786f2..80625a022b 100644 --- a/shyftDb/postgres_setup/drop_tables.psql +++ b/shyftDb/postgres_setup/drop_tables.psql @@ -1,2 +1,3 @@ DROP TABLE txs; -DROP TABLE blocks; \ No newline at end of file +DROP TABLE blocks; +DROP TABLE accounts; \ No newline at end of file diff --git a/shyftdb/shyft_database_util.go b/shyftdb/shyft_database_util.go index 8fd9193f29..03e7be7694 100644 --- a/shyftdb/shyft_database_util.go +++ b/shyftdb/shyft_database_util.go @@ -10,6 +10,8 @@ import ( "database/sql" + "log" + _ "github.com/lib/pq" ) @@ -28,8 +30,15 @@ type blockRes struct { Blocks []SBlock } -type txRes struct { - TxEntry []ShyftTxEntryPretty +type SAccounts struct { + Addr string + Balance string +} + +type accountRes struct { + addr string + balance string + AllAccounts []SAccounts } //ShyftTxEntry structure @@ -45,6 +54,10 @@ type ShyftTxEntry struct { Data []byte } +type txRes struct { + TxEntry []ShyftTxEntryPretty +} + type ShyftTxEntryPretty struct { TxHash string To string @@ -62,9 +75,12 @@ type ShyftAccountEntry struct { Txs []string } -type ShyftSenderEntry struct { - Address string - Balance *big.Int +type SendAndReceive struct { + To string + From string + Amount string + Address string + Balance string } //WriteBlock writes to block info to sql db @@ -131,84 +147,91 @@ func WriteTransactions(sqldb *sql.DB, tx *types.Transaction, blockHash common.Ha return nil } -//WriteSenderBalance writes senders balance to accounts db +//WriteFromBalance writes senders balance to accounts db func WriteFromBalance(sqldb *sql.DB, tx *types.Transaction) error { - sender := ShyftSenderEntry{ - Address: tx.From().Hex(), - Balance: tx.Value(), - } + sendAndReceiveData, balanceRec, balanceSen := WriteBalanceHelper(sqldb, tx) + toAddr := sendAndReceiveData.To + fromAddr := sendAndReceiveData.From + amount := sendAndReceiveData.Amount + balanceReceiver := balanceRec + balanceSender := balanceSen - addr := sender.Address - balance := sender.Balance.String() - fmt.Println("++++++++++++++++++++++", addr) - fmt.Println("++++++++++++++++++++++", balance) - sqlStatement := `INSERT INTO accounts(addr, balance) VALUES(($1), ($2)) RETURNING addr` - qerr := sqldb.QueryRow(sqlStatement, addr, balance).Scan(&addr) - if qerr != nil { - panic(qerr) + var response string + sqlExistsStatement := `SELECT balance from accounts WHERE addr = ($1)` + err := sqldb.QueryRow(sqlExistsStatement, toAddr).Scan(&response) + switch { + case err == sql.ErrNoRows: + fmt.Println("No rows error :)") + + sqlStatement := `INSERT INTO accounts(addr, balance) VALUES(($1), ($2)) RETURNING addr` + insertErr := sqldb.QueryRow(sqlStatement, toAddr, amount).Scan(&toAddr) + if insertErr != nil { + panic(insertErr) + } + case err != nil: + log.Fatal(err) + default: + + var newBalanceReceiver big.Int + var newBalanceSender big.Int + updateSQLStatement := `UPDATE accounts SET balance = ($2) WHERE addr = ($1)` + + r := new(big.Int) + _, err := fmt.Sscan(balanceReceiver, r) + if err != nil { + log.Println("error scanning value:", err) + } + + s := new(big.Int) + _, error := fmt.Sscan(balanceSender, s) + if error != nil { + log.Println("error scanning value:", error) + } + + newBalanceReceiver.Add(r, tx.Value()) + newBalanceSender.Sub(s, tx.Value()) + + _, err = sqldb.Exec(updateSQLStatement, toAddr, newBalanceReceiver.String()) + if err != nil { + panic(err) + } + + _, err = sqldb.Exec(updateSQLStatement, fromAddr, newBalanceSender.String()) + if err != nil { + panic(err) + } } return nil } -// key := append([]byte("acc-")[:], tx.From().Hash().Bytes()[:]...) -// // The from (sender) addr must have balance. If it fails to retrieve there is a bigger issue. -// retrievedData, err := db.Get(key, nil) -// if err != nil { -// log.Crit("From MUST have eth and no record found", "err", err) -// } -// var decodedData ShyftAccountEntry -// d := gob.NewDecoder(bytes.NewBuffer(retrievedData)) -// if err := d.Decode(&decodedData); err != nil { -// log.Crit("Failed to decode From data:", "err", err) -// } -// decodedData.Balance.Sub(decodedData.Balance, tx.Value()) -// decodedData.Txs = append(decodedData.Txs, tx.Hash().String()) -// // Encode updated data -// var encodedData bytes.Buffer -// encoder := gob.NewEncoder(&encodedData) -// if err := encoder.Encode(decodedData); err != nil { -// log.Crit("Faild to encode From Account data", "err", err) -// } -// if err := db.Put(key, encodedData.Bytes(), nil); err != nil { -// log.Crit("Could not write the From account data", "err", err) -// } +func WriteBalanceHelper(sqldb *sql.DB, tx *types.Transaction) (SendAndReceive, string, string) { + sendAndReceiveData := SendAndReceive{ + To: tx.To().Hex(), + From: tx.From().Hex(), + Amount: tx.Value().String(), + } -// func WriteToBalance(db *leveldb.DB, tx *types.Transaction) { -// key := append([]byte("acc-")[:], tx.To().Hash().Bytes()[:]...) -// var txs []string + toAddr := sendAndReceiveData.To + fromAddr := sendAndReceiveData.From -// retrievedData, err := db.Get(key, nil) -// if err != nil { -// accData := ShyftAccountEntry{ -// Balance: tx.Value(), -// Txs: append(txs, tx.Hash().String()), -// } -// var encodedData bytes.Buffer -// encoder := gob.NewEncoder(&encodedData) -// if err := encoder.Encode(accData); err != nil { -// log.Crit("Faild to encode To Account data", "err", err) -// } -// if err := db.Put(key, encodedData.Bytes(), nil); err != nil { -// log.Crit("Could not write the TO account's first tx", "err", err) -// } -// } -// var decodedData ShyftAccountEntry -// d := gob.NewDecoder(bytes.NewBuffer(retrievedData)) -// if err := d.Decode(&decodedData); err != nil { -// log.Crit("Failed to decode To account data:", "err", err) -// } -// decodedData.Balance.Add(decodedData.Balance, tx.Value()) -// decodedData.Txs = append(decodedData.Txs, tx.Hash().String()) -// // Encode updated data -// var encodedData bytes.Buffer -// encoder := gob.NewEncoder(&encodedData) -// if err := encoder.Encode(decodedData); err != nil { -// log.Crit("Faild to encode To Account data", "err", err) -// } -// if err := db.Put(key, encodedData.Bytes(), nil); err != nil { -// log.Crit("Could not write the To account data", "err", err) -// } -// } + getAccountBalanceReceiver := GetAccount(sqldb, toAddr) + getAccountBalanceSender:= GetAccount(sqldb, fromAddr) + + var receiverBalance SendAndReceive + if err := json.Unmarshal([]byte(getAccountBalanceReceiver), &receiverBalance); err != nil { + log.Fatal(err) + } + + var senderBalance SendAndReceive + if err := json.Unmarshal([]byte(getAccountBalanceSender), &senderBalance); err != nil { + log.Fatal(err) + } + + balanceReceiver := receiverBalance.Balance + balanceSender := senderBalance.Balance + + return sendAndReceiveData, balanceReceiver, balanceSender +} // @NOTE: This function is extremely complex and requires heavy testing and knowdlege of edge cases: // uncle blocks, account balance updates based on reorgs, diverges that get dropped. @@ -388,14 +411,14 @@ func GetAllTransactions(sqldb *sql.DB) string { //GetTransaction fn returns single tx func GetTransaction(sqldb *sql.DB) string { sqlStatement := `SELECT - txhash, - to_addr, - from_addr, - blockhash, - amount, - gasprice, - gas, - nonce + txhash, + to_addr, + from_addr, + blockhash, + amount, + gasprice, + gas, + nonce FROM txs WHERE nonce=$1;` row := sqldb.QueryRow(sqlStatement, 1) var txhash string @@ -421,4 +444,56 @@ func GetTransaction(sqldb *sql.DB) string { json, _ := json.Marshal(tx) return string(json) +} + +//GetAccount returns account balances +func GetAccount(sqldb *sql.DB, address string) string { + sqlStatement := `SELECT * FROM accounts WHERE addr=$1;` + row := sqldb.QueryRow(sqlStatement, address) + var addr string + var balance string + + row.Scan(&addr, &balance) + + account := SAccounts{ + Addr: addr, + Balance: balance, + } + json, _ := json.Marshal(account) + return string(json) +} + +//GetAllAccounts returns all accounts and balances +func GetAllAccounts(sqldb *sql.DB) string { + var array accountRes + var accountsArr string + accs, err := sqldb.Query(` + SELECT + addr, + balance + FROM accounts`) + if err != nil { + fmt.Println(err) + } + + defer accs.Close() + //// + for accs.Next() { + var addr string + var balance string + err = accs.Scan( + &addr, + &balance, + ) + + array.AllAccounts = append(array.AllAccounts, SAccounts{ + Addr: addr, + Balance: balance, + }) + + accounts, _ := json.Marshal(array.AllAccounts) + accountsFmt := string(accounts) + accountsArr = accountsFmt + } + return accountsArr } \ No newline at end of file diff --git a/simulations/sendTransactions.js b/simulations/sendTransactions.js index 9f01473ee7..73aeba9e9e 100644 --- a/simulations/sendTransactions.js +++ b/simulations/sendTransactions.js @@ -2,18 +2,17 @@ var firstAccount = web3.eth.accounts[0] var secondAccount = web3.eth.accounts[1] var thirdAccount = web3.eth.accounts[2] -for (var i = 0; i < 1; i++) { +for (var i = 0; i < 10; i++) { console.log('\t\t' + (i + 1) + ' - Transactions') web3.eth.sendTransaction({ - from: web3.eth.accounts[0], - to: web3.eth.accounts[1], - value: 623, + from: web3.eth.accounts[2], + to: web3.eth.accounts[0], + value: 5, gas: 50000, gasPrice: 20 }); - web3.eth.sendTransaction({ - from: web3.eth.accounts[0], + from: web3.eth.accounts[1], to: web3.eth.accounts[2], value: 291, gas: 50000, @@ -21,8 +20,8 @@ for (var i = 0; i < 1; i++) { }); web3.eth.sendTransaction({ - from: web3.eth.accounts[1], - to: web3.eth.accounts[3], + from: web3.eth.accounts[0], + to: web3.eth.accounts[1], value: 53039, gas: 50000, gasPrice: 20