ipld-eth-server/pkg/geth/blockchain.go

225 lines
6.6 KiB
Go
Raw Normal View History

package geth
2017-10-23 18:58:33 +00:00
import (
"errors"
"math/big"
2018-01-15 21:27:45 +00:00
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
2018-08-07 15:51:34 +00:00
"github.com/ethereum/go-ethereum/core/types"
2018-12-12 16:01:50 +00:00
"github.com/ethereum/go-ethereum/rpc"
"github.com/vulcanize/vulcanizedb/pkg/core"
2018-05-02 16:17:02 +00:00
vulcCommon "github.com/vulcanize/vulcanizedb/pkg/geth/converters/common"
2018-12-12 16:01:50 +00:00
"golang.org/x/net/context"
"strconv"
2017-10-23 18:58:33 +00:00
)
var ErrEmptyHeader = errors.New("empty header returned over RPC")
2018-12-12 16:01:50 +00:00
const MAX_BATCH_SIZE = 100
type BlockChain struct {
blockConverter vulcCommon.BlockConverter
ethClient core.EthClient
headerConverter vulcCommon.HeaderConverter
node core.Node
rpcClient core.RpcClient
}
func NewBlockChain(ethClient core.EthClient, rpcClient core.RpcClient, node core.Node, converter vulcCommon.TransactionConverter) *BlockChain {
return &BlockChain{
blockConverter: vulcCommon.NewBlockConverter(converter),
ethClient: ethClient,
headerConverter: vulcCommon.HeaderConverter{},
node: node,
rpcClient: rpcClient,
}
}
func (blockChain *BlockChain) GetBlockByNumber(blockNumber int64) (block core.Block, err error) {
gethBlock, err := blockChain.ethClient.BlockByNumber(context.Background(), big.NewInt(blockNumber))
if err != nil {
return block, err
}
return blockChain.blockConverter.ToCoreBlock(gethBlock)
}
func (blockChain *BlockChain) GetHeaderByNumber(blockNumber int64) (header core.Header, err error) {
if blockChain.node.NetworkID == core.KOVAN_NETWORK_ID {
return blockChain.getPOAHeader(blockNumber)
}
return blockChain.getPOWHeader(blockNumber)
}
2018-12-12 16:01:50 +00:00
func (blockChain *BlockChain) GetHeaderByNumbers(blockNumbers []int64) (header []core.Header, err error) {
if blockChain.node.NetworkID == core.KOVAN_NETWORK_ID {
return blockChain.getPOAHeaders(blockNumbers)
}
return blockChain.getPOWHeaders(blockNumbers)
}
func (blockChain *BlockChain) getPOWHeader(blockNumber int64) (header core.Header, err error) {
gethHeader, err := blockChain.ethClient.HeaderByNumber(context.Background(), big.NewInt(blockNumber))
if err != nil {
return header, err
}
return blockChain.headerConverter.Convert(gethHeader, gethHeader.Hash().String())
}
2018-12-12 16:01:50 +00:00
func (blockChain *BlockChain) getPOWHeaders(blockNumbers []int64) (headers []core.Header, err error) {
var batch []rpc.BatchElem
var POWHeaders [MAX_BATCH_SIZE]types.Header
includeTransactions := false
for index, blockNumber := range blockNumbers {
if index >= MAX_BATCH_SIZE {
break
}
blockNumberArg := hexutil.EncodeBig(big.NewInt(blockNumber))
batchElem := rpc.BatchElem{
Method: "eth_getBlockByNumber",
Result: &POWHeaders[index],
Args: []interface{}{blockNumberArg, includeTransactions},
}
batch = append(batch, batchElem)
}
err = blockChain.rpcClient.BatchCall(batch)
if err != nil {
return headers, err
}
for index, _ := range blockNumbers {
header, _ := blockChain.headerConverter.Convert(&POWHeaders[index], POWHeaders[index].Hash().String())
headers = append(headers, header)
}
return headers, err
}
func (blockChain *BlockChain) getPOAHeader(blockNumber int64) (header core.Header, err error) {
var POAHeader core.POAHeader
blockNumberArg := hexutil.EncodeBig(big.NewInt(blockNumber))
includeTransactions := false
err = blockChain.rpcClient.CallContext(context.Background(), &POAHeader, "eth_getBlockByNumber", blockNumberArg, includeTransactions)
if err != nil {
return header, err
}
if POAHeader.Number == nil {
return header, ErrEmptyHeader
}
return blockChain.headerConverter.Convert(&types.Header{
ParentHash: POAHeader.ParentHash,
UncleHash: POAHeader.UncleHash,
Coinbase: POAHeader.Coinbase,
Root: POAHeader.Root,
TxHash: POAHeader.TxHash,
ReceiptHash: POAHeader.ReceiptHash,
Bloom: POAHeader.Bloom,
Difficulty: POAHeader.Difficulty.ToInt(),
Number: POAHeader.Number.ToInt(),
GasLimit: uint64(POAHeader.GasLimit),
GasUsed: uint64(POAHeader.GasUsed),
Time: POAHeader.Time.ToInt(),
Extra: POAHeader.Extra,
}, POAHeader.Hash.String())
}
2018-12-12 16:01:50 +00:00
func (blockChain *BlockChain) getPOAHeaders(blockNumbers []int64) (headers []core.Header, err error) {
var batch []rpc.BatchElem
var POAHeaders [MAX_BATCH_SIZE]core.POAHeader
includeTransactions := false
for index, blockNumber := range blockNumbers {
if index >= MAX_BATCH_SIZE {
break
}
blockNumberArg := hexutil.EncodeBig(big.NewInt(blockNumber))
batchElem := rpc.BatchElem{
Method: "eth_getBlockByNumber",
Result: &POAHeaders[index],
Args: []interface{}{blockNumberArg, includeTransactions},
}
batch = append(batch, batchElem)
}
err = blockChain.rpcClient.BatchCall(batch)
if err != nil {
return headers, err
}
for index, _ := range blockNumbers {
var header core.Header
var POAHeader = POAHeaders[index]
//Header.Number of the newest block will return nil.
if _, err := strconv.ParseUint(POAHeader.Number.ToInt().String(), 16, 64); err == nil {
header, _ = blockChain.headerConverter.Convert(&types.Header{
ParentHash: POAHeader.ParentHash,
UncleHash: POAHeader.UncleHash,
Coinbase: POAHeader.Coinbase,
Root: POAHeader.Root,
TxHash: POAHeader.TxHash,
ReceiptHash: POAHeader.ReceiptHash,
Bloom: POAHeader.Bloom,
Difficulty: POAHeader.Difficulty.ToInt(),
Number: POAHeader.Number.ToInt(),
GasLimit: uint64(POAHeader.GasLimit),
GasUsed: uint64(POAHeader.GasUsed),
Time: POAHeader.Time.ToInt(),
Extra: POAHeader.Extra,
}, POAHeader.Hash.String())
headers = append(headers, header)
}
}
return headers, err
}
func (blockChain *BlockChain) GetLogs(contract core.Contract, startingBlockNumber, endingBlockNumber *big.Int) ([]core.Log, error) {
if endingBlockNumber == nil {
endingBlockNumber = startingBlockNumber
}
contractAddress := common.HexToAddress(contract.Hash)
fc := ethereum.FilterQuery{
FromBlock: startingBlockNumber,
ToBlock: endingBlockNumber,
Addresses: []common.Address{contractAddress},
2018-07-24 16:38:49 +00:00
Topics: nil,
}
2018-08-07 15:51:34 +00:00
gethLogs, err := blockChain.GetEthLogsWithCustomQuery(fc)
if err != nil {
return []core.Log{}, err
}
2018-05-02 16:17:02 +00:00
logs := vulcCommon.ToCoreLogs(gethLogs)
return logs, nil
}
2018-08-07 15:51:34 +00:00
func (blockChain *BlockChain) GetEthLogsWithCustomQuery(query ethereum.FilterQuery) ([]types.Log, error) {
gethLogs, err := blockChain.ethClient.FilterLogs(context.Background(), query)
2018-08-07 15:51:34 +00:00
if err != nil {
return []types.Log{}, err
}
return gethLogs, nil
}
func (blockChain *BlockChain) LastBlock() *big.Int {
block, _ := blockChain.ethClient.HeaderByNumber(context.Background(), nil)
return block.Number
}
func (blockChain *BlockChain) Node() core.Node {
return blockChain.node
}