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

Support batched transactions #223

Merged
merged 29 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f5d8ac3
add helper with setup
devbugging Apr 30, 2024
5a767fe
add test for batch
devbugging Apr 30, 2024
1491478
Merge branch 'gregor/update-flow-go-latest' into gregor/batched-trans…
devbugging Apr 30, 2024
ca9197b
change interface to return list of receipts
devbugging Apr 30, 2024
0fc58f2
add comments
devbugging Apr 30, 2024
4b169c2
change events to return map of height to tx/receipt
devbugging Apr 30, 2024
399133a
add test for batched txs
devbugging Apr 30, 2024
e2db84a
Revert "change events to return map of height to tx/receipt"
devbugging Apr 30, 2024
3de63ad
change receipt to store list of receipts
devbugging Apr 30, 2024
5de73d7
add filters for multiple receipts
devbugging Apr 30, 2024
583a421
fix test
devbugging Apr 30, 2024
a84996a
update mocks
devbugging Apr 30, 2024
191d667
add test for multiple receipts
devbugging Apr 30, 2024
1910040
fix bugs
devbugging Apr 30, 2024
d416988
add test for receipts
devbugging Apr 30, 2024
20c7e2d
add logging index
devbugging Apr 30, 2024
1da46e3
fix test
devbugging Apr 30, 2024
faaf3ed
Merge branch 'main' into gregor/batched-transactions
devbugging Apr 30, 2024
a42429b
update flow-go
devbugging Apr 30, 2024
81cb1d4
update emulator
devbugging Apr 30, 2024
e0b6384
update test
devbugging Apr 30, 2024
6b66045
add one more test
devbugging Apr 30, 2024
5c8ffb5
add test for blooms multiple per block
devbugging Apr 30, 2024
e210e0f
index bloom list for height
devbugging Apr 30, 2024
c529aee
add tests for bloom heights
devbugging Apr 30, 2024
d6117a9
test fixes
devbugging Apr 30, 2024
4c391ca
update emulator
devbugging Apr 30, 2024
5a910a3
fix typo
devbugging Apr 30, 2024
08ddfaf
handle err
devbugging Apr 30, 2024
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
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/goccy/go-json v0.10.2
github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/onflow/cadence v1.0.0-preview.23
github.com/onflow/flow-go v0.34.0-crescendo-preview.16
github.com/onflow/flow-go v0.34.0-crescendo-preview.17
github.com/onflow/flow-go-sdk v1.0.0-preview.22
github.com/onflow/go-ethereum v1.13.4
github.com/rs/cors v1.8.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1942,8 +1942,8 @@ github.com/onflow/flow-ft/lib/go/contracts v0.7.1-0.20240424211859-3ff4c0fe2a1e
github.com/onflow/flow-ft/lib/go/contracts v0.7.1-0.20240424211859-3ff4c0fe2a1e/go.mod h1:PwsL8fC81cjnUnTfmyL/HOIyHnyaw/JA474Wfj2tl6A=
github.com/onflow/flow-ft/lib/go/templates v0.7.1-0.20240424211859-3ff4c0fe2a1e h1:jl7SYAui/gYRmBofrY//Ln8ixRJwvLzvwLstNfRKmWY=
github.com/onflow/flow-ft/lib/go/templates v0.7.1-0.20240424211859-3ff4c0fe2a1e/go.mod h1:uQ8XFqmMK2jxyBSVrmyuwdWjTEb+6zGjRYotfDJ5pAE=
github.com/onflow/flow-go v0.34.0-crescendo-preview.16 h1:GTOLB2FTG4En91WAd51ReNM5zGJ56KJY9k7AN/ZsCMw=
github.com/onflow/flow-go v0.34.0-crescendo-preview.16/go.mod h1:WbsDXtDBGRil+pQevdxTlP2r3a67/Aq5Y7+ab/P0aFw=
github.com/onflow/flow-go v0.34.0-crescendo-preview.17 h1:HnISCj+nZkfwDHmVF1VmbmyuVbOH76GNGKFTMbthD7c=
github.com/onflow/flow-go v0.34.0-crescendo-preview.17/go.mod h1:WbsDXtDBGRil+pQevdxTlP2r3a67/Aq5Y7+ab/P0aFw=
github.com/onflow/flow-go-sdk v1.0.0-M1/go.mod h1:TDW0MNuCs4SvqYRUzkbRnRmHQL1h4X8wURsCw9P9beo=
github.com/onflow/flow-go-sdk v1.0.0-preview.22 h1:ahHlppdDd4TjHMfnE73SD15AR16KTgbczdhFjGjAtFM=
github.com/onflow/flow-go-sdk v1.0.0-preview.22/go.mod h1:0hJfpIajLtBvaAUfJAdvWx6WBVp5hS0DJidc0NJLgE4=
Expand Down
1 change: 1 addition & 0 deletions services/ingestion/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ func (e *Engine) indexTransaction(tx models.Transaction, receipt *gethTypes.Rece
Str("contract-address", receipt.ContractAddress.String()).
Int("log-count", len(receipt.Logs)).
Uint64("evm-height", receipt.BlockNumber.Uint64()).
Uint("tx-index", receipt.TransactionIndex).
Str("receipt-tx-hash", receipt.TxHash.String()).
Str("tx-hash", txHash.String()).
Msg("ingesting new transaction executed event")
Expand Down
20 changes: 12 additions & 8 deletions services/logs/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,16 @@ func (r *RangeFilter) Match() ([]*gethTypes.Log, error) {
}

// todo do this concurrently
receipt, err := r.receipts.GetByBlockHeight(heights[i])
receipts, err := r.receipts.GetByBlockHeight(heights[i])
if err != nil {
return nil, err
}

for _, log := range receipt.Logs {
if exactMatch(log, r.criteria) {
logs = append(logs, log)
for _, receipt := range receipts {
for _, log := range receipt.Logs {
if exactMatch(log, r.criteria) {
logs = append(logs, log)
}
Comment on lines +68 to +77
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optimize log filtering with concurrent processing.

The current implementation of log filtering in the RangeFilter class processes receipts sequentially. Given that log filtering can be a CPU-intensive operation, especially with a large number of receipts, consider implementing concurrent processing of receipts to improve performance. This could involve using worker pools or parallel processing techniques to handle multiple receipts simultaneously.

}
}
}
Expand Down Expand Up @@ -109,15 +111,17 @@ func (i *IDFilter) Match() ([]*gethTypes.Log, error) {
return nil, err
}

receipt, err := i.receipts.GetByBlockHeight(big.NewInt(int64(blk.Height)))
receipts, err := i.receipts.GetByBlockHeight(big.NewInt(int64(blk.Height)))
if err != nil {
return nil, err
}

logs := make([]*gethTypes.Log, 0)
for _, log := range receipt.Logs {
if exactMatch(log, i.criteria) {
logs = append(logs, log)
for _, receipt := range receipts {
for _, log := range receipt.Logs {
if exactMatch(log, i.criteria) {
logs = append(logs, log)
}
}
}

Expand Down
12 changes: 9 additions & 3 deletions services/logs/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,19 @@ func receiptStorage() storage.ReceiptIndexer {
receiptStorage := &mocks.ReceiptIndexer{}
receiptStorage.
On("GetByBlockHeight", mock.AnythingOfType("*big.Int")).
Return(func(height *big.Int) (*gethTypes.Receipt, error) {
Return(func(height *big.Int) ([]*gethTypes.Receipt, error) {
rcps := make([]*gethTypes.Receipt, 0)
for _, r := range receipts {
if r.BlockNumber.Cmp(height) == 0 {
return r, nil
rcps = append(rcps, r)
}
}
return nil, errors.ErrNotFound

if len(rcps) == 0 {
return nil, errors.ErrNotFound
}

return rcps, nil
})

receiptStorage.
Expand Down
3 changes: 1 addition & 2 deletions storage/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,7 @@ type ReceiptIndexer interface {
// GetByBlockHeight returns the receipt for the block height.
// Expected errors:
// - errors.NotFound if the receipt is not found
// TODO right now one transaction per block, but this might change in future so the API needs to be updated.
GetByBlockHeight(height *big.Int) (*gethTypes.Receipt, error)
GetByBlockHeight(height *big.Int) ([]*gethTypes.Receipt, error)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure consistent error handling for the GetByBlockHeight method.

The GetByBlockHeight method in the ReceiptIndexer interface is expected to handle errors such as errors.NotFound when the receipt is not found. However, the method now returns a slice of receipts, which implies multiple receipts could be associated with a single block height. This change in functionality should be accompanied by an update in the documentation and error handling strategy to reflect the possibility of returning multiple receipts and handling their associated errors.


// BloomsForBlockRange returns slice of bloom values and a slice of block heights
// corresponding to each item in the bloom slice. It only matches the blooms between
Expand Down
61 changes: 55 additions & 6 deletions storage/index_testsuite.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,33 @@ type ReceiptTestSuite struct {
}

func (s *ReceiptTestSuite) TestStoreReceipt() {
receipt := mocks.NewReceipt(1, common.HexToHash("0xf1"))

s.Run("store receipt successfully", func() {
receipt := mocks.NewReceipt(1, common.HexToHash("0xf1"))
err := s.ReceiptIndexer.Store(receipt)
s.Require().NoError(err)
})

s.Run("store multiple receipts at same height", func() {
const height = 5
receipts := []*types.Receipt{
mocks.NewReceipt(height, common.HexToHash("0x1")),
mocks.NewReceipt(height, common.HexToHash("0x2")),
mocks.NewReceipt(height, common.HexToHash("0x3")),
}

for _, r := range receipts {
err := s.ReceiptIndexer.Store(r)
s.Require().NoError(err)
}

storeReceipts, err := s.ReceiptIndexer.GetByBlockHeight(big.NewInt(height))
s.Require().NoError(err)

for i, sr := range storeReceipts {
s.compareReceipts(receipts[i], sr)
}
})
}

func (s *ReceiptTestSuite) TestGetReceiptByTransactionID() {
Expand All @@ -155,15 +176,17 @@ func (s *ReceiptTestSuite) TestGetReceiptByTransactionID() {
})
}

func (s *ReceiptTestSuite) TestGetReceiptByBlockID() {
s.Run("existing block ID", func() {
func (s *ReceiptTestSuite) TestGetReceiptByBlockHeight() {
s.Run("existing block height", func() {
receipt := mocks.NewReceipt(3, common.HexToHash("0x1"))
err := s.ReceiptIndexer.Store(receipt)
s.Require().NoError(err)
// add one more receipt that shouldn't be retrieved
s.Require().NoError(s.ReceiptIndexer.Store(mocks.NewReceipt(4, common.HexToHash("0x2"))))

retReceipt, err := s.ReceiptIndexer.GetByBlockHeight(receipt.BlockNumber)
retReceipts, err := s.ReceiptIndexer.GetByBlockHeight(receipt.BlockNumber)
s.Require().NoError(err)
s.compareReceipts(receipt, retReceipt)
s.compareReceipts(receipt, retReceipts[0])
})

s.Run("non-existing block height", func() {
Expand Down Expand Up @@ -193,7 +216,33 @@ func (s *ReceiptTestSuite) TestBloomsForBlockRange() {
s.Require().Len(heights, len(testBlooms))
s.Require().Equal(testBlooms, blooms)

// todo smaller block range
blooms, heights, err = s.ReceiptIndexer.BloomsForBlockRange(start, big.NewInt(13))
s.Require().NoError(err)
s.Require().Len(blooms, 4)
s.Require().Len(heights, 4)
s.Require().Equal(testBlooms[0:4], blooms)
})

s.Run("valid block range with multiple receipts per block", func() {
start := big.NewInt(15)
end := big.NewInt(20)
testBlooms := make([]*types.Bloom, 0)
testHeights := make([]*big.Int, 0)

for i := start.Uint64(); i < end.Uint64(); i++ {
r1 := mocks.NewReceipt(i, common.HexToHash(fmt.Sprintf("0x%d", i)))
r2 := mocks.NewReceipt(i, common.HexToHash(fmt.Sprintf("0x%d", i)))
s.Require().NoError(s.ReceiptIndexer.Store(r1))
s.Require().NoError(s.ReceiptIndexer.Store(r2))
testBlooms = append(testBlooms, &r1.Bloom, &r2.Bloom)
testHeights = append(testHeights, big.NewInt(int64(i)))
}

blooms, heights, err := s.ReceiptIndexer.BloomsForBlockRange(start, end)
s.Require().NoError(err)
s.Require().Len(blooms, len(testBlooms))
s.Require().Len(heights, len(testHeights))
s.Require().Equal(testBlooms, blooms)
})

s.Run("invalid block range", func() {
Expand Down
10 changes: 5 additions & 5 deletions storage/mocks/ReceiptIndexer.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading