fix: add block receipt

This commit is contained in:
Jaynti Kanani 2020-10-17 13:52:07 +05:30
parent 93e2ac2733
commit 45230abb63
No known key found for this signature in database
GPG key ID: 4396982C976BAE5E
19 changed files with 427 additions and 43 deletions

View file

@ -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)

30
core/bor_blockchain.go Normal file
View file

@ -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
}

View file

@ -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

View file

@ -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")
}

133
core/rawdb/bor_receipt.go Normal file
View file

@ -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)
}
}

View file

@ -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
}

View file

@ -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)

View file

@ -101,6 +101,7 @@ var freezerNoSnappy = map[string]bool{
freezerHashTable: true,
freezerBodiesTable: false,
freezerReceiptTable: false,
freezerBorReceiptTable: false,
freezerDifficultyTable: true,
}

View file

@ -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

110
core/types/bor_receipt.go Normal file
View file

@ -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
}

View file

@ -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
}

46
eth/bor_api_backend.go Normal file
View file

@ -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
// }

View file

@ -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
}

View file

@ -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,

View file

@ -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

View file

@ -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"`

View file

@ -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

View file

@ -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)
}

View file

@ -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")
}