Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: update blockTxs to correctly parse finalizeblock events #123

Merged
merged 4 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ Ref: https://keepachangelog.com/en/1.0.0/

## [Unreleased]

### Bug Fixes

* [123](https://github.com/cosmos/rosetta/pull/123) Correctly parse cometBFT finalize block.

## [v0.50.6](https://github.com/cosmos/rosetta/releases/tag/v0.50.6) 2024-04-23

### Improvements
Expand Down
37 changes: 7 additions & 30 deletions client_online.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,20 +306,6 @@ func (c *Client) GetTx(ctx context.Context, hash string) (*rosettatypes.Transact
// construct rosetta tx
switch txType {
// handle begin block hash
case BeginBlockTx:
// get block height by hash
block, err := c.tmRPC.BlockByHash(ctx, hashBytes)
if err != nil {
return nil, crgerrs.WrapError(crgerrs.ErrOnlineClient, fmt.Sprintf("getting block by hash %s", err.Error()))
}

// get block txs
fullBlock, err := c.blockTxs(ctx, &block.Block.Height)
if err != nil {
return nil, crgerrs.WrapError(crgerrs.ErrOnlineClient, fmt.Sprintf("getting block tx %s", err.Error()))
}

return fullBlock.Transactions[0], nil
// handle deliver tx hash
case DeliverTxTx:
rawTx, err := c.tmRPC.Tx(ctx, hashBytes, true)
Expand All @@ -328,7 +314,7 @@ func (c *Client) GetTx(ctx context.Context, hash string) (*rosettatypes.Transact
}
return c.converter.ToRosetta().Tx(rawTx.Tx, &rawTx.TxResult)
// handle end block hash
case EndBlockTx:
case FinalizeBlockTx:
// get block height by hash
block, err := c.tmRPC.BlockByHash(ctx, hashBytes)
if err != nil {
Expand Down Expand Up @@ -365,8 +351,8 @@ func (c *Client) GetUnconfirmedTx(ctx context.Context, hash string) (*rosettatyp
switch len(hashAsBytes) {
default:
return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, fmt.Sprintf("unrecognized tx size: %d", len(hashAsBytes)))
case BeginEndBlockTxSize:
return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "endblock and begin block txs cannot be unconfirmed")
case FinalizeBlockTxSize:
return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "finalize block txs cannot be unconfirmed")
case DeliverTxSize:
break
}
Expand Down Expand Up @@ -510,16 +496,8 @@ func (c *Client) blockTxs(ctx context.Context, height *int64) (crgtypes.BlockTra
return crgtypes.BlockTransactionsResponse{}, crgerrs.WrapError(crgerrs.ErrOnlineClient, "block results transactions do now match block transactions")
}
// process begin and end block txs
beginBlockTx := &rosettatypes.Transaction{
TransactionIdentifier: &rosettatypes.TransactionIdentifier{Hash: c.converter.ToRosetta().BeginBlockTxHash(blockInfo.BlockID.Hash)},
Operations: AddOperationIndexes(
nil,
c.converter.ToRosetta().BalanceOps(StatusTxSuccess, blockResults.FinalizeBlockEvents),
),
}

endBlockTx := &rosettatypes.Transaction{
TransactionIdentifier: &rosettatypes.TransactionIdentifier{Hash: c.converter.ToRosetta().EndBlockTxHash(blockInfo.BlockID.Hash)},
finalizeBlockTx := &rosettatypes.Transaction{
TransactionIdentifier: &rosettatypes.TransactionIdentifier{Hash: c.converter.ToRosetta().FinalizeBlockTxHash(blockInfo.BlockID.Hash)},
Operations: AddOperationIndexes(
nil,
c.converter.ToRosetta().BalanceOps(StatusTxSuccess, blockResults.FinalizeBlockEvents),
Expand All @@ -536,10 +514,9 @@ func (c *Client) blockTxs(ctx context.Context, height *int64) (crgtypes.BlockTra
deliverTx[i] = rosTx
}

finalTxs := make([]*rosettatypes.Transaction, 0, 2+len(deliverTx))
finalTxs = append(finalTxs, beginBlockTx)
finalTxs := make([]*rosettatypes.Transaction, 0, 1+len(deliverTx))
finalTxs = append(finalTxs, deliverTx...)
finalTxs = append(finalTxs, endBlockTx)
finalTxs = append(finalTxs, finalizeBlockTx)

return crgtypes.BlockTransactionsResponse{
BlockResponse: c.converter.ToRosetta().BlockResponse(blockInfo),
Expand Down
32 changes: 10 additions & 22 deletions converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,7 @@ type ToRosettaConverter interface {
// BlockResponse returns a block response given a result block
BlockResponse(block *tmcoretypes.ResultBlock) crgtypes.BlockResponse
// BeginBlockToTx converts the given begin block hash to rosetta transaction hash
BeginBlockTxHash(blockHash []byte) string
// EndBlockTxHash converts the given endblock hash to rosetta transaction hash
EndBlockTxHash(blockHash []byte) string
FinalizeBlockTxHash(blockHash []byte) string
// Amounts converts sdk.Coins to rosetta.Amounts
Amounts(ownedCoins []sdk.Coin, availableCoins sdk.Coins) []*rosettatypes.Amount
// Ops converts an sdk.Msg to rosetta operations
Expand Down Expand Up @@ -474,35 +472,25 @@ func AddOperationIndexes(msgOps, balanceOps []*rosettatypes.Operation) (finalOps
return finalOps
}

// EndBlockTxHash produces a mock endblock hash that rosetta can query
// for endblock operations, it also serves the purpose of representing
// part of the state changes happening at endblock level (balance ones)
func (c converter) EndBlockTxHash(hash []byte) string {
final := append([]byte{EndBlockHashStart}, hash...)
return fmt.Sprintf("%X", final)
}

// BeginBlockTxHash produces a mock beginblock hash that rosetta can query
// for beginblock operations, it also serves the purpose of representing
// part of the state changes happening at beginblock level (balance ones)
func (c converter) BeginBlockTxHash(hash []byte) string {
final := append([]byte{BeginBlockHashStart}, hash...)
// FinalizeBlockTxHash produces a mock beginblock hash that rosetta can query
// for finalizeBlock operations, it also serves the purpose of representing
// part of the state changes happening at finalizeblock level (balance ones)
func (c converter) FinalizeBlockTxHash(hash []byte) string {
final := append([]byte{FinalizeBlockHashStart}, hash...)
return fmt.Sprintf("%X", final)
}

// HashToTxType takes the provided hash bytes from rosetta and discerns if they are
// a deliver tx type or endblock/begin block hash, returning the real hash afterwards
// a deliver tx type or finalize block hash, returning the real hash afterward
func (c converter) HashToTxType(hashBytes []byte) (txType TransactionType, realHash []byte) {
switch len(hashBytes) {
case DeliverTxSize:
return DeliverTxTx, hashBytes

case BeginEndBlockTxSize:
case FinalizeBlockTxSize:
switch hashBytes[0] {
case BeginBlockHashStart:
return BeginBlockTx, hashBytes[1:]
case EndBlockHashStart:
return EndBlockTx, hashBytes[1:]
case FinalizeBlockHashStart:
return FinalizeBlockHashStart, hashBytes[1:]
default:
return UnrecognizedTx, nil
}
Expand Down
20 changes: 5 additions & 15 deletions converter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,36 +179,26 @@ func (s *ConverterTestSuite) TestOpsAndSigners() {
})
}

func (s *ConverterTestSuite) TestBeginEndBlockAndHashToTxType() {
func (s *ConverterTestSuite) TestFinalizeBlockHashToTxType() {
const deliverTxHex = "5229A67AA008B5C5F1A0AEA77D4DEBE146297A30AAEF01777AF10FAD62DD36AB"

deliverTxBytes, err := hex.DecodeString(deliverTxHex)
s.Require().NoError(err)

endBlockTxHex := s.c.ToRosetta().EndBlockTxHash(deliverTxBytes)
beginBlockTxHex := s.c.ToRosetta().BeginBlockTxHash(deliverTxBytes)
finalizeBlockTxHex := s.c.ToRosetta().FinalizeBlockTxHash(deliverTxBytes)

txType, hash := s.c.ToSDK().HashToTxType(deliverTxBytes)

s.Require().Equal(rosetta.DeliverTxTx, txType)
s.Require().Equal(deliverTxBytes, hash, "deliver tx hash should not change")

endBlockTxBytes, err := hex.DecodeString(endBlockTxHex)
finalizeBlockTxBytes, err := hex.DecodeString(finalizeBlockTxHex)
s.Require().NoError(err)

txType, hash = s.c.ToSDK().HashToTxType(endBlockTxBytes)

s.Require().Equal(rosetta.EndBlockTx, txType)
txType, hash = s.c.ToSDK().HashToTxType(finalizeBlockTxBytes)
s.Require().Equal(rosetta.FinalizeBlockTx, txType)
s.Require().Equal(deliverTxBytes, hash, "end block tx hash should be equal to a block hash")

beginBlockTxBytes, err := hex.DecodeString(beginBlockTxHex)
s.Require().NoError(err)

txType, hash = s.c.ToSDK().HashToTxType(beginBlockTxBytes)

s.Require().Equal(rosetta.BeginBlockTx, txType)
s.Require().Equal(deliverTxBytes, hash, "begin block tx hash should be equal to a block hash")

txType, hash = s.c.ToSDK().HashToTxType([]byte("invalid"))

s.Require().Equal(rosetta.UnrecognizedTx, txType)
Expand Down
10 changes: 4 additions & 6 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ const (
// which are not represented as transactions we mock only the balance changes
// happening at those levels as transactions. (check BeginBlockTxHash for more info)
const (
DeliverTxSize = sha256.Size
BeginEndBlockTxSize = DeliverTxSize + 1
EndBlockHashStart = 0x0
BeginBlockHashStart = 0x1
DeliverTxSize = sha256.Size
FinalizeBlockTxSize = DeliverTxSize + 1
FinalizeBlockHashStart = 0x1
)

const (
Expand All @@ -37,8 +36,7 @@ type TransactionType int

const (
UnrecognizedTx TransactionType = iota
BeginBlockTx
EndBlockTx
FinalizeBlockTx
DeliverTxTx
)

Expand Down
Loading