Skip to content

Commit

Permalink
Merge pull request onflow#166 from m-Peter/get-block-with-full-tx
Browse files Browse the repository at this point in the history
Add support for returning full transactions when getting blocks
  • Loading branch information
m-Peter authored Mar 21, 2024
2 parents 56af2d8 + f7f6376 commit d213370
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 22 deletions.
48 changes: 40 additions & 8 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,13 +276,23 @@ func (b *BlockChainAPI) GetBlockByHash(
return nil, errs.ErrInternal
}

return &Block{
block := &Block{
Hash: h,
Number: hexutil.Uint64(bl.Height),
ParentHash: bl.ParentBlockHash,
ReceiptsRoot: bl.ReceiptRoot,
Transactions: bl.TransactionHashes,
}, nil
}

if fullTx {
transactions, err := b.fetchBlockTransactions(ctx, bl)
if err != nil {
return nil, err
}
block.Transactions = transactions
}

return block, nil
}

// GetBlockByNumber returns the requested canonical block.
Expand All @@ -297,10 +307,6 @@ func (b *BlockChainAPI) GetBlockByNumber(
blockNumber rpc.BlockNumber,
fullTx bool,
) (*Block, error) {
if fullTx { // todo support full tx
b.logger.Warn().Msg("not supported getting full txs")
}

height := uint64(blockNumber)
var err error
// todo for now we treat all special blocks as latest, think which special statuses we can even support on Flow
Expand All @@ -322,13 +328,23 @@ func (b *BlockChainAPI) GetBlockByNumber(
return nil, errs.ErrInternal
}

return &Block{
block := &Block{
Hash: h,
Number: hexutil.Uint64(bl.Height),
ParentHash: bl.ParentBlockHash,
ReceiptsRoot: bl.ReceiptRoot,
Transactions: bl.TransactionHashes,
}, nil
}

if fullTx {
transactions, err := b.fetchBlockTransactions(ctx, bl)
if err != nil {
return nil, err
}
block.Transactions = transactions
}

return block, nil
}

// GetBlockReceipts returns the block receipts for the given block hash or number or tag.
Expand Down Expand Up @@ -766,3 +782,19 @@ func (b *BlockChainAPI) FeeHistory(
func (b *BlockChainAPI) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, error) {
return nil, errs.ErrNotSupported
}

func (b *BlockChainAPI) fetchBlockTransactions(
ctx context.Context,
block *evmTypes.Block,
) ([]*RPCTransaction, error) {
transactions := make([]*RPCTransaction, 0)
for _, txHash := range block.TransactionHashes {
transaction, err := b.GetTransactionByHash(ctx, txHash)
if err != nil {
return nil, err
}
transactions = append(transactions, transaction)
}

return transactions, nil
}
2 changes: 1 addition & 1 deletion api/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,6 @@ type Block struct {
Number hexutil.Uint64 `json:"number"`
ParentHash common.Hash `json:"parentHash"`
ReceiptsRoot common.Hash `json:"receiptsRoot"`
Transactions []common.Hash `json:"transactions"`
Transactions interface{} `json:"transactions"`
// todo add more fields needed
}
44 changes: 34 additions & 10 deletions integration/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -543,14 +543,38 @@ func TestE2E_API_DeployEvents(t *testing.T) {
latestBlockNumber, err := rpcTester.blockNumber()
require.NoError(t, err)

blkRpc, err := rpcTester.getBlock(latestBlockNumber)
// check the eth_getBlockByNumber JSON-RPC endpoint,
// with `fullTx` option.
blkRpc, err := rpcTester.getBlock(latestBlockNumber, true)
require.NoError(t, err)

require.Len(t, blkRpc.Transactions, 1)
assert.Equal(t, uintHex(4), blkRpc.Number)

require.Len(t, blkRpc.FullTransactions(), 1)
fullTx := blkRpc.FullTransactions()[0]

assert.Equal(t, blkRpc.Hash, fullTx["blockHash"])
assert.Equal(t, blkRpc.Number, fullTx["blockNumber"])
assert.Nil(t, fullTx["to"])

// check the eth_getBlockByHash JSON-RPC endpoint,
// with `fullTx` option.
blkRpc, err = rpcTester.getBlockByHash(blkRpc.Hash, true)
require.NoError(t, err)

require.Len(t, blkRpc.Transactions, 1)
assert.Equal(t, uintHex(4), blkRpc.Number)

require.Len(t, blkRpc.FullTransactions(), 1)
fullTx = blkRpc.FullTransactions()[0]

assert.Equal(t, blkRpc.Hash, fullTx["blockHash"])
assert.Equal(t, blkRpc.Number, fullTx["blockNumber"])
assert.Nil(t, fullTx["to"])

// check the deployment transaction and receipt
deployHash := blkRpc.Transactions[0]
deployHash := blkRpc.TransactionHashes()[0]
require.Equal(t, hash.String(), deployHash)

txRpc, err := rpcTester.getTx(deployHash)
Expand Down Expand Up @@ -605,12 +629,12 @@ func TestE2E_API_DeployEvents(t *testing.T) {
latestBlockNumber, err = rpcTester.blockNumber()
require.NoError(t, err)

blkRpc, err = rpcTester.getBlock(latestBlockNumber)
blkRpc, err = rpcTester.getBlock(latestBlockNumber, false)
require.NoError(t, err)
assert.Equal(t, uintHex(5), blkRpc.Number)
require.Len(t, blkRpc.Transactions, 1)

interactHash := blkRpc.Transactions[0]
interactHash := blkRpc.TransactionHashes()[0]
assert.Equal(t, signedHash.String(), interactHash)

txRpc, err = rpcTester.getTx(interactHash)
Expand Down Expand Up @@ -659,12 +683,12 @@ func TestE2E_API_DeployEvents(t *testing.T) {
latestBlockNumber, err = rpcTester.blockNumber()
require.NoError(t, err)

blkRpc, err = rpcTester.getBlock(latestBlockNumber)
blkRpc, err = rpcTester.getBlock(latestBlockNumber, false)
require.NoError(t, err)
assert.Equal(t, uintHex(6), blkRpc.Number)
require.Len(t, blkRpc.Transactions, 1)

interactHash = blkRpc.Transactions[0]
interactHash = blkRpc.TransactionHashes()[0]
assert.Equal(t, signedHash.String(), interactHash)

txRpc, err = rpcTester.getTx(interactHash)
Expand Down Expand Up @@ -699,11 +723,11 @@ func TestE2E_API_DeployEvents(t *testing.T) {
time.Sleep(1 * time.Second)

// block is produced by above call to the sum that emits sdkEvent
blkRpc, err = rpcTester.getBlock(latestBlockNumber + 1 + uint64(i))
blkRpc, err = rpcTester.getBlock(latestBlockNumber+1+uint64(i), false)
require.NoError(t, err)
require.Len(t, blkRpc.Transactions, 1)

sumHash := blkRpc.Transactions[0]
sumHash := blkRpc.TransactionHashes()[0]
assert.Equal(t, signedHash.String(), sumHash)

_, err = rpcTester.getTx(sumHash)
Expand Down Expand Up @@ -732,7 +756,7 @@ func TestE2E_API_DeployEvents(t *testing.T) {

// successfully filter by block id with found single match for each block
for i := 0; i < 4; i++ {
blkRpc, err = rpcTester.getBlock(latestBlockNumber + 1 + uint64(i))
blkRpc, err = rpcTester.getBlock(latestBlockNumber+1+uint64(i), false)
require.NoError(t, err)

blkID := common.HexToHash(blkRpc.Hash)
Expand All @@ -757,7 +781,7 @@ func TestE2E_API_DeployEvents(t *testing.T) {
}

// invalid filter by block id with wrong topic value
blkRpc, err = rpcTester.getBlock(latestBlockNumber + 1)
blkRpc, err = rpcTester.getBlock(latestBlockNumber+1, false)
require.NoError(t, err)
blkID := common.HexToHash(blkRpc.Hash)
require.NoError(t, err)
Expand Down
58 changes: 55 additions & 3 deletions integration/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -453,8 +453,29 @@ func (r *rpcTest) getLogs(
return lg, nil
}

func (r *rpcTest) getBlock(height uint64) (*rpcBlock, error) {
rpcRes, err := r.request("eth_getBlockByNumber", fmt.Sprintf(`["%s",false]`, uintHex(height)))
func (r *rpcTest) getBlock(height uint64, fullTx bool) (*rpcBlock, error) {
rpcRes, err := r.request(
"eth_getBlockByNumber",
fmt.Sprintf(`["%s",%t]`, uintHex(height), fullTx),
)
if err != nil {
return nil, err
}

var blkRpc rpcBlock
err = json.Unmarshal(rpcRes, &blkRpc)
if err != nil {
return nil, err
}

return &blkRpc, nil
}

func (r *rpcTest) getBlockByHash(hash string, fullTx bool) (*rpcBlock, error) {
rpcRes, err := r.request(
"eth_getBlockByHash",
fmt.Sprintf(`["%s",%t]`, hash, fullTx),
)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -639,5 +660,36 @@ type rpcBlock struct {
Hash string
Number string
ParentHash string
Transactions []string
Transactions interface{}
}

func (b *rpcBlock) TransactionHashes() []string {
txHashes := make([]string, 0)
switch value := b.Transactions.(type) {
case []interface{}:
for _, val := range value {
switch element := val.(type) {
case string:
txHashes = append(txHashes, element)
case map[string]interface{}:
txHashes = append(txHashes, element["hash"].(string))
}
}
}
return txHashes
}

func (b *rpcBlock) FullTransactions() []map[string]interface{} {
transactions := make([]map[string]interface{}, 0)
switch value := b.Transactions.(type) {
case []interface{}:
for _, val := range value {
switch element := val.(type) {
case map[string]interface{}:
transactions = append(transactions, element)

}
}
}
return transactions
}

0 comments on commit d213370

Please sign in to comment.