forked from cerc-io/ipld-eth-server
Update BlockChain to record NodeInfo (#95)
This commit is contained in:
@@ -4,6 +4,7 @@ import "math/big"
|
||||
|
||||
type Blockchain interface {
|
||||
GetBlockByNumber(blockNumber int64) Block
|
||||
Node() Node
|
||||
SubscribeToBlocks(blocks chan Block)
|
||||
StartListening()
|
||||
StopListening()
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package core
|
||||
|
||||
type Node struct {
|
||||
GenesisBlock string
|
||||
NetworkId float64
|
||||
}
|
||||
@@ -13,6 +13,11 @@ type Blockchain struct {
|
||||
contractAttributes map[string]map[string]string
|
||||
blocksChannel chan core.Block
|
||||
WasToldToStop bool
|
||||
node core.Node
|
||||
}
|
||||
|
||||
func (blockchain *Blockchain) Node() core.Node {
|
||||
return blockchain.node
|
||||
}
|
||||
|
||||
func (blockchain *Blockchain) GetAttribute(contract core.Contract, attributeName string, blockNumber *big.Int) (interface{}, error) {
|
||||
@@ -29,6 +34,7 @@ func NewBlockchain() *Blockchain {
|
||||
return &Blockchain{
|
||||
blocks: make(map[int64]core.Block),
|
||||
contractAttributes: make(map[string]map[string]string),
|
||||
node: core.Node{GenesisBlock: "GENESIS"},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,11 @@ import (
|
||||
"math/big"
|
||||
|
||||
"github.com/8thlight/vulcanizedb/pkg/core"
|
||||
"github.com/8thlight/vulcanizedb/pkg/geth/node"
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
@@ -17,6 +19,11 @@ type GethBlockchain struct {
|
||||
readGethHeaders chan *types.Header
|
||||
outputBlocks chan core.Block
|
||||
newHeadSubscription ethereum.Subscription
|
||||
node core.Node
|
||||
}
|
||||
|
||||
func (blockchain *GethBlockchain) Node() core.Node {
|
||||
return blockchain.node
|
||||
}
|
||||
|
||||
func (blockchain *GethBlockchain) GetBlockByNumber(blockNumber int64) core.Block {
|
||||
@@ -26,7 +33,9 @@ func (blockchain *GethBlockchain) GetBlockByNumber(blockNumber int64) core.Block
|
||||
|
||||
func NewGethBlockchain(ipcPath string) *GethBlockchain {
|
||||
blockchain := GethBlockchain{}
|
||||
client, _ := ethclient.Dial(ipcPath)
|
||||
rpcClient, _ := rpc.Dial(ipcPath)
|
||||
client := ethclient.NewClient(rpcClient)
|
||||
blockchain.node = node.Retrieve(rpcClient)
|
||||
blockchain.client = client
|
||||
return &blockchain
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/8thlight/vulcanizedb/pkg/core"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
func Retrieve(client *rpc.Client) core.Node {
|
||||
var info p2p.NodeInfo
|
||||
node := core.Node{}
|
||||
client.CallContext(context.Background(), &info, "admin_nodeInfo")
|
||||
for protocolName, protocol := range info.Protocols {
|
||||
if protocolName == "eth" {
|
||||
protocolMap, _ := protocol.(map[string]interface{})
|
||||
node.GenesisBlock = getAttribute(protocolMap, "genesis").(string)
|
||||
node.NetworkId = getAttribute(protocolMap, "network").(float64)
|
||||
}
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
func getAttribute(protocolMap map[string]interface{}, protocol string) interface{} {
|
||||
for key, val := range protocolMap {
|
||||
if key == protocol {
|
||||
return val
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package repositories_test
|
||||
|
||||
import (
|
||||
"github.com/8thlight/vulcanizedb/pkg/core"
|
||||
"github.com/8thlight/vulcanizedb/pkg/repositories"
|
||||
"github.com/8thlight/vulcanizedb/pkg/repositories/testing"
|
||||
_ "github.com/lib/pq"
|
||||
@@ -9,7 +10,7 @@ import (
|
||||
|
||||
var _ = Describe("In memory repository", func() {
|
||||
|
||||
testing.AssertRepositoryBehavior(func() repositories.Repository {
|
||||
testing.AssertRepositoryBehavior(func(core.Node) repositories.Repository {
|
||||
return repositories.NewInMemory()
|
||||
})
|
||||
|
||||
|
||||
@@ -14,21 +14,46 @@ import (
|
||||
)
|
||||
|
||||
type Postgres struct {
|
||||
Db *sqlx.DB
|
||||
Db *sqlx.DB
|
||||
node core.Node
|
||||
nodeId int64
|
||||
}
|
||||
|
||||
var (
|
||||
ErrDBInsertFailed = errors.New("postgres: insert failed")
|
||||
ErrDBConnectionFailed = errors.New("postgres: db connection failed")
|
||||
ErrUnableToSetNode = errors.New("postgres: unable to set node")
|
||||
)
|
||||
|
||||
func NewPostgres(databaseConfig config.Database) (Postgres, error) {
|
||||
func NewPostgres(databaseConfig config.Database, node core.Node) (Postgres, error) {
|
||||
connectString := config.DbConnectionString(databaseConfig)
|
||||
db, err := sqlx.Connect("postgres", connectString)
|
||||
if err != nil {
|
||||
return Postgres{}, ErrDBConnectionFailed
|
||||
}
|
||||
return Postgres{Db: db}, nil
|
||||
pg := Postgres{Db: db, node: node}
|
||||
err = pg.CreateNode(&node)
|
||||
if err != nil {
|
||||
return Postgres{}, ErrUnableToSetNode
|
||||
}
|
||||
return pg, nil
|
||||
}
|
||||
|
||||
func (repository *Postgres) CreateNode(node *core.Node) error {
|
||||
var nodeId int64
|
||||
err := repository.Db.QueryRow(
|
||||
`INSERT INTO nodes (genesis_block, network_id)
|
||||
VALUES ($1, $2)
|
||||
ON CONFLICT (genesis_block, network_id)
|
||||
DO UPDATE
|
||||
SET genesis_block = $1, network_id = $2
|
||||
RETURNING id`,
|
||||
node.GenesisBlock, node.NetworkId).Scan(&nodeId)
|
||||
if err != nil {
|
||||
return ErrUnableToSetNode
|
||||
}
|
||||
repository.nodeId = nodeId
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repository Postgres) CreateContract(contract core.Contract) error {
|
||||
@@ -53,7 +78,8 @@ func (repository Postgres) CreateContract(contract core.Contract) error {
|
||||
func (repository Postgres) ContractExists(contractHash string) bool {
|
||||
var exists bool
|
||||
repository.Db.QueryRow(
|
||||
`SELECT exists(SELECT 1 FROM watched_contracts WHERE contract_hash=$1) FROM watched_contracts`, contractHash).Scan(&exists)
|
||||
`SELECT exists(SELECT 1 FROM watched_contracts WHERE contract_hash=$1)
|
||||
FROM watched_contracts`, contractHash).Scan(&exists)
|
||||
return exists
|
||||
}
|
||||
|
||||
@@ -92,7 +118,9 @@ func (repository Postgres) MissingBlockNumbers(startingBlockNumber int64, highes
|
||||
|
||||
func (repository Postgres) FindBlockByNumber(blockNumber int64) *core.Block {
|
||||
blockRows, _ := repository.Db.Query(
|
||||
`SELECT id, block_number, block_gaslimit, block_gasused, block_time, block_difficulty, block_hash, block_nonce, block_parenthash, block_size, uncle_hash FROM blocks`)
|
||||
`SELECT id, block_number, block_gaslimit, block_gasused, block_time, block_difficulty, block_hash, block_nonce, block_parenthash, block_size, uncle_hash
|
||||
FROM blocks
|
||||
WHERE node_id = $1`, repository.nodeId)
|
||||
var savedBlocks []core.Block
|
||||
for blockRows.Next() {
|
||||
savedBlock := repository.loadBlock(blockRows)
|
||||
@@ -116,10 +144,10 @@ func (repository Postgres) CreateBlock(block core.Block) error {
|
||||
var blockId int64
|
||||
err := tx.QueryRow(
|
||||
`INSERT INTO blocks
|
||||
(block_number, block_gaslimit, block_gasused, block_time, block_difficulty, block_hash, block_nonce, block_parenthash, block_size, uncle_hash)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
||||
RETURNING id `,
|
||||
block.Number, block.GasLimit, block.GasUsed, block.Time, block.Difficulty, block.Hash, block.Nonce, block.ParentHash, block.Size, block.UncleHash).
|
||||
(node_id, block_number, block_gaslimit, block_gasused, block_time, block_difficulty, block_hash, block_nonce, block_parenthash, block_size, uncle_hash)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
||||
RETURNING id `,
|
||||
repository.nodeId, block.Number, block.GasLimit, block.GasUsed, block.Time, block.Difficulty, block.Hash, block.Nonce, block.ParentHash, block.Size, block.UncleHash).
|
||||
Scan(&blockId)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
@@ -138,8 +166,8 @@ func (repository Postgres) createTransactions(tx *sql.Tx, blockId int64, transac
|
||||
for _, transaction := range transactions {
|
||||
_, err := tx.Exec(
|
||||
`INSERT INTO transactions
|
||||
(block_id, tx_hash, tx_nonce, tx_to, tx_from, tx_gaslimit, tx_gasprice, tx_value)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
|
||||
(block_id, tx_hash, tx_nonce, tx_to, tx_from, tx_gaslimit, tx_gasprice, tx_value)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
|
||||
blockId, transaction.Hash, transaction.Nonce, transaction.To, transaction.From, transaction.GasLimit, transaction.GasPrice, transaction.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -204,7 +232,7 @@ func (repository Postgres) loadTransactions(transactionRows *sql.Rows) []core.Tr
|
||||
}
|
||||
|
||||
func (repository Postgres) addTransactions(contract core.Contract) core.Contract {
|
||||
transactionRows, _ := repository.Db.Query(`SELECT tx_hash, tx_nonce, tx_to, tx_from, tx_gaslimit, tx_gasprice, tx_value FROM transactions WHERE tx_to = $1 ORDER BY block_id desc`, contract.Hash)
|
||||
transactionRows, _ := repository.Db.Query(`SELECT tx_hash, tx_nonce, tx_to, tx_from, tx_gaslimit, tx_gasprice, tx_value FROM transactions WHERE tx_to = $1 ORDER BY block_id DESC`, contract.Hash)
|
||||
transactions := repository.loadTransactions(transactionRows)
|
||||
savedContract := core.Contract{Hash: contract.Hash, Transactions: transactions, Abi: contract.Abi}
|
||||
return savedContract
|
||||
|
||||
@@ -24,9 +24,9 @@ var _ = Describe("Postgres repository", func() {
|
||||
Expect(db).ShouldNot(BeNil())
|
||||
})
|
||||
|
||||
testing.AssertRepositoryBehavior(func() repositories.Repository {
|
||||
testing.AssertRepositoryBehavior(func(node core.Node) repositories.Repository {
|
||||
cfg, _ := config.NewConfig("private")
|
||||
repository, _ := repositories.NewPostgres(cfg.Database)
|
||||
repository, _ := repositories.NewPostgres(cfg.Database, node)
|
||||
testing.ClearData(repository)
|
||||
return repository
|
||||
})
|
||||
@@ -40,7 +40,8 @@ var _ = Describe("Postgres repository", func() {
|
||||
Transactions: []core.Transaction{},
|
||||
}
|
||||
cfg, _ := config.NewConfig("private")
|
||||
repository, _ := repositories.NewPostgres(cfg.Database)
|
||||
node := core.Node{GenesisBlock: "GENESIS", NetworkId: 1}
|
||||
repository, _ := repositories.NewPostgres(cfg.Database, node)
|
||||
|
||||
err := repository.CreateBlock(badBlock)
|
||||
savedBlock := repository.FindBlockByNumber(123)
|
||||
@@ -51,10 +52,19 @@ var _ = Describe("Postgres repository", func() {
|
||||
|
||||
It("throws error when can't connect to the database", func() {
|
||||
invalidDatabase := config.Database{}
|
||||
_, err := repositories.NewPostgres(invalidDatabase)
|
||||
node := core.Node{GenesisBlock: "GENESIS", NetworkId: 1}
|
||||
_, err := repositories.NewPostgres(invalidDatabase, node)
|
||||
Expect(err).To(Equal(repositories.ErrDBConnectionFailed))
|
||||
})
|
||||
|
||||
It("throws error when can't create node", func() {
|
||||
cfg, _ := config.NewConfig("private")
|
||||
badHash := fmt.Sprintf("x %s", strings.Repeat("1", 100))
|
||||
node := core.Node{GenesisBlock: badHash, NetworkId: 1}
|
||||
_, err := repositories.NewPostgres(cfg.Database, node)
|
||||
Expect(err).To(Equal(repositories.ErrUnableToSetNode))
|
||||
})
|
||||
|
||||
It("does not commit block or transactions if transaction is invalid", func() {
|
||||
//badHash violates db To field length
|
||||
badHash := fmt.Sprintf("x %s", strings.Repeat("1", 100))
|
||||
@@ -64,7 +74,8 @@ var _ = Describe("Postgres repository", func() {
|
||||
Transactions: []core.Transaction{badTransaction},
|
||||
}
|
||||
cfg, _ := config.NewConfig("private")
|
||||
repository, _ := repositories.NewPostgres(cfg.Database)
|
||||
node := core.Node{GenesisBlock: "GENESIS", NetworkId: 1}
|
||||
repository, _ := repositories.NewPostgres(cfg.Database, node)
|
||||
|
||||
err := repository.CreateBlock(block)
|
||||
savedBlock := repository.FindBlockByNumber(123)
|
||||
|
||||
@@ -13,11 +13,12 @@ func ClearData(postgres repositories.Postgres) {
|
||||
postgres.Db.MustExec("DELETE FROM blocks")
|
||||
}
|
||||
|
||||
func AssertRepositoryBehavior(buildRepository func() repositories.Repository) {
|
||||
func AssertRepositoryBehavior(buildRepository func(node core.Node) repositories.Repository) {
|
||||
var repository repositories.Repository
|
||||
|
||||
BeforeEach(func() {
|
||||
repository = buildRepository()
|
||||
node := core.Node{GenesisBlock: "GENESIS", NetworkId: 1}
|
||||
repository = buildRepository(node)
|
||||
})
|
||||
|
||||
Describe("Saving blocks", func() {
|
||||
@@ -34,6 +35,21 @@ func AssertRepositoryBehavior(buildRepository func() repositories.Repository) {
|
||||
Expect(repository.BlockCount()).To(Equal(1))
|
||||
})
|
||||
|
||||
It("associates blocks to a node", func() {
|
||||
block := core.Block{
|
||||
Number: 123,
|
||||
}
|
||||
repository.CreateBlock(block)
|
||||
nodeTwo := core.Node{
|
||||
GenesisBlock: "0x456",
|
||||
NetworkId: 1,
|
||||
}
|
||||
repositoryTwo := buildRepository(nodeTwo)
|
||||
|
||||
foundBlock := repositoryTwo.FindBlockByNumber(123)
|
||||
Expect(foundBlock).To(BeNil())
|
||||
})
|
||||
|
||||
It("saves the attributes of the block", func() {
|
||||
blockNumber := int64(123)
|
||||
gasLimit := int64(1000000)
|
||||
|
||||
Reference in New Issue
Block a user