From 45230abb631d590a830a99a2a51bc5b816250cd5 Mon Sep 17 00:00:00 2001 From: Jaynti Kanani <jdkanani@gmail.com> Date: Sat, 17 Oct 2020 13:52:07 +0530 Subject: [PATCH] fix: add block receipt --- core/blockchain.go | 19 ++++- core/bor_blockchain.go | 30 +++++++ core/rawdb/accessors_chain.go | 19 ++++- core/rawdb/accessors_chain_test.go | 2 +- core/rawdb/bor_receipt.go | 133 +++++++++++++++++++++++++++++ core/rawdb/database.go | 2 +- core/rawdb/freezer.go | 13 ++- core/rawdb/schema.go | 1 + core/rawdb/table.go | 4 +- core/types/bor_receipt.go | 110 ++++++++++++++++++++++++ eth/api_backend.go | 15 ---- eth/bor_api_backend.go | 46 ++++++++++ ethclient/bor_ethclient.go | 30 +++++++ ethclient/ethclient.go | 9 -- ethdb/database.go | 2 +- internal/ethapi/api.go | 8 -- internal/ethapi/backend.go | 3 + internal/ethapi/bor_api.go | 20 +++++ les/api_backend.go | 4 + 19 files changed, 427 insertions(+), 43 deletions(-) create mode 100644 core/bor_blockchain.go create mode 100644 core/rawdb/bor_receipt.go create mode 100644 core/types/bor_receipt.go create mode 100644 eth/bor_api_backend.go create mode 100644 ethclient/bor_ethclient.go create mode 100644 internal/ethapi/bor_api.go diff --git a/core/blockchain.go b/core/blockchain.go index 6ecab669b..4b0886f06 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -196,6 +196,8 @@ type BlockChain struct { badBlocks *lru.Cache // Bad block cache shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block. terminateInsert func(common.Hash, uint64) bool // Testing hook used to terminate ancient receipt chain insertion. + + borReceiptsCache *lru.Cache // Cache for the most recent bor receipt receipts per block } // NewBlockChain returns a fully initialised block chain using information @@ -219,6 +221,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par futureBlocks, _ := lru.New(maxFutureBlocks) badBlocks, _ := lru.New(badBlockLimit) + borReceiptsCache, _ := lru.New(receiptsCacheLimit) + bc := &BlockChain{ chainConfig: chainConfig, cacheConfig: cacheConfig, @@ -236,6 +240,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par engine: engine, vmConfig: vmConfig, badBlocks: badBlocks, + + borReceiptsCache: borReceiptsCache, } bc.validator = NewBlockValidator(chainConfig, bc, engine) bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine) @@ -1155,7 +1161,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ } h := rawdb.ReadCanonicalHash(bc.db, frozen) b := rawdb.ReadBlock(bc.db, h, frozen) - size += rawdb.WriteAncientBlock(bc.db, b, rawdb.ReadReceipts(bc.db, h, frozen, bc.chainConfig), rawdb.ReadTd(bc.db, h, frozen)) + size += rawdb.WriteAncientBlock(bc.db, b, rawdb.ReadReceipts(bc.db, h, frozen, bc.chainConfig), rawdb.ReadTd(bc.db, h, frozen), rawdb.ReadBorReceipt(bc.db, h, frozen)) count += 1 // Always keep genesis block in active database. @@ -1198,7 +1204,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ log.Info("Migrated ancient blocks", "count", count, "elapsed", common.PrettyDuration(time.Since(start))) } // Flush data into ancient database. - size += rawdb.WriteAncientBlock(bc.db, block, receiptChain[i], bc.GetTd(block.Hash(), block.NumberU64())) + size += rawdb.WriteAncientBlock(bc.db, block, receiptChain[i], bc.GetTd(block.Hash(), block.NumberU64()), bc.GetBorReceiptByHash(block.Hash())) // Write tx indices if any condition is satisfied: // * If user requires to reserve all tx indices(txlookuplimit=0) @@ -1438,6 +1444,15 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd) rawdb.WriteBlock(blockBatch, block) rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts) + + // storing bor block receipt + blockLogs := state.Logs() + if len(blockLogs) > len(logs) { + rawdb.WriteBorReceipt(blockBatch, block.Hash(), block.NumberU64(), &types.BorReceiptForStorage{ + Logs: blockLogs[len(logs):], + }) + } + rawdb.WritePreimages(blockBatch, state.Preimages()) if err := blockBatch.Write(); err != nil { log.Crit("Failed to write block into disk", "err", err) diff --git a/core/bor_blockchain.go b/core/bor_blockchain.go new file mode 100644 index 000000000..21e5b73fb --- /dev/null +++ b/core/bor_blockchain.go @@ -0,0 +1,30 @@ +package core + +import ( + "github.com/maticnetwork/bor/common" + "github.com/maticnetwork/bor/core/rawdb" + "github.com/maticnetwork/bor/core/types" +) + +// GetBorReceiptByHash retrieves the bor block receipt in a given block. +func (bc *BlockChain) GetBorReceiptByHash(hash common.Hash) *types.BorReceipt { + if receipt, ok := bc.borReceiptsCache.Get(hash); ok { + return receipt.(*types.BorReceipt) + } + + // read header from hash + number := rawdb.ReadHeaderNumber(bc.db, hash) + if number == nil { + return nil + } + + // read bor reciept by hash and number + receipt := rawdb.ReadBorReceipt(bc.db, hash, *number) + if receipt == nil { + return nil + } + + // add into bor receipt cache + bc.borReceiptsCache.Add(hash, receipt) + return receipt +} diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 1c6b213de..d863e2408 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -596,7 +596,7 @@ func WriteBlock(db ethdb.KeyValueWriter, block *types.Block) { } // WriteAncientBlock writes entire block data into ancient store and returns the total written size. -func WriteAncientBlock(db ethdb.AncientWriter, block *types.Block, receipts types.Receipts, td *big.Int) int { +func WriteAncientBlock(db ethdb.AncientWriter, block *types.Block, receipts types.Receipts, td *big.Int, borReceipt *types.BorReceipt) int { // Encode all block components to RLP format. headerBlob, err := rlp.EncodeToBytes(block.Header()) if err != nil { @@ -618,8 +618,17 @@ func WriteAncientBlock(db ethdb.AncientWriter, block *types.Block, receipts type if err != nil { log.Crit("Failed to RLP encode block total difficulty", "err", err) } + + borReceiptBlob := make([]byte, 0) + if borReceipt != nil { + borReceiptBlob, err = rlp.EncodeToBytes(borReceipt) + if err != nil { + log.Crit("Failed to RLP encode bor block receipt", "err", err) + } + } + // Write all blob to flatten files. - err = db.AppendAncient(block.NumberU64(), block.Hash().Bytes(), headerBlob, bodyBlob, receiptBlob, tdBlob) + err = db.AppendAncient(block.NumberU64(), block.Hash().Bytes(), headerBlob, bodyBlob, receiptBlob, tdBlob, borReceiptBlob) if err != nil { log.Crit("Failed to write block data to ancient store", "err", err) } @@ -632,6 +641,9 @@ func DeleteBlock(db ethdb.KeyValueWriter, hash common.Hash, number uint64) { DeleteHeader(db, hash, number) DeleteBody(db, hash, number) DeleteTd(db, hash, number) + + // delete bor receipt + DeleteBorReceipt(db, hash, number) } // DeleteBlockWithoutNumber removes all block data associated with a hash, except @@ -641,6 +653,9 @@ func DeleteBlockWithoutNumber(db ethdb.KeyValueWriter, hash common.Hash, number deleteHeaderWithoutNumber(db, hash, number) DeleteBody(db, hash, number) DeleteTd(db, hash, number) + + // delete bor receipt + DeleteBorReceipt(db, hash, number) } // FindCommonAncestor returns the last common ancestor of two block headers diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index 61c0925c6..1b93aade8 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -396,7 +396,7 @@ func TestAncientStorage(t *testing.T) { t.Fatalf("non existent td returned") } // Write and verify the header in the database - WriteAncientBlock(db, block, nil, big.NewInt(100)) + WriteAncientBlock(db, block, nil, big.NewInt(100), nil) if blob := ReadHeaderRLP(db, hash, number); len(blob) == 0 { t.Fatalf("no header returned") } diff --git a/core/rawdb/bor_receipt.go b/core/rawdb/bor_receipt.go new file mode 100644 index 000000000..e34e0dc89 --- /dev/null +++ b/core/rawdb/bor_receipt.go @@ -0,0 +1,133 @@ +package rawdb + +import ( + "fmt" + + "github.com/maticnetwork/bor/common" + "github.com/maticnetwork/bor/core/types" + "github.com/maticnetwork/bor/ethdb" + "github.com/maticnetwork/bor/log" + "github.com/maticnetwork/bor/rlp" +) + +var ( + borReceiptPrefix = []byte("bor-receipt-") // borReceiptPrefix + number + block hash -> bor block receipt + + // freezerReceiptTable indicates the name of the freezer bor receipts table. + freezerBorReceiptTable = "bor-receipts" +) + +// borReceiptKey = borReceiptPrefix + num (uint64 big endian) + hash +func borReceiptKey(number uint64, hash common.Hash) []byte { + return append(append(borReceiptPrefix, encodeBlockNumber(number)...), hash.Bytes()...) +} + +// HasBorReceipt verifies the existence of all block receipt belonging +// to a block. +func HasBorReceipt(db ethdb.Reader, hash common.Hash, number uint64) bool { + if has, err := db.Ancient(freezerHashTable, number); err == nil && common.BytesToHash(has) == hash { + return true + } + + if has, err := db.Has(borReceiptKey(number, hash)); !has || err != nil { + return false + } + + return true +} + +// ReadBorReceiptRLP retrieves all the transaction receipts belonging to a block in RLP encoding. +func ReadBorReceiptRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue { + // First try to look up the data in ancient database. Extra hash + // comparison is necessary since ancient database only maintains + // the canonical data. + data, _ := db.Ancient(freezerBorReceiptTable, number) + if len(data) > 0 { + h, _ := db.Ancient(freezerHashTable, number) + if common.BytesToHash(h) == hash { + return data + } + } + // Then try to look up the data in leveldb. + data, _ = db.Get(borReceiptKey(number, hash)) + if len(data) > 0 { + fmt.Println("==> RAWDB IN ReadBorReceiptRLP", common.Bytes2Hex(data)) + return data + } + // In the background freezer is moving data from leveldb to flatten files. + // So during the first check for ancient db, the data is not yet in there, + // but when we reach into leveldb, the data was already moved. That would + // result in a not found error. + data, _ = db.Ancient(freezerReceiptTable, number) + if len(data) > 0 { + h, _ := db.Ancient(freezerHashTable, number) + if common.BytesToHash(h) == hash { + return data + } + } + return nil // Can't find the data anywhere. +} + +// ReadRawBorReceipt retrieves the block receipt belonging to a block. +// The receipt metadata fields are not guaranteed to be populated, so they +// should not be used. Use ReadBorReceipt instead if the metadata is needed. +func ReadRawBorReceipt(db ethdb.Reader, hash common.Hash, number uint64) *types.BorReceipt { + // Retrieve the flattened receipt slice + data := ReadBorReceiptRLP(db, hash, number) + if data == nil || len(data) == 0 { + return nil + } + + // Convert the receipts from their storage form to their internal representation + var storageReceipt types.BorReceiptForStorage + if err := rlp.DecodeBytes(data, &storageReceipt); err != nil { + log.Error("Invalid receipt array RLP", "hash", hash, "err", err) + return nil + } + + return (*types.BorReceipt)(&storageReceipt) +} + +// ReadBorReceipt retrieves all the bor block receipts belonging to a block, including +// its correspoinding metadata fields. If it is unable to populate these metadata +// fields then nil is returned. +func ReadBorReceipt(db ethdb.Reader, hash common.Hash, number uint64) *types.BorReceipt { + // We're deriving many fields from the block body, retrieve beside the receipt + borReceipt := ReadRawBorReceipt(db, hash, number) + if borReceipt == nil { + return nil + } + + body := ReadBody(db, hash, number) + if body == nil { + log.Error("Missing body but have bor receipt", "hash", hash, "number", number) + return nil + } + + if err := borReceipt.DeriveFields(hash, number); err != nil { + log.Error("Failed to derive bor receipt fields", "hash", hash, "number", number, "err", err) + return nil + } + return borReceipt +} + +// WriteBorReceipt stores all the bor receipt belonging to a block. +func WriteBorReceipt(db ethdb.KeyValueWriter, hash common.Hash, number uint64, borReceipt *types.BorReceiptForStorage) { + // Convert the bor receipt into their storage form and serialize them + bytes, err := rlp.EncodeToBytes(borReceipt) + if err != nil { + log.Crit("Failed to encode bor receipt", "err", err) + } + + // Store the flattened receipt slice + if err := db.Put(borReceiptKey(number, hash), bytes); err != nil { + log.Crit("Failed to store bor receipt", "err", err) + } +} + +// DeleteBorReceipt removes receipt data associated with a block hash. +func DeleteBorReceipt(db ethdb.KeyValueWriter, hash common.Hash, number uint64) { + if err := db.Delete(borReceiptKey(number, hash)); err != nil { + log.Crit("Failed to delete bor receipt", "err", err) + } +} diff --git a/core/rawdb/database.go b/core/rawdb/database.go index b9829d236..1375f5b34 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -79,7 +79,7 @@ func (db *nofreezedb) AncientSize(kind string) (uint64, error) { } // AppendAncient returns an error as we don't have a backing chain freezer. -func (db *nofreezedb) AppendAncient(number uint64, hash, header, body, receipts, td []byte) error { +func (db *nofreezedb) AppendAncient(number uint64, hash, header, body, receipts, td, borBlockReceipt []byte) error { return errNotSupported } diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index 42bb69d70..3690dde9a 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -180,7 +180,7 @@ func (f *freezer) AncientSize(kind string) (uint64, error) { // Notably, this function is lock free but kind of thread-safe. All out-of-order // injection will be rejected. But if two injections with same number happen at // the same time, we can get into the trouble. -func (f *freezer) AppendAncient(number uint64, hash, header, body, receipts, td []byte) (err error) { +func (f *freezer) AppendAncient(number uint64, hash, header, body, receipts, td, borBlockReceipt []byte) (err error) { // Ensure the binary blobs we are appending is continuous with freezer. if atomic.LoadUint64(&f.frozen) != number { return errOutOrderInsertion @@ -217,6 +217,11 @@ func (f *freezer) AppendAncient(number uint64, hash, header, body, receipts, td log.Error("Failed to append ancient difficulty", "number", f.frozen, "hash", hash, "err", err) return err } + if err := f.tables[freezerBorReceiptTable].Append(f.frozen, borBlockReceipt); err != nil { + log.Error("Failed to append bor block receipt", "number", f.frozen, "hash", hash, "err", err) + return err + } + atomic.AddUint64(&f.frozen, 1) // Only modify atomically return nil } @@ -340,9 +345,13 @@ func (f *freezer) freeze(db ethdb.KeyValueStore) { log.Error("Total difficulty missing, can't freeze", "number", f.frozen, "hash", hash) break } + + // bor block receipt + borBlockReceipt := ReadBorReceiptRLP(nfdb, hash, f.frozen) + log.Trace("Deep froze ancient block", "number", f.frozen, "hash", hash) // Inject all the components into the relevant data tables - if err := f.AppendAncient(f.frozen, hash[:], header, body, receipts, td); err != nil { + if err := f.AppendAncient(f.frozen, hash[:], header, body, receipts, td, borBlockReceipt); err != nil { break } ancients = append(ancients, hash) diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 9157c97a6..4def3c77e 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -101,6 +101,7 @@ var freezerNoSnappy = map[string]bool{ freezerHashTable: true, freezerBodiesTable: false, freezerReceiptTable: false, + freezerBorReceiptTable: false, freezerDifficultyTable: true, } diff --git a/core/rawdb/table.go b/core/rawdb/table.go index 428373c47..ca1689eb5 100644 --- a/core/rawdb/table.go +++ b/core/rawdb/table.go @@ -76,8 +76,8 @@ func (t *table) AncientSize(kind string) (uint64, error) { // AppendAncient is a noop passthrough that just forwards the request to the underlying // database. -func (t *table) AppendAncient(number uint64, hash, header, body, receipts, td []byte) error { - return t.db.AppendAncient(number, hash, header, body, receipts, td) +func (t *table) AppendAncient(number uint64, hash, header, body, receipts, td, borBlockReceipt []byte) error { + return t.db.AppendAncient(number, hash, header, body, receipts, td, borBlockReceipt) } // TruncateAncients is a noop passthrough that just forwards the request to the underlying diff --git a/core/types/bor_receipt.go b/core/types/bor_receipt.go new file mode 100644 index 000000000..a62895e31 --- /dev/null +++ b/core/types/bor_receipt.go @@ -0,0 +1,110 @@ +package types + +import ( + "io" + "math/big" + + "github.com/maticnetwork/bor/common" + "github.com/maticnetwork/bor/crypto" + "github.com/maticnetwork/bor/rlp" +) + +// BorReceipt represents the results of a block state syncs +type BorReceipt struct { + // Consensus fields + Bloom Bloom `json:"logsBloom" gencodec:"required"` + Logs []*Log `json:"logs" gencodec:"required"` + + // Inclusion information: These fields provide information about the inclusion of the + // transaction corresponding to this receipt. + BlockHash common.Hash `json:"blockHash,omitempty"` + BlockNumber *big.Int `json:"blockNumber,omitempty"` +} + +// borReceiptRLP is the consensus encoding of a block receipt. +type borReceiptRLP struct { + Bloom Bloom + Logs []*Log +} + +// storedBorReceiptRLP is the storage encoding of a block receipt. +type storedBorReceiptRLP struct { + Logs []*LogForStorage +} + +// EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a block receipt +// into an RLP stream. If no post state is present, byzantium fork is assumed. +func (r *BorReceipt) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, &borReceiptRLP{r.Bloom, r.Logs}) +} + +// DecodeRLP implements rlp.Decoder, and loads the consensus fields of a block receipt +// from an RLP stream. +func (r *BorReceipt) DecodeRLP(s *rlp.Stream) error { + var dec receiptRLP + if err := s.Decode(&dec); err != nil { + return err + } + r.Bloom, r.Logs = dec.Bloom, dec.Logs + return nil +} + +// BorReceiptForStorage is a wrapper around a Bor Receipt that flattens and parses the +// entire content of a receipt, as opposed to only the consensus fields originally. +type BorReceiptForStorage BorReceipt + +// EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt +// into an RLP stream. +func (r *BorReceiptForStorage) EncodeRLP(w io.Writer) error { + enc := &storedBorReceiptRLP{ + Logs: make([]*LogForStorage, len(r.Logs)), + } + + for i, log := range r.Logs { + enc.Logs[i] = (*LogForStorage)(log) + } + return rlp.Encode(w, enc) +} + +// DecodeRLP implements rlp.Decoder, and loads both consensus and implementation +// fields of a receipt from an RLP stream. +func (r *BorReceiptForStorage) DecodeRLP(s *rlp.Stream) error { + // Retrieve the entire receipt blob as we need to try multiple decoders + blob, err := s.Raw() + if err != nil { + return err + } + + return decodeStoredBorReceiptRLP(r, blob) +} + +func decodeStoredBorReceiptRLP(r *BorReceiptForStorage, blob []byte) error { + var stored storedBorReceiptRLP + if err := rlp.DecodeBytes(blob, &stored); err != nil { + return err + } + + r.Logs = make([]*Log, len(stored.Logs)) + for i, log := range stored.Logs { + r.Logs[i] = (*Log)(log) + } + r.Bloom = BytesToBloom(LogsBloom(r.Logs).Bytes()) + + return nil +} + +// DeriveFields fills the receipts with their computed fields based on consensus +// data and contextual infos like containing block and transactions. +func (r *BorReceipt) DeriveFields(hash common.Hash, number uint64) error { + txHash := common.BytesToHash(crypto.Keccak256(append([]byte("matic-receipt-"), hash.Bytes()...))) + + // The derived log fields can simply be set from the block and transaction + for j := 0; j < len(r.Logs); j++ { + r.Logs[j].BlockNumber = number + r.Logs[j].BlockHash = hash + r.Logs[j].TxHash = txHash + r.Logs[j].TxIndex = uint(0) + r.Logs[j].Index = uint(j) + } + return nil +} diff --git a/eth/api_backend.go b/eth/api_backend.go index 6f50814cc..31e38ab78 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -23,7 +23,6 @@ import ( "github.com/maticnetwork/bor/accounts" "github.com/maticnetwork/bor/common" - "github.com/maticnetwork/bor/consensus/bor" "github.com/maticnetwork/bor/core" "github.com/maticnetwork/bor/core/bloombits" "github.com/maticnetwork/bor/core/rawdb" @@ -312,17 +311,3 @@ func (b *EthAPIBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests) } } - -func (b *EthAPIBackend) GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) { - var api *bor.API - for _, _api := range b.eth.Engine().APIs(b.eth.BlockChain()) { - if _api.Namespace == "bor" { - api = _api.Service.(*bor.API) - } - } - root, err := api.GetRootHash(starBlockNr, endBlockNr) - if err != nil { - return "", err - } - return root, nil -} diff --git a/eth/bor_api_backend.go b/eth/bor_api_backend.go new file mode 100644 index 000000000..ac2c4ec73 --- /dev/null +++ b/eth/bor_api_backend.go @@ -0,0 +1,46 @@ +package eth + +import ( + "context" + + ethereum "github.com/maticnetwork/bor" + "github.com/maticnetwork/bor/common" + "github.com/maticnetwork/bor/consensus/bor" + "github.com/maticnetwork/bor/core/types" +) + +func (b *EthAPIBackend) GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) { + var api *bor.API + for _, _api := range b.eth.Engine().APIs(b.eth.BlockChain()) { + if _api.Namespace == "bor" { + api = _api.Service.(*bor.API) + } + } + + root, err := api.GetRootHash(starBlockNr, endBlockNr) + if err != nil { + return "", err + } + return root, nil +} + +func (b *EthAPIBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) { + receipt := b.eth.blockchain.GetBorReceiptByHash(hash) + if receipt == nil { + return nil, ethereum.NotFound + } + + return receipt, nil +} + +// func (b *EthAPIBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) { +// receipts := b.eth.blockchain.GetReceiptsByHash(hash) +// if receipts == nil { +// return nil, nil +// } +// logs := make([][]*types.Log, len(receipts)) +// for i, receipt := range receipts { +// logs[i] = receipt.Logs +// } +// return logs, nil +// } diff --git a/ethclient/bor_ethclient.go b/ethclient/bor_ethclient.go new file mode 100644 index 000000000..4b1a01a26 --- /dev/null +++ b/ethclient/bor_ethclient.go @@ -0,0 +1,30 @@ +package ethclient + +import ( + "context" + + ethereum "github.com/maticnetwork/bor" + "github.com/maticnetwork/bor/common" + "github.com/maticnetwork/bor/core/types" +) + +// GetRootHash returns the merkle root of the block headers +func (ec *Client) GetRootHash(ctx context.Context, startBlockNumber uint64, endBlockNumber uint64) (string, error) { + var rootHash string + if err := ec.c.CallContext(ctx, &rootHash, "eth_getRootHash", startBlockNumber, endBlockNumber); err != nil { + return "", err + } + return rootHash, nil +} + +// GetBorBlockReceipt returns bor block receipt +func (ec *Client) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) { + var r *types.BorReceipt + err := ec.c.CallContext(ctx, &r, "eth_getBorBlockReceipt", hash) + if err == nil { + if r == nil { + return nil, ethereum.NotFound + } + } + return r, err +} diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 78b58e7a1..44fbd10de 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -522,15 +522,6 @@ func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) er return ec.c.CallContext(ctx, nil, "eth_sendRawTransaction", hexutil.Encode(data)) } -// GetRootHash returns the merkle root of the block headers -func (ec *Client) GetRootHash(ctx context.Context, startBlockNumber uint64, endBlockNumber uint64) (string, error) { - var rootHash string - if err := ec.c.CallContext(ctx, &rootHash, "eth_getRootHash", startBlockNumber, endBlockNumber); err != nil { - return "", err - } - return rootHash, nil -} - func toCallArg(msg ethereum.CallMsg) interface{} { arg := map[string]interface{}{ "from": msg.From, diff --git a/ethdb/database.go b/ethdb/database.go index 0dc14624b..e90f023fb 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -87,7 +87,7 @@ type AncientReader interface { type AncientWriter interface { // AppendAncient injects all binary blobs belong to block at the end of the // append-only immutable table files. - AppendAncient(number uint64, hash, header, body, receipt, td []byte) error + AppendAncient(number uint64, hash, header, body, receipt, td, borBlockReceipt []byte) error // TruncateAncients discards all but the first n ancient data from the ancient store. TruncateAncients(n uint64) error diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index f329e2636..09a3e0c47 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -748,14 +748,6 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.A return res[:], state.Error() } -func (s *PublicBlockChainAPI) GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) { - root, err := s.b.GetRootHash(ctx, starBlockNr, endBlockNr) - if err != nil { - return "", err - } - return root, nil -} - // CallArgs represents the arguments for a call. type CallArgs struct { From *common.Address `json:"from"` diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 0a1a606ef..272aea858 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -65,7 +65,10 @@ type Backend interface { SubscribeStateSyncEvent(ch chan<- core.StateSyncEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription + + // Bor API GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) + GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) // Transaction pool API SendTx(ctx context.Context, signedTx *types.Transaction) error diff --git a/internal/ethapi/bor_api.go b/internal/ethapi/bor_api.go new file mode 100644 index 000000000..3cf1347a4 --- /dev/null +++ b/internal/ethapi/bor_api.go @@ -0,0 +1,20 @@ +package ethapi + +import ( + "context" + + "github.com/maticnetwork/bor/common" + "github.com/maticnetwork/bor/core/types" +) + +func (s *PublicBlockChainAPI) GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) { + root, err := s.b.GetRootHash(ctx, starBlockNr, endBlockNr) + if err != nil { + return "", err + } + return root, nil +} + +func (s *PublicBlockChainAPI) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) { + return s.b.GetBorBlockReceipt(ctx, hash) +} diff --git a/les/api_backend.go b/les/api_backend.go index 46c348eb5..86dc91ea2 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -287,3 +287,7 @@ func (b *LesApiBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma func (b *LesApiBackend) GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) { return "", errors.New("Not implemented") } + +func (b *LesApiBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) { + return nil, errors.New("Not implemented") +} -- GitLab