From fad7ea326cb7de2dc26b8b14f6bc7d42d476d273 Mon Sep 17 00:00:00 2001 From: Martin Boehm Date: Thu, 15 Nov 2018 18:07:45 +0100 Subject: [PATCH] Load ERC20 events in eth.GetBlock --- bchain/coins/eth/ethparser.go | 49 ++++++++++++++++++++--------------- bchain/coins/eth/ethrpc.go | 33 +++++++++++++++++++---- 2 files changed, 56 insertions(+), 26 deletions(-) diff --git a/bchain/coins/eth/ethparser.go b/bchain/coins/eth/ethparser.go index 7856baa9..ff13bd24 100644 --- a/bchain/coins/eth/ethparser.go +++ b/bchain/coins/eth/ethparser.go @@ -27,26 +27,26 @@ func NewEthereumParser() *EthereumParser { } type rpcHeader struct { - Hash ethcommon.Hash `json:"hash"` - Difficulty string `json:"difficulty"` - Number string `json:"number"` - Time string `json:"timestamp"` - Size string `json:"size"` - Nonce string `json:"nonce"` + Hash string `json:"hash"` + Difficulty string `json:"difficulty"` + Number string `json:"number"` + Time string `json:"timestamp"` + Size string `json:"size"` + Nonce string `json:"nonce"` } type rpcTransaction struct { - AccountNonce string `json:"nonce"` - GasPrice string `json:"gasPrice"` - GasLimit string `json:"gas"` - To string `json:"to" rlp:"nil"` // nil means contract creation - Value string `json:"value"` - Payload string `json:"input"` - Hash ethcommon.Hash `json:"hash" rlp:"-"` - BlockNumber string `json:"blockNumber"` - BlockHash *ethcommon.Hash `json:"blockHash,omitempty"` - From string `json:"from"` - TransactionIndex string `json:"transactionIndex"` + AccountNonce string `json:"nonce"` + GasPrice string `json:"gasPrice"` + GasLimit string `json:"gas"` + To string `json:"to"` // nil means contract creation + Value string `json:"value"` + Payload string `json:"input"` + Hash string `json:"hash"` + BlockNumber string `json:"blockNumber"` + BlockHash string `json:"blockHash,omitempty"` + From string `json:"from"` + TransactionIndex string `json:"transactionIndex"` // Signature values - ignored // V string `json:"v"` // R string `json:"r"` @@ -59,6 +59,11 @@ type rpcLog struct { Data string `json:"data"` } +type rpcLogWithTxHash struct { + rpcLog + Hash string `json:"transactionHash"` +} + type rpcReceipt struct { GasUsed string `json:"gasUsed"` Status string `json:"status"` @@ -86,7 +91,7 @@ func ethNumber(n string) (int64, error) { } func (p *EthereumParser) ethTxToTx(tx *rpcTransaction, receipt *rpcReceipt, blocktime int64, confirmations uint32, marshallHex bool) (*bchain.Tx, error) { - txid := tx.Hash.Hex() + txid := tx.Hash var ( fa, ta []string err error @@ -105,7 +110,7 @@ func (p *EthereumParser) ethTxToTx(tx *rpcTransaction, receipt *rpcReceipt, bloc if marshallHex { // completeTransaction without BlockHash is marshalled and hex encoded to bchain.Tx.Hex bh := tx.BlockHash - tx.BlockHash = nil + tx.BlockHash = "" b, err := json.Marshal(ct) if err != nil { return nil, err @@ -235,7 +240,9 @@ func (p *EthereumParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ( if pt.Tx.GasLimit, err = hexutil.DecodeUint64(r.Tx.GasLimit); err != nil { return nil, errors.Annotatef(err, "GasLimit %v", r.Tx.GasLimit) } - pt.Tx.Hash = r.Tx.Hash.Bytes() + if pt.Tx.Hash, err = hexDecode(r.Tx.Hash); err != nil { + return nil, errors.Annotatef(err, "Hash %v", r.Tx.Hash) + } if pt.Tx.Payload, err = hexDecode(r.Tx.Payload); err != nil { return nil, errors.Annotatef(err, "Payload %v", r.Tx.Payload) } @@ -306,7 +313,7 @@ func (p *EthereumParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) { BlockNumber: hexutil.EncodeUint64(uint64(pt.BlockNumber)), From: hexutil.Encode(pt.Tx.From), GasLimit: hexutil.EncodeUint64(pt.Tx.GasLimit), - Hash: ethcommon.BytesToHash(pt.Tx.Hash), + Hash: hexutil.Encode(pt.Tx.Hash), Payload: hexutil.Encode(pt.Tx.Payload), GasPrice: hexEncodeBig(pt.Tx.GasPrice), // R: hexEncodeBig(pt.R), diff --git a/bchain/coins/eth/ethrpc.go b/bchain/coins/eth/ethrpc.go index d04369cb..6339cf83 100644 --- a/bchain/coins/eth/ethrpc.go +++ b/bchain/coins/eth/ethrpc.go @@ -374,7 +374,7 @@ func (b *EthereumRPC) ethHeaderToBlockHeader(h *rpcHeader) (*bchain.BlockHeader, return nil, err } return &bchain.BlockHeader{ - Hash: h.Hash.Hex(), + Hash: h.Hash, Height: uint32(height), Confirmations: int(c), Time: time, @@ -427,6 +427,25 @@ func (b *EthereumRPC) getBlockRaw(hash string, height uint32, fullTxs bool) (jso return raw, nil } +func (b *EthereumRPC) getERC20EventsForBlock(blockNumber string) (map[string][]*rpcLog, error) { + ctx, cancel := context.WithTimeout(context.Background(), b.timeout) + defer cancel() + var logs []rpcLogWithTxHash + err := b.rpc.CallContext(ctx, &logs, "eth_getLogs", map[string]interface{}{ + "fromBlock": blockNumber, + "toBlock": blockNumber, + "topics": []string{erc20EventTransferSignature}, + }) + if err != nil { + return nil, errors.Annotatef(err, "blockNumber %v", blockNumber) + } + r := make(map[string][]*rpcLog) + for _, l := range logs { + r[l.Hash] = append(r[l.Hash], &l.rpcLog) + } + return r, nil +} + // GetBlock returns block with given hash or height, hash has precedence if both passed func (b *EthereumRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) { raw, err := b.getBlockRaw(hash, height, true) @@ -445,12 +464,16 @@ func (b *EthereumRPC) GetBlock(hash string, height uint32) (*bchain.Block, error if err != nil { return nil, errors.Annotatef(err, "hash %v, height %v", hash, height) } - // TODO - get ERC20 events + // get ERC20 events + logs, err := b.getERC20EventsForBlock(head.Number) + if err != nil { + return nil, err + } btxs := make([]bchain.Tx, len(body.Transactions)) for i, tx := range body.Transactions { - btx, err := b.Parser.ethTxToTx(&tx, nil, bbh.Time, uint32(bbh.Confirmations), false) + btx, err := b.Parser.ethTxToTx(&tx, &rpcReceipt{Logs: logs[tx.Hash]}, bbh.Time, uint32(bbh.Confirmations), false) if err != nil { - return nil, errors.Annotatef(err, "hash %v, height %v, txid %v", hash, height, tx.Hash.String()) + return nil, errors.Annotatef(err, "hash %v, height %v, txid %v", hash, height, tx.Hash) } btxs[i] = *btx } @@ -511,7 +534,7 @@ func (b *EthereumRPC) GetTransaction(txid string) (*bchain.Tx, error) { } } else { // non mempool tx - we must read the block header to get the block time - raw, err := b.getBlockRaw(tx.BlockHash.Hex(), 0, false) + raw, err := b.getBlockRaw(tx.BlockHash, 0, false) if err != nil { return nil, err }