modified write accounts

This commit is contained in:
Dustin Brickwood 2018-04-24 13:12:58 -04:00
parent 7e9aa2c8bd
commit 14b29696a3
2 changed files with 130 additions and 110 deletions

View file

@ -5,14 +5,18 @@ CREATE TABLE IF NOT EXISTS blocks (
); );
CREATE TABLE IF NOT EXISTS txs ( CREATE TABLE IF NOT EXISTS txs (
txHash text, txHash text primary key,
to_addr text, to_addr text references accounts(addr),
from_addr text, from_addr text references accounts(addr),
blockhash text, blockhash text references blocks(hash),
amount numeric, amount numeric,
gasprice numeric, gasprice numeric,
gas numeric, gas numeric,
nonce numeric, nonce numeric,
data bytea, data bytea
block text references blocks(hash) );
CREATE TABLE IF NOT EXISTS accounts (
addr text primary key unique,
balance numeric
); );

View file

@ -1,16 +1,12 @@
package shyftdb package shyftdb
import ( import (
"bytes"
"encoding/gob"
"encoding/json" "encoding/json"
"fmt" "fmt"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/syndtr/goleveldb/leveldb"
"database/sql" "database/sql"
@ -62,17 +58,22 @@ type ShyftTxEntryPretty struct {
} }
type ShyftAccountEntry struct { type ShyftAccountEntry struct {
Balance *big.Int Balance string
Txs []string Txs []string
} }
type ShyftSenderEntry struct {
Address string
Balance *big.Int
}
//WriteBlock writes to block info to sql db //WriteBlock writes to block info to sql db
func WriteBlock(sqldb *sql.DB, block *types.Block) error { func WriteBlock(sqldb *sql.DB, block *types.Block) error {
coinbase := block.Header().Coinbase.String() coinbase := block.Header().Coinbase.String()
number := block.Header().Number.String() number := block.Header().Number.String()
sqlStatement := `INSERT INTO blocks(hash, coinbase, number) VALUES(($1), ($2), ($3)) RETURNING number` sqlStatement := `INSERT INTO blocks(hash, coinbase, number) VALUES(($1), ($2), ($3)) RETURNING number`
qerr := sqldb.QueryRow(sqlStatement, block.Header().Hash().Hex(), coinbase, number).Scan(&number) //.Scan(&fun) qerr := sqldb.QueryRow(sqlStatement, block.Header().Hash().Hex(), coinbase, number).Scan(&number)
if qerr != nil { if qerr != nil {
panic(qerr) panic(qerr)
} }
@ -80,7 +81,7 @@ func WriteBlock(sqldb *sql.DB, block *types.Block) error {
if block.Transactions().Len() > 0 { if block.Transactions().Len() > 0 {
for _, tx := range block.Transactions() { for _, tx := range block.Transactions() {
WriteTransactions(sqldb, tx, block.Header().Hash()) WriteTransactions(sqldb, tx, block.Header().Hash())
//tx_bytes[i] = tx.Hash().Bytes() WriteFromBalance(sqldb, tx)
} }
} }
return nil return nil
@ -118,127 +119,142 @@ func WriteTransactions(sqldb *sql.DB, tx *types.Transaction, blockHash common.Ha
return nil return nil
} }
//WriteAccountBalances(db, tx) //WriteSenderBalance writes senders balance to accounts db
func WriteFromBalance(sqldb *sql.DB, tx *types.Transaction) error {
sender := ShyftSenderEntry{
Address: tx.From().Hex(),
Balance: tx.Value(),
}
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)
}
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 WriteToBalance(db *leveldb.DB, tx *types.Transaction) {
// key := append([]byte("acc-")[:], tx.To().Hash().Bytes()[:]...)
// var txs []string
// func WriteFromBalance(db *leveldb.DB, tx *types.Transaction) {
// 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) // retrievedData, err := db.Get(key, nil)
// if err != nil { // if err != nil {
// log.Crit("From MUST have eth and no record found", "err", err) // 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 // var decodedData ShyftAccountEntry
// d := gob.NewDecoder(bytes.NewBuffer(retrievedData)) // d := gob.NewDecoder(bytes.NewBuffer(retrievedData))
// if err := d.Decode(&decodedData); err != nil { // if err := d.Decode(&decodedData); err != nil {
// log.Crit("Failed to decode From data:", "err", err) // log.Crit("Failed to decode To account data:", "err", err)
// } // }
// decodedData.Balance.Sub(decodedData.Balance, tx.Value()) // decodedData.Balance.Add(decodedData.Balance, tx.Value())
// decodedData.Txs = append(decodedData.Txs, tx.Hash().String()) // decodedData.Txs = append(decodedData.Txs, tx.Hash().String())
// // Encode updated data // // Encode updated data
// var encodedData bytes.Buffer // var encodedData bytes.Buffer
// encoder := gob.NewEncoder(&encodedData) // encoder := gob.NewEncoder(&encodedData)
// if err := encoder.Encode(decodedData); err != nil { // if err := encoder.Encode(decodedData); err != nil {
// log.Crit("Faild to encode From Account data", "err", err) // log.Crit("Faild to encode To Account data", "err", err)
// } // }
// if err := db.Put(key, encodedData.Bytes(), nil); err != nil { // if err := db.Put(key, encodedData.Bytes(), nil); err != nil {
// log.Crit("Could not write the From account data", "err", err) // log.Crit("Could not write the To account data", "err", err)
// } // }
// } // }
func WriteToBalance(db *leveldb.DB, tx *types.Transaction) {
key := append([]byte("acc-")[:], tx.To().Hash().Bytes()[:]...)
var txs []string
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)
}
}
// @NOTE: This function is extremely complex and requires heavy testing and knowdlege of edge cases: // @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. // 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 reward if there are uncles // @TODO: Calculate reward if there are uncles
// @TODO: Calculate mining reward (most likely retrieve higher up in the operations) // @TODO: Calculate mining reward (most likely retrieve higher up in the operations)
// @TODO: Calculate reorg // @TODO: Calculate reorg
func WriteMinerReward(db *leveldb.DB, block *types.Block) { // func WriteMinerReward(db *leveldb.DB, block *types.Block) {
var totalGas *big.Int // var totalGas *big.Int
var txs []string // var txs []string
key := append([]byte("acc-")[:], block.Coinbase().Hash().Bytes()[:]...) // key := append([]byte("acc-")[:], block.Coinbase().Hash().Bytes()[:]...)
for _, tx := range block.Transactions() { // for _, tx := range block.Transactions() {
totalGas.Add(totalGas, new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(tx.Gas()))) // totalGas.Add(totalGas, new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(tx.Gas())))
} // }
retrievedData, err := db.Get(key, nil) // retrievedData, err := db.Get(key, nil)
if err != nil { // if err != nil {
// Assume time this account has had a tx // // Assume time this account has had a tx
// Balacne is exclusively minerreward + total gas from the block b/c no prior evm activity // // Balacne is exclusively minerreward + total gas from the block b/c no prior evm activity
// Txs would be empty because they have not had any transactions on the EVM // // Txs would be empty because they have not had any transactions on the EVM
// @TODO: Calc mining reward // // @TODO: Calc mining reward
//balance := totalGas.Add(totalGas, MINING_REWARD) // //balance := totalGas.Add(totalGas, MINING_REWARD)
balance := totalGas // balance := totalGas
accData := ShyftAccountEntry{ // accData := ShyftAccountEntry{
Balance: balance, // Balance: balance,
Txs: txs, // Txs: txs,
} // }
var encodedData bytes.Buffer // var encodedData bytes.Buffer
encoder := gob.NewEncoder(&encodedData) // encoder := gob.NewEncoder(&encodedData)
if err := encoder.Encode(accData); err != nil { // if err := encoder.Encode(accData); err != nil {
log.Crit("Faild to encode Miner Account data", "err", err) // log.Crit("Faild to encode Miner Account data", "err", err)
} // }
if err := db.Put(key, encodedData.Bytes(), nil); err != nil { // if err := db.Put(key, encodedData.Bytes(), nil); err != nil {
log.Crit("Could not write the miner's first tx", "err", err) // log.Crit("Could not write the miner's first tx", "err", err)
} // }
} else { // } else {
// The account has already have previous data stored due to activity in the EVM // // The account has already have previous data stored due to activity in the EVM
// Decode the data to update balance // // Decode the data to update balance
var decodedData ShyftAccountEntry // var decodedData ShyftAccountEntry
d := gob.NewDecoder(bytes.NewBuffer(retrievedData)) // d := gob.NewDecoder(bytes.NewBuffer(retrievedData))
if err := d.Decode(&decodedData); err != nil { // if err := d.Decode(&decodedData); err != nil {
log.Crit("Failed to decode miner data:", "err", err) // log.Crit("Failed to decode miner data:", "err", err)
} // }
// Write new balance // // Write new balance
// @TODO: Calc mining reward // // @TODO: Calc mining reward
// decodedData.Balance.Add(decodedData.Balance, totalGas.Add(totalGas, MINING_REWARD))) // // decodedData.Balance.Add(decodedData.Balance, totalGas.Add(totalGas, MINING_REWARD)))
decodedData.Balance.Add(decodedData.Balance, totalGas) // decodedData.Balance.Add(decodedData.Balance, totalGas)
// Encode the data to be written back to the db // // Encode the data to be written back to the db
var encodedData bytes.Buffer // var encodedData bytes.Buffer
encoder := gob.NewEncoder(&encodedData) // encoder := gob.NewEncoder(&encodedData)
if err := encoder.Encode(decodedData); err != nil { // if err := encoder.Encode(decodedData); err != nil {
log.Crit("Faild to encode Miner Account data", "err", err) // log.Crit("Faild to encode Miner Account data", "err", err)
} // }
// Write newly encoded data back to the db // // Write newly encoded data back to the db
if err := db.Put(key, encodedData.Bytes(), nil); err != nil { // if err := db.Put(key, encodedData.Bytes(), nil); err != nil {
log.Crit("Could not update miner account data", "err", err) // log.Crit("Could not update miner account data", "err", err)
} // }
} // }
} // }
/////////// ///////////
// Getters // Getters