Skip to content
Permalink
Browse files

Initial commit

  • Loading branch information...
maran committed Apr 7, 2015
0 parents commit 782eacbf751a2017d8cee619388af8a88d7ed4d8
Showing with 238 additions and 0 deletions.
  1. +5 −0 .gitignore
  2. +9 −0 README.md
  3. +6 −0 contrib/Dockerfile
  4. +1 −0 contrib/README.md
  5. +3 −0 contrib/build
  6. +104 −0 importer.go
  7. +110 −0 main.go
@@ -0,0 +1,5 @@
state/*
extra/*
blockchain/*
main
ecp
@@ -0,0 +1,9 @@
##### Ethereum chain parser

**E**thereum **Chain** **Parser** listens for Ethereum (block) chain events and turns them into MongoDB
records (currently). This could be easily extended to allow importing to
various database formats. These records can be accessed from a third client application.

It's currently being used for the Ethereum chain explorer.

This is still pre-Alpha software, not ready for production.
@@ -0,0 +1,6 @@
FROM golang:1.4.2
MAINTAINER maran@ethdev.com

RUN go get -u github.com/tools/godep
RUN go get -d github.com/ethereum/go-ethereum/cmd/ethereum
RUN cd /go/src/github.com/ethereum/go-ethereum && git checkout develop && godep restore
@@ -0,0 +1 @@
This is a small docker container to build ECP linux binaries from OSX.
@@ -0,0 +1,3 @@
#!/bin/bash
docker build -t blockparser-linux .
cd ../ && docker run --rm -v "$PWD":/usr/src/blocker -w /usr/src/blocker blockparser-linux go get -u github.com/codegangsta/cli && go build -v
@@ -0,0 +1,104 @@
package main

import (
"github.com/codegangsta/cli"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)

type ImportMaster struct {
session *mgo.Session
ethereum *eth.Ethereum
txCollection *mgo.Collection
blockCollection *mgo.Collection
}

type Transaction struct {
TxHash string `bson:"tx_hash"`
Recipient string
From string
Amount string
Price string
GasLimit string `bson:"gas_limit"`
Payload []byte
BlockId *bson.ObjectId `bson:"block_id,omitempty"`
}

func (self *ImportMaster) parseTx(tx *types.Transaction, blockId *bson.ObjectId) *Transaction {
hash := tx.Hash().Hex()
from, err := tx.From()
if err != nil {
utils.Fatalf("Could not parse from address: %v", err)
}
var recipient string
if tx.Recipient != nil {
recipient = tx.Recipient.Hex()
}
txx := &Transaction{hash, recipient, from.Hex(), tx.Amount.String(), tx.Price.String(), tx.GasLimit.String(), tx.Payload, blockId}
return txx
}

type Block struct {
BlockHash string `bson:"block_hash"`
ParentHash string `bson:"parent_hash"`
UncleHash string `bson:"uncle_hash"`
Coinbase string `bson:"coin_base"`
Root string `bson:"root"`
TxHash string `bson:"tx_hash"`
ReceiptHash string `bson:"receipt_hash"`
Number string
Difficulty string
GasLimit string `bson:"gas_limit"`
GasUsed string `bson:"gas_used"`
Time uint64
TxAmount uint64 `bson:"tx_amount"`
Nonce string
StorageSize string `bson:"storage_size"`
MixDigest string `bson:"mix_digest"`
Id *bson.ObjectId `bson:"_id,omitempty"`
}

func NewImporter(ctx *cli.Context) *ImportMaster {
importer := new(ImportMaster)
mongoUrl := ctx.String("mongo-url")
db := ctx.String("mongo-database")

clilogger.Infoln("Connecting to MongoDB db '", db, "' using", mongoUrl)
session, err := mgo.Dial(mongoUrl)
if err != nil {
panic(err)
}
importer.session = session
importer.txCollection = session.DB(db).C("transactions")
importer.blockCollection = session.DB(db).C("blocks")

return importer
}

func (self *ImportMaster) importBlock(block *types.Block) {
blockHash := block.Header().Hash().Hex()
txAmount := uint64(len(block.Transactions()))
clilogger.Infoln("Importing block", blockHash, "Hash transactions:", txAmount)
err := self.blockCollection.Insert(&Block{blockHash, block.ParentHash().Hex(), block.Header().UncleHash.Hex(), block.Header().Coinbase.Hex(), block.Header().Root.Hex(), block.Header().TxHash.Hex(), block.Header().ReceiptHash.Hex(), block.Header().Number.String(), block.Header().Difficulty.String(), block.Header().GasLimit.String(), block.Header().GasUsed.String(), block.Header().Time, txAmount, string(block.Nonce()), block.Size().String(), block.Header().MixDigest.Hex(), nil})
if err != nil {
clilogger.Infoln(err)
}
result := Block{}
err = self.blockCollection.Find(bson.M{"block_hash": blockHash}).One(&result)
if err != nil {
utils.Fatalf("Could not find the block we just added: %v", err)
}
for _, tx := range block.Transactions() {
self.importTx(tx, result.Id)
}
}
func (self *ImportMaster) importTx(tx *types.Transaction, blockId *bson.ObjectId) {
clilogger.Infoln("Importing tx", tx.Hash().Hex())
err := self.txCollection.Insert(self.parseTx(tx, blockId))
if err != nil {
clilogger.Infoln(err)
}
}
110 main.go
@@ -0,0 +1,110 @@
package main

import (
"fmt"
"github.com/codegangsta/cli"
"os"
"runtime"

"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/core"

"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/logger"
)

const (
Version = "0.0.1"
)

var (
clilogger = logger.NewLogger("Parser")
app = utils.NewApp(Version, "Ethereum chain parser")
)

func init() {
app.Action = run
app.Name = "BlockParser"
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "mongo-url",
Value: "mongodb://localhost",
Usage: "MongoDB connection url",
},
cli.StringFlag{
Name: "mongo-database",
Value: "chain_explorer",
Usage: "MongoDB database",
},
utils.UnlockedAccountFlag,
utils.PasswordFileFlag,
utils.BootnodesFlag,
utils.DataDirFlag,
utils.JSpathFlag,
utils.ListenPortFlag,
utils.LogFileFlag,
utils.LogJSONFlag,
utils.LogLevelFlag,
utils.MaxPeersFlag,
utils.EtherbaseFlag,
utils.MinerThreadsFlag,
utils.MiningEnabledFlag,
utils.NATFlag,
utils.NodeKeyFileFlag,
utils.NodeKeyHexFlag,
utils.RPCEnabledFlag,
utils.RPCListenAddrFlag,
utils.RPCPortFlag,
utils.VMDebugFlag,
utils.ProtocolVersionFlag,
utils.NetworkIdFlag,
utils.RPCCORSDomainFlag,
utils.BacktraceAtFlag,
utils.LogToStdErrFlag,
}
}

func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
defer logger.Flush()
if err := app.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func run(ctx *cli.Context) {
importer := NewImporter(ctx)
utils.HandleInterrupt()
cfg := utils.MakeEthConfig("EthChainParser", Version, ctx)

ethereum, err := eth.New(cfg)
utils.StartEthereum(ethereum)
if err != nil {
utils.Fatalf("%v", err)
}
events := ethereum.EventMux().Subscribe(
core.ChainEvent{},
core.TxPreEvent{},
)

defer events.Unsubscribe()
for {
select {
case ev, isopen := <-events.Chan():
if !isopen {
return
}
switch ev := ev.(type) {
case core.ChainEvent:
importer.importBlock(ev.Block)
case core.TxPreEvent:
// Not dealing with incoming txes for now
//importer.importTx(ev.Tx)
}
}
}

ethereum.WaitForShutdown()
logger.Flush()
fmt.Printf("Shutting down\n")
}

0 comments on commit 782eacb

Please sign in to comment.
You can’t perform that action at this time.