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

Improve event testing #240

Merged
merged 30 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
f487e82
remove uneeded
sideninja May 10, 2024
4850c98
add table tests for filter events
sideninja May 10, 2024
a769e53
add filter factory with checks
sideninja May 10, 2024
7233526
move errs and limits
sideninja May 10, 2024
d5300eb
add support for backfilling log events
sideninja May 10, 2024
4fb16be
remove the backfill and add check on filter from to on stream
sideninja May 10, 2024
5cc5e71
fix a bug in OR filter
sideninja May 10, 2024
a46e9d7
add todo
sideninja May 10, 2024
8ef5567
added more test combinations for filters
sideninja May 10, 2024
d17aea8
remove todos
sideninja May 10, 2024
984cf65
add todo
sideninja May 10, 2024
af1683e
match all no addresses
sideninja May 13, 2024
ea9f047
add special block values
sideninja May 13, 2024
d334d7d
handle get blocks with null values
sideninja May 13, 2024
575240f
add more custom tests
sideninja May 13, 2024
f508afb
improve filters with special values
sideninja May 13, 2024
9c842b1
use latest as special val
sideninja May 13, 2024
912269a
remove unneeded complexity
sideninja May 13, 2024
449f84a
add more tests
sideninja May 13, 2024
44ea942
match id again
sideninja May 13, 2024
bf68300
temp disable after test
sideninja May 13, 2024
6aa05bf
support multiple transactions in stream of pending txs
sideninja May 13, 2024
1df50b7
add test to fetch historic logs
sideninja May 14, 2024
441a3ce
clean up test
sideninja May 14, 2024
c71e144
clean up test
sideninja May 14, 2024
27b99d3
Merge branch 'main' into gregor/event-testing
sideninja May 14, 2024
8473656
update mocks
sideninja May 15, 2024
c80a52d
mod tidy
sideninja May 15, 2024
b18e802
Merge branch 'main' into gregor/event-testing
sideninja May 15, 2024
2a03886
Merge branch 'main' into gregor/event-testing
sideninja May 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
44 changes: 32 additions & 12 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
_ "embed"
"errors"
"fmt"
"math/big"

evmTypes "github.com/onflow/flow-go/fvm/evm/types"
"github.com/onflow/go-ethereum/common"
Expand Down Expand Up @@ -435,31 +436,50 @@ func (b *BlockChainAPI) GetLogs(
ctx context.Context,
criteria filters.FilterCriteria,
) ([]*types.Log, error) {

filter := logs.FilterCriteria{
Addresses: criteria.Addresses,
Topics: criteria.Topics,
}

// if filter provided specific block ID
if criteria.BlockHash != nil {
return logs.
NewIDFilter(*criteria.BlockHash, filter, b.blocks, b.receipts).
Match()
}
if criteria.FromBlock != nil && criteria.ToBlock != nil {
f, err := logs.
NewRangeFilter(*criteria.FromBlock, *criteria.ToBlock, filter, b.receipts)
if err != nil {
return nil, err
}

return f.Match()
// otherwise we use the block range as the filter

// assign default values to latest block number, unless provided
from := models.LatestBlockNumber
if criteria.FromBlock != nil {
from = criteria.FromBlock
}
to := models.LatestBlockNumber
if criteria.ToBlock != nil {
to = criteria.ToBlock
}

return nil, errors.Join(
errs.ErrInvalid,
fmt.Errorf("must provide either block ID or 'from' and 'to' block nubmers, to filter events"),
)
l, err := b.blocks.LatestEVMHeight()
if err != nil {
return nil, err
}
latest := big.NewInt(int64(l))

// if special value, use latest block number
if from.Cmp(models.EarliestBlockNumber) < 0 {
from = latest
}
if to.Cmp(models.EarliestBlockNumber) < 0 {
to = latest
}

f, err := logs.NewRangeFilter(*from, *to, filter, b.receipts)
if err != nil {
return nil, err
}

return f.Match()
}

// GetTransactionCount returns the number of transactions the given address
Expand Down
13 changes: 0 additions & 13 deletions api/models.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package api

import (
"errors"

errs "github.com/onflow/flow-evm-gateway/api/errors"
"github.com/onflow/flow-evm-gateway/models"

Expand All @@ -11,17 +9,6 @@ import (
"github.com/onflow/go-ethereum/core/types"
)

var (
errExceedMaxTopics = errors.New("exceed max topics")
errExceedMaxAddresses = errors.New("exceed max addresses")
)

// The maximum number of topic criteria allowed, vm.LOG4 - vm.LOG0
const maxTopics = 4

// The maximum number of addresses allowed
const maxAddresses = 6

// TransactionArgs represents the arguments to construct a new transaction
// or a message call.
type TransactionArgs struct {
Expand Down
94 changes: 53 additions & 41 deletions api/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@ import (
"fmt"
"reflect"

errs "github.com/onflow/flow-evm-gateway/api/errors"
"github.com/onflow/flow-evm-gateway/config"
"github.com/onflow/flow-evm-gateway/services/logs"
"github.com/onflow/flow-evm-gateway/storage"
storageErrs "github.com/onflow/flow-evm-gateway/storage/errors"
"github.com/onflow/flow-go/engine"
"github.com/onflow/flow-go/engine/access/subscription"
"github.com/onflow/go-ethereum/common"
"github.com/onflow/go-ethereum/common/hexutil"
"github.com/onflow/go-ethereum/eth/filters"
"github.com/onflow/go-ethereum/rpc"
"github.com/rs/zerolog"

errs "github.com/onflow/flow-evm-gateway/api/errors"
"github.com/onflow/flow-evm-gateway/config"
"github.com/onflow/flow-evm-gateway/services/logs"
"github.com/onflow/flow-evm-gateway/storage"
storageErrs "github.com/onflow/flow-evm-gateway/storage/errors"
)

// subscriptionBufferLimit is a constant that represents the buffer limit for subscriptions.
Expand Down Expand Up @@ -111,39 +113,47 @@ func (s *StreamAPI) NewPendingTransactions(ctx context.Context, fullTx *bool) (*
return nil, fmt.Errorf("failed to get block at height: %d: %w", height, err)
}

// todo once a block can contain multiple transactions this needs to be refactored
if len(block.TransactionHashes) != 1 {
return nil, fmt.Errorf("block contains more than a single transaction")
}
hash := block.TransactionHashes[0]
hashes := make([]common.Hash, len(block.TransactionHashes))
txs := make([]*Transaction, len(block.TransactionHashes))

tx, err := s.transactions.Get(hash)
if err != nil {
if errors.Is(err, storageErrs.ErrNotFound) {
// make sure to wrap in not found error as the streamer expects it
return nil, errors.Join(subscription.ErrBlockNotReady, err)
for i, hash := range block.TransactionHashes {

tx, err := s.transactions.Get(hash)
if err != nil {
if errors.Is(err, storageErrs.ErrNotFound) {
// make sure to wrap in not found error as the streamer expects it
return nil, errors.Join(subscription.ErrBlockNotReady, err)
}
return nil, fmt.Errorf("failed to get tx with hash: %s at height: %d: %w", hash, height, err)
}
return nil, fmt.Errorf("failed to get tx with hash: %s at height: %d: %w", hash, height, err)
}

rcp, err := s.receipts.GetByTransactionID(hash)
if err != nil {
if errors.Is(err, storageErrs.ErrNotFound) {
// make sure to wrap in not found error as the streamer expects it
return nil, errors.Join(subscription.ErrBlockNotReady, err)
rcp, err := s.receipts.GetByTransactionID(hash)
if err != nil {
if errors.Is(err, storageErrs.ErrNotFound) {
// make sure to wrap in not found error as the streamer expects it
return nil, errors.Join(subscription.ErrBlockNotReady, err)
}
return nil, fmt.Errorf("failed to get receipt with hash: %s at height: %d: %w", hash, height, err)
}
return nil, fmt.Errorf("failed to get receipt with hash: %s at height: %d: %w", hash, height, err)
}

h, err := tx.Hash()
if err != nil {
return nil, fmt.Errorf("failed to compute tx hash: %w", err)
h, err := tx.Hash()
if err != nil {
return nil, fmt.Errorf("failed to compute tx hash: %w", err)
}

t, err := NewTransaction(tx, *rcp)
if err != nil {
return nil, err
}

hashes[i] = h
txs[i] = t
}

if fullTx != nil && *fullTx {
return NewTransaction(tx, *rcp)
return txs, nil
}
return h, nil
return hashes, nil
},
)
l := s.logger.With().Str("subscription-id", string(sub.ID)).Logger()
Expand All @@ -158,17 +168,22 @@ func (s *StreamAPI) NewPendingTransactions(ctx context.Context, fullTx *bool) (*

// Logs creates a subscription that fires for all new log that match the given filter criteria.
func (s *StreamAPI) Logs(ctx context.Context, criteria filters.FilterCriteria) (*rpc.Subscription, error) {
if len(criteria.Topics) > maxTopics {
return nil, errExceedMaxTopics
}
if len(criteria.Addresses) > maxAddresses {
return nil, errExceedMaxAddresses
filter, err := logs.NewFilterCriteria(criteria.Addresses, criteria.Topics)
if err != nil {
return nil, fmt.Errorf("failed to crete log subscription filter: %w", err)
}

sub, err := s.newSubscription(
ctx,
s.logsBroadcaster,
func(ctx context.Context, height uint64) (interface{}, error) {
if criteria.ToBlock != nil && height > criteria.ToBlock.Uint64() {
return nil, nil
}
if criteria.FromBlock != nil && height < criteria.FromBlock.Uint64() {
return nil, nil
}

block, err := s.blocks.GetByHeight(height)
if err != nil {
if errors.Is(err, storageErrs.ErrNotFound) {
Expand All @@ -183,12 +198,9 @@ func (s *StreamAPI) Logs(ctx context.Context, criteria filters.FilterCriteria) (
return nil, err
}

// convert from the API type
f := logs.FilterCriteria{
Addresses: criteria.Addresses,
Topics: criteria.Topics,
}
return logs.NewIDFilter(id, f, s.blocks, s.receipts).Match()
// todo change this to height filter so we don't have to get the same block twice, once for height and then for id

return logs.NewIDFilter(id, *filter, s.blocks, s.receipts).Match()
},
)
l := s.logger.With().Str("subscription-id", string(sub.ID)).Logger()
Expand All @@ -198,6 +210,7 @@ func (s *StreamAPI) Logs(ctx context.Context, criteria filters.FilterCriteria) (
}

l.Info().Msg("new logs subscription created")

return sub, nil
}

Expand Down Expand Up @@ -273,7 +286,6 @@ func streamData(
}

case err := <-rpcSub.Err():
// todo maybe handle nil err, this is when client disconnects unexpectedly
l.Debug().Err(err).Msg("client unsubscribed")
return
case <-notifier.Closed():
Expand Down
6 changes: 6 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ require (
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chigopher/pathlib v0.12.0 // indirect
github.com/cockroachdb/errors v1.9.1 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/redact v1.1.3 // indirect
Expand Down Expand Up @@ -84,6 +85,7 @@ require (
github.com/ipfs/go-metrics-interface v0.0.1 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jbenet/goprocess v0.1.4 // indirect
github.com/jinzhu/copier v0.3.5 // indirect
github.com/k0kubun/pp v3.0.1+incompatible // indirect
github.com/kevinburke/go-bindata v3.24.0+incompatible // indirect
github.com/klauspost/compress v1.17.4 // indirect
Expand All @@ -99,6 +101,7 @@ require (
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
Expand Down Expand Up @@ -155,6 +158,7 @@ require (
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/turbolent/prettier v0.0.0-20220320183459-661cc755135d // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
github.com/vektra/mockery/v2 v2.21.4 // indirect
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
github.com/vmihailenco/msgpack/v4 v4.3.11 // indirect
github.com/vmihailenco/tagparser v0.1.1 // indirect
Expand All @@ -174,6 +178,7 @@ require (
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/term v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.17.0 // indirect
Expand All @@ -185,6 +190,7 @@ require (
google.golang.org/grpc v1.63.2 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.2.1 // indirect
rsc.io/tmplfunc v0.0.3 // indirect
Expand Down
9 changes: 9 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1078,6 +1078,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chigopher/pathlib v0.12.0 h1:1GM7fN/IwXXmOHbd1jkMqHD2wUhYqUvafgxTwmLT/q8=
github.com/chigopher/pathlib v0.12.0/go.mod h1:EJ5UtJ/sK8Nt6q3VWN+EwZLZ3g0afJiG8NegYiQQ/gQ=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
Expand Down Expand Up @@ -1627,6 +1629,8 @@ github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU=
github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E=
github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
Expand Down Expand Up @@ -1806,6 +1810,7 @@ github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dz
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
Expand Down Expand Up @@ -2051,6 +2056,7 @@ github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0b
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/afero v1.4.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY=
Expand Down Expand Up @@ -2137,6 +2143,8 @@ github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBn
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/vektra/mockery/v2 v2.21.4 h1:QInaL4ma4Bz/cVipKeBLggB5XyPenpksiz8sJpgBZSE=
github.com/vektra/mockery/v2 v2.21.4/go.mod h1:le9nnD50TkeV8QGwrkza7v/xd3DA7YbSZYBEyiuAlsI=
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/vmihailenco/msgpack/v4 v4.3.11 h1:Q47CePddpNGNhk4GCnAx9DDtASi2rasatE0cd26cZoE=
Expand Down Expand Up @@ -2624,6 +2632,7 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down
9 changes: 9 additions & 0 deletions models/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,21 @@ package models

import (
"fmt"
"math/big"

"github.com/onflow/cadence"
"github.com/onflow/flow-go/fvm/evm/types"
"github.com/onflow/go-ethereum/common"
)

var (
SafeBlockNumber = big.NewInt(-4)
FinalizedBlockNumber = big.NewInt(-3)
LatestBlockNumber = big.NewInt(-2)
PendingBlockNumber = big.NewInt(-1)
EarliestBlockNumber = big.NewInt(0)
)

// decodeBlock takes a cadence event that contains executed block payload and
// decodes it into the Block type.
func decodeBlock(event cadence.Event) (*types.Block, error) {
Expand Down