2018-03-15 01:19:02 -06:00
package eth
import (
"blockbook/bchain"
2018-03-15 04:38:31 -06:00
"context"
2018-03-19 05:05:16 -06:00
"encoding/json"
2018-03-22 08:56:21 -06:00
"fmt"
2018-03-19 10:34:51 -06:00
"math/big"
2018-03-20 07:43:15 -06:00
"sync"
2018-03-15 01:19:02 -06:00
"time"
2018-03-15 04:38:31 -06:00
"github.com/golang/glog"
2018-03-19 05:05:16 -06:00
"github.com/juju/errors"
2018-03-15 04:38:31 -06:00
2018-03-22 08:56:21 -06:00
ethereum "github.com/ethereum/go-ethereum"
2018-03-19 10:34:51 -06:00
ethcommon "github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
2018-03-15 01:19:02 -06:00
"github.com/ethereum/go-ethereum/ethclient"
2018-03-22 08:56:21 -06:00
"github.com/ethereum/go-ethereum/rpc"
2018-03-15 01:19:02 -06:00
)
2018-04-03 14:24:23 -06:00
// EthereumNet type specifies the type of ethereum network
2018-03-19 10:34:51 -06:00
type EthereumNet uint32
const (
2018-04-03 14:24:23 -06:00
// MainNet is production network
2018-03-19 10:34:51 -06:00
MainNet EthereumNet = 1
2018-04-03 14:24:23 -06:00
// TestNet is Ropsten test network
2018-03-19 10:34:51 -06:00
TestNet EthereumNet = 3
)
2018-06-05 08:14:46 -06:00
type Configuration struct {
2018-07-31 02:46:15 -06:00
CoinName string ` json:"coin_name" `
CoinShortcut string ` json:"coin_shortcut" `
RPCURL string ` json:"rpc_url" `
RPCTimeout int ` json:"rpc_timeout" `
2018-06-05 08:14:46 -06:00
}
2018-04-03 14:24:23 -06:00
// EthereumRPC is an interface to JSON-RPC eth service.
type EthereumRPC struct {
2018-03-28 02:25:08 -06:00
client * ethclient . Client
rpc * rpc . Client
timeout time . Duration
rpcURL string
2018-04-03 14:24:23 -06:00
Parser * EthereumParser
2018-06-05 08:14:46 -06:00
CoinName string
2018-03-28 02:25:08 -06:00
Testnet bool
Network string
2018-03-29 09:30:12 -06:00
Mempool * bchain . NonUTXOMempool
2018-03-28 02:25:08 -06:00
bestHeaderMu sync . Mutex
bestHeader * ethtypes . Header
chanNewBlock chan * ethtypes . Header
newBlockSubscription * rpc . ClientSubscription
2018-04-03 10:22:36 -06:00
chanNewTx chan ethcommon . Hash
newTxSubscription * rpc . ClientSubscription
2018-06-05 08:14:46 -06:00
ChainConfig * Configuration
2018-03-19 05:05:16 -06:00
}
2018-04-03 14:24:23 -06:00
// NewEthereumRPC returns new EthRPC instance.
func NewEthereumRPC ( config json . RawMessage , pushHandler func ( bchain . NotificationType ) ) ( bchain . BlockChain , error ) {
2018-03-19 05:05:16 -06:00
var err error
2018-06-05 08:14:46 -06:00
var c Configuration
2018-03-19 05:05:16 -06:00
err = json . Unmarshal ( config , & c )
if err != nil {
return nil , errors . Annotatef ( err , "Invalid configuration file" )
}
2018-03-22 08:56:21 -06:00
rc , err := rpc . Dial ( c . RPCURL )
2018-03-15 01:19:02 -06:00
if err != nil {
return nil , err
}
2018-03-22 08:56:21 -06:00
ec := ethclient . NewClient ( rc )
2018-04-03 14:24:23 -06:00
s := & EthereumRPC {
2018-06-05 08:14:46 -06:00
client : ec ,
rpc : rc ,
ChainConfig : & c ,
2018-03-15 01:19:02 -06:00
}
// always create parser
2018-05-18 07:04:40 -06:00
s . Parser = NewEthereumParser ( )
2018-03-19 10:34:51 -06:00
s . timeout = time . Duration ( c . RPCTimeout ) * time . Second
2018-03-15 01:19:02 -06:00
2018-03-28 02:25:08 -06:00
// new blocks notifications handling
// the subscription is done in Initialize
s . chanNewBlock = make ( chan * ethtypes . Header )
go func ( ) {
for {
h , ok := <- s . chanNewBlock
if ! ok {
break
}
glog . V ( 2 ) . Info ( "rpc: new block header " , h . Number )
// update best header to the new header
s . bestHeaderMu . Lock ( )
s . bestHeader = h
s . bestHeaderMu . Unlock ( )
// notify blockbook
pushHandler ( bchain . NotificationNewBlock )
}
} ( )
2018-04-03 10:22:36 -06:00
// new mempool transaction notifications handling
// the subscription is done in Initialize
s . chanNewTx = make ( chan ethcommon . Hash )
go func ( ) {
for {
t , ok := <- s . chanNewTx
if ! ok {
break
}
if glog . V ( 2 ) {
glog . Info ( "rpc: new tx " , t . Hex ( ) )
}
pushHandler ( bchain . NotificationNewTx )
}
} ( )
2018-03-21 08:47:31 -06:00
return s , nil
}
2018-03-28 02:25:08 -06:00
// Initialize initializes ethereum rpc interface
2018-04-03 14:24:23 -06:00
func ( b * EthereumRPC ) Initialize ( ) error {
2018-03-21 08:47:31 -06:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , b . timeout )
2018-03-19 10:34:51 -06:00
defer cancel ( )
2018-03-21 08:47:31 -06:00
id , err := b . client . NetworkID ( ctx )
2018-03-15 04:38:31 -06:00
if err != nil {
2018-03-21 08:47:31 -06:00
return err
2018-03-15 04:38:31 -06:00
}
2018-03-19 10:34:51 -06:00
// parameters for getInfo request
switch EthereumNet ( id . Uint64 ( ) ) {
case MainNet :
2018-03-21 08:47:31 -06:00
b . Testnet = false
b . Network = "livenet"
2018-03-19 10:34:51 -06:00
break
case TestNet :
2018-03-21 08:47:31 -06:00
b . Testnet = true
b . Network = "testnet"
2018-03-19 10:34:51 -06:00
break
default :
2018-03-21 08:47:31 -06:00
return errors . Errorf ( "Unknown network id %v" , id )
2018-03-19 10:34:51 -06:00
}
2018-03-21 08:47:31 -06:00
glog . Info ( "rpc: block chain " , b . Network )
2018-03-15 01:19:02 -06:00
2018-04-06 03:03:55 -06:00
// subscriptions
if err = b . subscribe ( func ( ) ( * rpc . ClientSubscription , error ) {
// invalidate the previous subscription - it is either the first one or there was an error
b . newBlockSubscription = nil
ctx , cancel := context . WithTimeout ( context . Background ( ) , b . timeout )
defer cancel ( )
sub , err := b . rpc . EthSubscribe ( ctx , b . chanNewBlock , "newHeads" )
if err != nil {
return nil , errors . Annotatef ( err , "EthSubscribe newHeads" )
}
b . newBlockSubscription = sub
glog . Info ( "Subscribed to newHeads" )
return sub , nil
} ) ; err != nil {
return err
2018-03-28 02:25:08 -06:00
}
2018-04-06 03:03:55 -06:00
if err = b . subscribe ( func ( ) ( * rpc . ClientSubscription , error ) {
// invalidate the previous subscription - it is either the first one or there was an error
b . newTxSubscription = nil
ctx , cancel := context . WithTimeout ( context . Background ( ) , b . timeout )
defer cancel ( )
sub , err := b . rpc . EthSubscribe ( ctx , b . chanNewTx , "newPendingTransactions" )
if err != nil {
return nil , errors . Annotatef ( err , "EthSubscribe newPendingTransactions" )
}
b . newTxSubscription = sub
glog . Info ( "Subscribed to newPendingTransactions" )
return sub , nil
} ) ; err != nil {
return err
2018-04-03 10:22:36 -06:00
}
2018-04-06 03:03:55 -06:00
// create mempool
2018-03-29 09:30:12 -06:00
b . Mempool = bchain . NewNonUTXOMempool ( b )
2018-03-21 08:47:31 -06:00
return nil
2018-03-15 01:19:02 -06:00
}
2018-04-06 03:03:55 -06:00
// subscribeNewBlocks subscribes to new blocks notification
func ( b * EthereumRPC ) subscribe ( f func ( ) ( * rpc . ClientSubscription , error ) ) error {
s , err := f ( )
if err != nil {
return err
}
go func ( ) {
Loop :
for {
// wait for error in subscription
e := <- s . Err ( )
// nil error means sub.Unsubscribe called, exit goroutine
if e == nil {
return
}
glog . Error ( "Subscription error " , e )
timer := time . NewTimer ( time . Second )
// try in 1 second interval to resubscribe
for {
select {
case e = <- s . Err ( ) :
if e == nil {
return
}
case <- timer . C :
ns , err := f ( )
if err == nil {
// subscription successful, restart wait for next error
s = ns
continue Loop
}
timer . Reset ( time . Second )
}
}
}
} ( )
return nil
}
2018-03-28 02:25:08 -06:00
// Shutdown cleans up rpc interface to ethereum
2018-05-30 06:37:30 -06:00
func ( b * EthereumRPC ) Shutdown ( ctx context . Context ) error {
2018-03-28 02:25:08 -06:00
if b . newBlockSubscription != nil {
b . newBlockSubscription . Unsubscribe ( )
}
2018-04-03 10:22:36 -06:00
if b . newTxSubscription != nil {
b . newTxSubscription . Unsubscribe ( )
}
2018-03-28 02:25:08 -06:00
if b . rpc != nil {
b . rpc . Close ( )
}
close ( b . chanNewBlock )
glog . Info ( "rpc: shutdown" )
2018-03-19 05:05:16 -06:00
return nil
}
2018-04-03 14:24:23 -06:00
func ( b * EthereumRPC ) IsTestnet ( ) bool {
2018-03-19 10:36:18 -06:00
return b . Testnet
2018-03-15 01:19:02 -06:00
}
2018-04-03 14:24:23 -06:00
func ( b * EthereumRPC ) GetNetworkName ( ) string {
2018-03-19 10:36:18 -06:00
return b . Network
}
2018-06-05 08:14:46 -06:00
func ( b * EthereumRPC ) GetCoinName ( ) string {
return b . ChainConfig . CoinName
}
2018-04-27 02:53:33 -06:00
func ( b * EthereumRPC ) GetSubversion ( ) string {
return ""
}
2018-05-17 04:30:45 -06:00
// GetBlockChainInfo returns the NetworkID of the ethereum network
func ( b * EthereumRPC ) GetBlockChainInfo ( ) ( string , error ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , b . timeout )
defer cancel ( )
id , err := b . client . NetworkID ( ctx )
if err != nil {
return "" , err
}
return id . String ( ) , nil
}
2018-04-03 14:24:23 -06:00
func ( b * EthereumRPC ) getBestHeader ( ) ( * ethtypes . Header , error ) {
2018-03-20 07:43:15 -06:00
b . bestHeaderMu . Lock ( )
defer b . bestHeaderMu . Unlock ( )
2018-03-19 10:36:18 -06:00
if b . bestHeader == nil {
var err error
ctx , cancel := context . WithTimeout ( context . Background ( ) , b . timeout )
defer cancel ( )
b . bestHeader , err = b . client . HeaderByNumber ( ctx , nil )
if err != nil {
return nil , err
}
}
return b . bestHeader , nil
2018-03-15 01:19:02 -06:00
}
2018-04-03 14:24:23 -06:00
func ( b * EthereumRPC ) GetBestBlockHash ( ) ( string , error ) {
2018-03-19 10:36:18 -06:00
h , err := b . getBestHeader ( )
if err != nil {
return "" , err
}
2018-03-20 07:43:15 -06:00
return ethHashToHash ( h . Hash ( ) ) , nil
2018-03-15 01:19:02 -06:00
}
2018-04-03 14:24:23 -06:00
func ( b * EthereumRPC ) GetBestBlockHeight ( ) ( uint32 , error ) {
2018-03-19 10:36:18 -06:00
h , err := b . getBestHeader ( )
if err != nil {
return 0 , err
}
// TODO - can it grow over 2^32 ?
return uint32 ( h . Number . Uint64 ( ) ) , nil
2018-03-15 01:19:02 -06:00
}
2018-04-03 14:24:23 -06:00
func ( b * EthereumRPC ) GetBlockHash ( height uint32 ) ( string , error ) {
2018-03-19 10:36:18 -06:00
var n big . Int
n . SetUint64 ( uint64 ( height ) )
ctx , cancel := context . WithTimeout ( context . Background ( ) , b . timeout )
defer cancel ( )
h , err := b . client . HeaderByNumber ( ctx , & n )
if err != nil {
2018-03-26 09:47:46 -06:00
if err == ethereum . NotFound {
return "" , bchain . ErrBlockNotFound
}
2018-03-26 10:14:26 -06:00
return "" , errors . Annotatef ( err , "height %v" , height )
2018-03-19 10:36:18 -06:00
}
2018-03-20 07:43:15 -06:00
return ethHashToHash ( h . Hash ( ) ) , nil
2018-03-15 01:19:02 -06:00
}
2018-04-03 14:24:23 -06:00
func ( b * EthereumRPC ) ethHeaderToBlockHeader ( h * ethtypes . Header ) ( * bchain . BlockHeader , error ) {
2018-03-22 08:56:21 -06:00
hn := h . Number . Uint64 ( )
c , err := b . computeConfirmations ( hn )
2018-03-19 10:36:18 -06:00
if err != nil {
return nil , err
}
2018-03-20 07:43:15 -06:00
return & bchain . BlockHeader {
Hash : ethHashToHash ( h . Hash ( ) ) ,
2018-03-22 08:56:21 -06:00
Height : uint32 ( hn ) ,
Confirmations : int ( c ) ,
2018-08-21 08:36:14 -06:00
Time : int64 ( h . Time . Uint64 ( ) ) ,
2018-03-20 07:43:15 -06:00
// Next
// Prev
} , nil
}
2018-04-03 14:24:23 -06:00
func ( b * EthereumRPC ) GetBlockHeader ( hash string ) ( * bchain . BlockHeader , error ) {
2018-03-20 07:43:15 -06:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , b . timeout )
defer cancel ( )
h , err := b . client . HeaderByHash ( ctx , ethcommon . HexToHash ( hash ) )
if err != nil {
2018-03-26 09:47:46 -06:00
if err == ethereum . NotFound {
return nil , bchain . ErrBlockNotFound
}
2018-03-26 10:14:26 -06:00
return nil , errors . Annotatef ( err , "hash %v" , hash )
2018-03-19 10:36:18 -06:00
}
2018-03-20 07:43:15 -06:00
return b . ethHeaderToBlockHeader ( h )
2018-03-15 01:19:02 -06:00
}
2018-04-03 14:24:23 -06:00
func ( b * EthereumRPC ) computeConfirmations ( n uint64 ) ( uint32 , error ) {
2018-03-22 08:56:21 -06:00
bh , err := b . getBestHeader ( )
if err != nil {
return 0 , err
}
bn := bh . Number . Uint64 ( )
2018-04-06 09:13:38 -06:00
// transaction in the best block has 1 confirmation
return uint32 ( bn - n + 1 ) , nil
2018-03-22 08:56:21 -06:00
}
2018-03-27 08:34:58 -06:00
// GetBlock returns block with given hash or height, hash has precedence if both passed
2018-04-03 14:24:23 -06:00
func ( b * EthereumRPC ) GetBlock ( hash string , height uint32 ) ( * bchain . Block , error ) {
2018-03-20 07:43:15 -06:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , b . timeout )
defer cancel ( )
2018-03-22 08:56:21 -06:00
var raw json . RawMessage
2018-03-26 05:57:40 -06:00
var err error
if hash != "" {
err = b . rpc . CallContext ( ctx , & raw , "eth_getBlockByHash" , ethcommon . HexToHash ( hash ) , true )
} else {
err = b . rpc . CallContext ( ctx , & raw , "eth_getBlockByNumber" , fmt . Sprintf ( "%#x" , height ) , true )
}
2018-03-20 07:43:15 -06:00
if err != nil {
2018-03-26 10:14:26 -06:00
return nil , errors . Annotatef ( err , "hash %v, height %v" , hash , height )
2018-03-22 08:56:21 -06:00
} else if len ( raw ) == 0 {
2018-03-26 09:47:46 -06:00
return nil , bchain . ErrBlockNotFound
2018-03-22 08:56:21 -06:00
}
// Decode header and transactions.
var head * ethtypes . Header
var body rpcBlock
if err := json . Unmarshal ( raw , & head ) ; err != nil {
2018-03-26 10:14:26 -06:00
return nil , errors . Annotatef ( err , "hash %v, height %v" , hash , height )
2018-03-22 08:56:21 -06:00
}
2018-03-26 09:47:46 -06:00
if head == nil {
return nil , bchain . ErrBlockNotFound
}
2018-03-22 08:56:21 -06:00
if err := json . Unmarshal ( raw , & body ) ; err != nil {
2018-03-26 10:14:26 -06:00
return nil , errors . Annotatef ( err , "hash %v, height %v" , hash , height )
2018-03-22 08:56:21 -06:00
}
// Quick-verify transaction and uncle lists. This mostly helps with debugging the server.
if head . UncleHash == ethtypes . EmptyUncleHash && len ( body . UncleHashes ) > 0 {
2018-03-26 10:14:26 -06:00
return nil , errors . Annotatef ( fmt . Errorf ( "server returned non-empty uncle list but block header indicates no uncles" ) , "hash %v, height %v" , hash , height )
2018-03-22 08:56:21 -06:00
}
if head . UncleHash != ethtypes . EmptyUncleHash && len ( body . UncleHashes ) == 0 {
2018-03-26 10:14:26 -06:00
return nil , errors . Annotatef ( fmt . Errorf ( "server returned empty uncle list but block header indicates uncles" ) , "hash %v, height %v" , hash , height )
2018-03-20 07:43:15 -06:00
}
2018-03-22 08:56:21 -06:00
if head . TxHash == ethtypes . EmptyRootHash && len ( body . Transactions ) > 0 {
2018-03-26 10:14:26 -06:00
return nil , errors . Annotatef ( fmt . Errorf ( "server returned non-empty transaction list but block header indicates no transactions" ) , "hash %v, height %v" , hash , height )
2018-03-22 08:56:21 -06:00
}
if head . TxHash != ethtypes . EmptyRootHash && len ( body . Transactions ) == 0 {
2018-03-26 10:14:26 -06:00
return nil , errors . Annotatef ( fmt . Errorf ( "server returned empty transaction list but block header indicates transactions" ) , "hash %v, height %v" , hash , height )
2018-03-22 08:56:21 -06:00
}
bbh , err := b . ethHeaderToBlockHeader ( head )
2018-08-21 08:36:14 -06:00
// TODO - this is probably not the correct size
bbh . Size = len ( raw )
2018-03-22 08:56:21 -06:00
btxs := make ( [ ] bchain . Tx , len ( body . Transactions ) )
for i , tx := range body . Transactions {
2018-05-18 07:04:40 -06:00
btx , err := b . Parser . ethTxToTx ( & tx , int64 ( head . Time . Uint64 ( ) ) , uint32 ( bbh . Confirmations ) )
2018-03-22 08:56:21 -06:00
if err != nil {
2018-03-26 10:14:26 -06:00
return nil , errors . Annotatef ( err , "hash %v, height %v, txid %v" , hash , height , tx . Hash . String ( ) )
2018-03-20 07:43:15 -06:00
}
2018-03-22 08:56:21 -06:00
btxs [ i ] = * btx
2018-03-20 07:43:15 -06:00
}
bbk := bchain . Block {
BlockHeader : * bbh ,
Txs : btxs ,
}
return & bbk , nil
2018-03-15 01:19:02 -06:00
}
2018-05-14 10:12:01 -06:00
// GetTransactionForMempool returns a transaction by the transaction ID.
// It could be optimized for mempool, i.e. without block time and confirmations
func ( b * EthereumRPC ) GetTransactionForMempool ( txid string ) ( * bchain . Tx , error ) {
return b . GetTransaction ( txid )
}
2018-03-27 08:34:58 -06:00
// GetTransaction returns a transaction by the transaction ID.
2018-04-03 14:24:23 -06:00
func ( b * EthereumRPC ) GetTransaction ( txid string ) ( * bchain . Tx , error ) {
2018-03-20 07:43:15 -06:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , b . timeout )
defer cancel ( )
2018-03-24 17:30:09 -06:00
var tx * rpcTransaction
err := b . rpc . CallContext ( ctx , & tx , "eth_getTransactionByHash" , ethcommon . HexToHash ( txid ) )
2018-03-20 07:43:15 -06:00
if err != nil {
return nil , err
2018-03-24 17:30:09 -06:00
} else if tx == nil {
2018-03-22 08:56:21 -06:00
return nil , ethereum . NotFound
2018-03-24 17:30:09 -06:00
} else if tx . R == "" {
2018-03-26 10:14:26 -06:00
return nil , errors . Annotatef ( fmt . Errorf ( "server returned transaction without signature" ) , "txid %v" , txid )
2018-03-20 07:43:15 -06:00
}
2018-03-22 08:56:21 -06:00
var btx * bchain . Tx
2018-03-24 17:30:09 -06:00
if tx . BlockNumber == "" {
2018-03-22 08:56:21 -06:00
// mempool tx
2018-05-18 07:04:40 -06:00
btx , err = b . Parser . ethTxToTx ( tx , 0 , 0 )
2018-03-22 08:56:21 -06:00
if err != nil {
2018-03-26 10:14:26 -06:00
return nil , errors . Annotatef ( err , "txid %v" , txid )
2018-03-22 08:56:21 -06:00
}
} else {
// non mempool tx - we must read the block header to get the block time
2018-03-24 17:30:09 -06:00
n , err := ethNumber ( tx . BlockNumber )
2018-03-22 08:56:21 -06:00
if err != nil {
2018-03-26 10:14:26 -06:00
return nil , errors . Annotatef ( err , "txid %v" , txid )
2018-03-22 08:56:21 -06:00
}
2018-04-05 04:41:15 -06:00
h , err := b . client . HeaderByHash ( ctx , * tx . BlockHash )
2018-03-22 08:56:21 -06:00
if err != nil {
2018-03-26 10:14:26 -06:00
return nil , errors . Annotatef ( err , "txid %v" , txid )
2018-03-22 08:56:21 -06:00
}
confirmations , err := b . computeConfirmations ( uint64 ( n ) )
if err != nil {
2018-03-26 10:14:26 -06:00
return nil , errors . Annotatef ( err , "txid %v" , txid )
2018-03-22 08:56:21 -06:00
}
2018-05-18 07:04:40 -06:00
btx , err = b . Parser . ethTxToTx ( tx , h . Time . Int64 ( ) , confirmations )
2018-03-22 08:56:21 -06:00
if err != nil {
2018-03-26 10:14:26 -06:00
return nil , errors . Annotatef ( err , "txid %v" , txid )
2018-03-22 08:56:21 -06:00
}
2018-03-20 07:43:15 -06:00
}
2018-03-22 08:56:21 -06:00
return btx , nil
}
2018-03-29 09:30:12 -06:00
type rpcMempoolBlock struct {
Transactions [ ] string ` json:"transactions" `
}
2018-04-03 14:24:23 -06:00
func ( b * EthereumRPC ) GetMempool ( ) ( [ ] string , error ) {
2018-03-29 09:30:12 -06:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , b . timeout )
defer cancel ( )
var raw json . RawMessage
var err error
err = b . rpc . CallContext ( ctx , & raw , "eth_getBlockByNumber" , "pending" , false )
if err != nil {
return nil , err
} else if len ( raw ) == 0 {
return nil , bchain . ErrBlockNotFound
}
var body rpcMempoolBlock
if err := json . Unmarshal ( raw , & body ) ; err != nil {
return nil , err
}
return body . Transactions , nil
2018-03-15 01:19:02 -06:00
}
2018-03-27 08:34:58 -06:00
// EstimateFee returns fee estimation.
2018-07-24 07:58:37 -06:00
func ( b * EthereumRPC ) EstimateFee ( blocks int ) ( big . Int , error ) {
2018-03-27 08:34:58 -06:00
return b . EstimateSmartFee ( blocks , true )
}
// EstimateSmartFee returns fee estimation.
2018-07-24 07:58:37 -06:00
func ( b * EthereumRPC ) EstimateSmartFee ( blocks int , conservative bool ) ( big . Int , error ) {
2018-03-27 08:34:58 -06:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , b . timeout )
defer cancel ( )
// TODO - what parameters of msg to use to get better estimate, maybe more data from the wallet are needed
a := ethcommon . HexToAddress ( "0x1234567890123456789012345678901234567890" )
msg := ethereum . CallMsg {
To : & a ,
}
g , err := b . client . EstimateGas ( ctx , msg )
2018-07-24 07:58:37 -06:00
var r big . Int
2018-03-27 08:34:58 -06:00
if err != nil {
2018-07-24 07:58:37 -06:00
return r , err
2018-03-27 08:34:58 -06:00
}
2018-07-24 07:58:37 -06:00
r . SetUint64 ( g )
return r , nil
2018-03-15 01:19:02 -06:00
}
2018-03-27 08:34:58 -06:00
// SendRawTransaction sends raw transaction.
2018-04-03 14:24:23 -06:00
func ( b * EthereumRPC ) SendRawTransaction ( tx string ) ( string , error ) {
2018-03-28 02:25:08 -06:00
return "" , errors . New ( "SendRawTransaction: not implemented" )
2018-03-15 01:19:02 -06:00
}
2018-06-01 05:22:56 -06:00
func ( b * EthereumRPC ) ResyncMempool ( onNewTxAddr func ( txid string , addr string ) ) ( int , error ) {
2018-03-29 09:30:12 -06:00
return b . Mempool . Resync ( onNewTxAddr )
2018-03-15 01:19:02 -06:00
}
2018-04-03 14:24:23 -06:00
func ( b * EthereumRPC ) GetMempoolTransactions ( address string ) ( [ ] string , error ) {
2018-03-29 09:30:12 -06:00
return b . Mempool . GetTransactions ( address )
2018-03-15 01:19:02 -06:00
}
2018-04-03 14:24:23 -06:00
func ( b * EthereumRPC ) GetMempoolEntry ( txid string ) ( * bchain . MempoolEntry , error ) {
return nil , errors . New ( "GetMempoolEntry: not implemented" )
2018-03-15 01:19:02 -06:00
}
2018-04-03 14:24:23 -06:00
func ( b * EthereumRPC ) GetChainParser ( ) bchain . BlockChainParser {
2018-03-19 10:36:18 -06:00
return b . Parser
2018-03-15 01:19:02 -06:00
}