Merge pull request #1597 from chaosma/tx-rpc

Add RPC call for CXReceipt
pull/1603/head
chaosma 5 years ago committed by GitHub
commit 510c4e528a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      core/blockchain.go
  2. 73
      core/rawdb/accessors_indexes.go
  3. 6
      core/rawdb/schema.go
  4. 4
      core/types/block.go
  5. 7
      core/types/bodyv0.go
  6. 16
      core/types/bodyv1.go
  7. 8
      internal/hmyapi/transactionpool.go
  8. 34
      internal/hmyapi/types.go

@ -1109,6 +1109,9 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
rawdb.WriteTxLookupEntries(batch, block)
rawdb.WritePreimages(batch, block.NumberU64(), state.Preimages())
// write the positional metadata for CXReceipts lookups
rawdb.WriteCxLookupEntries(batch, block)
status = CanonStatTy
} else {
status = SideStatTy

@ -123,3 +123,76 @@ func WriteBloomBits(db DatabaseWriter, bit uint, section uint64, head common.Has
utils.Logger().Error().Err(err).Msg("Failed to store bloom bits")
}
}
// ReadCxLookupEntry retrieves the positional metadata associated with a transaction hash
// to allow retrieving cross shard receipt by hash in destination shard
// not the original transaction in source shard
// return nil if not found
func ReadCxLookupEntry(db DatabaseReader, hash common.Hash) (common.Hash, uint64, uint64) {
data, _ := db.Get(cxLookupKey(hash))
if len(data) == 0 {
return common.Hash{}, 0, 0
}
var entry TxLookupEntry
if err := rlp.DecodeBytes(data, &entry); err != nil {
utils.Logger().Error().Err(err).Str("hash", hash.Hex()).Msg("Invalid transaction lookup entry RLP")
return common.Hash{}, 0, 0
}
return entry.BlockHash, entry.BlockIndex, entry.Index
}
// WriteCxLookupEntries stores a positional metadata for every transaction from
// a block, enabling hash based transaction and receipt lookups.
func WriteCxLookupEntries(db DatabaseWriter, block *types.Block) {
previousSum := 0
for _, cxp := range block.IncomingReceipts() {
for j, cx := range cxp.Receipts {
entry := TxLookupEntry{
BlockHash: block.Hash(),
BlockIndex: block.NumberU64(),
Index: uint64(j + previousSum),
}
data, err := rlp.EncodeToBytes(entry)
if err != nil {
utils.Logger().Error().Err(err).Msg("Failed to encode transaction lookup entry")
}
if err := db.Put(cxLookupKey(cx.TxHash), data); err != nil {
utils.Logger().Error().Err(err).Msg("Failed to store transaction lookup entry")
}
}
previousSum += len(cxp.Receipts)
}
}
// DeleteCxLookupEntry removes all transaction data associated with a hash.
func DeleteCxLookupEntry(db DatabaseDeleter, hash common.Hash) {
db.Delete(cxLookupKey(hash))
}
// ReadCXReceipt retrieves a specific transaction from the database, along with
// its added positional metadata.
func ReadCXReceipt(db DatabaseReader, hash common.Hash) (*types.CXReceipt, common.Hash, uint64, uint64) {
blockHash, blockNumber, cxIndex := ReadCxLookupEntry(db, hash)
if blockHash == (common.Hash{}) {
return nil, common.Hash{}, 0, 0
}
body := ReadBody(db, blockHash, blockNumber)
if body == nil {
utils.Logger().Error().
Uint64("number", blockNumber).
Str("hash", blockHash.Hex()).
Uint64("index", cxIndex).
Msg("block Body referenced missing")
return nil, common.Hash{}, 0, 0
}
cx := body.CXReceiptAt(int(cxIndex))
if cx == nil {
utils.Logger().Error().
Uint64("number", blockNumber).
Str("hash", blockHash.Hex()).
Uint64("index", cxIndex).
Msg("CXReceipt referenced missing")
return nil, common.Hash{}, 0, 0
}
return cx, blockHash, blockNumber, cxIndex
}

@ -52,6 +52,7 @@ var (
blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts
txLookupPrefix = []byte("l") // txLookupPrefix + hash -> transaction/receipt lookup metadata
cxLookupPrefix = []byte("cx") // cxLookupPrefix + hash -> cxReceipt lookup metadata
bloomBitsPrefix = []byte("B") // bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits
shardStatePrefix = []byte("ss") // shardStatePrefix + num (uint64 big endian) + hash -> shardState
@ -137,6 +138,11 @@ func txLookupKey(hash common.Hash) []byte {
return append(txLookupPrefix, hash.Bytes()...)
}
// cxLookupKey = cxLookupPrefix + hash
func cxLookupKey(hash common.Hash) []byte {
return append(cxLookupPrefix, hash.Bytes()...)
}
// bloomBitsKey = bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash
func bloomBitsKey(bit uint, section uint64, hash common.Hash) []byte {
key := append(append(bloomBitsPrefix, make([]byte, 10)...), hash.Bytes()...)

@ -86,6 +86,10 @@ type BodyInterface interface {
// It returns nil if index is out of bounds.
TransactionAt(index int) *Transaction
// CXReceiptAt returns the CXReceipt given index (calculated from IncomingReceipts)
// It returns nil if index is out of bounds
CXReceiptAt(index int) *CXReceipt
// SetTransactions sets the list of transactions with a deep copy of the
// given list.
SetTransactions(newTransactions []*Transaction)

@ -39,6 +39,13 @@ func (b *BodyV0) TransactionAt(index int) *Transaction {
return b.f.Transactions[index].Copy()
}
// CXReceiptAt returns the CXReceipt at given index in this block
// It returns nil if index is out of bounds
// V0 will just return nil because we don't support CXReceipt
func (b *BodyV0) CXReceiptAt(index int) *CXReceipt {
return nil
}
// SetTransactions sets the list of transactions with a deep copy of the given
// list.
func (b *BodyV0) SetTransactions(newTransactions []*Transaction) {

@ -39,6 +39,22 @@ func (b *BodyV1) TransactionAt(index int) *Transaction {
return b.f.Transactions[index].Copy()
}
// CXReceiptAt returns the CXReceipt at given index in this block
// It returns nil if index is out of bounds
func (b *BodyV1) CXReceiptAt(index int) *CXReceipt {
if index < 0 {
return nil
}
for _, cxp := range b.f.IncomingReceipts {
cxs := cxp.Receipts
if index < len(cxs) {
return cxs[index].Copy()
}
index -= len(cxs)
}
return nil
}
// SetTransactions sets the list of transactions with a deep copy of the given
// list.
func (b *BodyV1) SetTransactions(newTransactions []*Transaction) {

@ -212,3 +212,11 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, err
}
return transactions, nil
}
// GetCXReceiptByHash returns the transaction for the given hash
func (s *PublicTransactionPoolAPI) GetCXReceiptByHash(ctx context.Context, hash common.Hash) *RPCCXReceipt {
if cx, blockHash, blockNumber, _ := rawdb.ReadCXReceipt(s.b.ChainDb(), hash); cx != nil {
return newRPCCXReceipt(cx, blockHash, blockNumber)
}
return nil
}

@ -22,11 +22,43 @@ type RPCTransaction struct {
To *common.Address `json:"to"`
TransactionIndex hexutil.Uint `json:"transactionIndex"`
Value *hexutil.Big `json:"value"`
ShardID uint32 `json:"shardID"`
ToShardID uint32 `json:"toShardID"`
V *hexutil.Big `json:"v"`
R *hexutil.Big `json:"r"`
S *hexutil.Big `json:"s"`
}
// RPCCXReceipt represents a CXReceipt that will serialize to the RPC representation of a CXReceipt
type RPCCXReceipt struct {
BlockHash common.Hash `json:"blockHash"`
BlockNumber *hexutil.Big `json:"blockNumber"`
TxHash common.Hash `json:"hash"`
From common.Address `json:"from"`
To *common.Address `json:"to"`
ShardID uint32 `json:"shardID"`
ToShardID uint32 `json:"toShardID"`
Amount *hexutil.Big `json:"value"`
}
// newRPCCXReceipt returns a CXReceipt that will serialize to the RPC representation
func newRPCCXReceipt(cx *types.CXReceipt, blockHash common.Hash, blockNumber uint64) *RPCCXReceipt {
result := &RPCCXReceipt{
BlockHash: blockHash,
TxHash: cx.TxHash,
From: cx.From,
To: cx.To,
Amount: (*hexutil.Big)(cx.Amount),
ShardID: cx.ShardID,
ToShardID: cx.ToShardID,
}
if blockHash != (common.Hash{}) {
result.BlockHash = blockHash
result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber))
}
return result
}
// newRPCTransaction returns a transaction that will serialize to the RPC
// representation, with the given location metadata set (if available).
func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64) *RPCTransaction {
@ -46,6 +78,8 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
Nonce: hexutil.Uint64(tx.Nonce()),
To: tx.To(),
Value: (*hexutil.Big)(tx.Value()),
ShardID: tx.ShardID(),
ToShardID: tx.ToShardID(),
V: (*hexutil.Big)(v),
R: (*hexutil.Big)(r),
S: (*hexutil.Big)(s),

Loading…
Cancel
Save