Skip to content

Commit 0580149

Browse files
authored
[EVM] add stateless checks (#1188)
* Add basic checks * multiple fixes * fix race condition
1 parent b5362ae commit 0580149

16 files changed

+291
-61
lines changed

app/ante.go

+1
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ func NewAnteHandlerAndDepGenerator(options HandlerOptions) (sdk.AnteHandler, sdk
113113

114114
evmAnteDecorators := []sdk.AnteFullDecorator{
115115
evmante.NewEVMPreprocessDecorator(options.EVMKeeper, options.EVMKeeper.AccountKeeper()),
116+
sdk.DefaultWrappedAnteDecorator(evmante.NewBasicDecorator()),
116117
sdk.DefaultWrappedAnteDecorator(evmante.NewEVMFeeCheckDecorator(options.EVMKeeper)),
117118
sdk.DefaultWrappedAnteDecorator(evmante.NewEVMSigVerifyDecorator(options.EVMKeeper, options.LatestCtxGetter)),
118119
sdk.DefaultWrappedAnteDecorator(evmante.NewGasLimitDecorator(options.EVMKeeper)),

evmrpc/block.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func (a *BlockAPI) GetBlockTransactionCountByNumber(ctx context.Context, number
3434
if err != nil {
3535
return nil
3636
}
37-
block, err := a.tmClient.Block(ctx, numberPtr)
37+
block, err := blockWithRetry(ctx, a.tmClient, numberPtr)
3838
if err != nil {
3939
return nil
4040
}
@@ -43,7 +43,7 @@ func (a *BlockAPI) GetBlockTransactionCountByNumber(ctx context.Context, number
4343
}
4444

4545
func (a *BlockAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint {
46-
block, err := a.tmClient.BlockByHash(ctx, blockHash[:])
46+
block, err := blockByHashWithRetry(ctx, a.tmClient, blockHash[:])
4747
if err != nil {
4848
return nil
4949
}
@@ -52,11 +52,11 @@ func (a *BlockAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash
5252
}
5353

5454
func (a *BlockAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (map[string]interface{}, error) {
55-
block, err := a.tmClient.BlockByHash(ctx, blockHash[:])
55+
block, err := blockByHashWithRetry(ctx, a.tmClient, blockHash[:])
5656
if err != nil {
5757
return nil, err
5858
}
59-
blockRes, err := a.tmClient.BlockResults(ctx, &block.Block.Height)
59+
blockRes, err := blockResultsWithRetry(ctx, a.tmClient, &block.Block.Height)
6060
if err != nil {
6161
return nil, err
6262
}
@@ -68,11 +68,11 @@ func (a *BlockAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber,
6868
if err != nil {
6969
return nil, err
7070
}
71-
block, err := a.tmClient.Block(ctx, numberPtr)
71+
block, err := blockWithRetry(ctx, a.tmClient, numberPtr)
7272
if err != nil {
7373
return nil, err
7474
}
75-
blockRes, err := a.tmClient.BlockResults(ctx, &block.Block.Height)
75+
blockRes, err := blockResultsWithRetry(ctx, a.tmClient, &block.Block.Height)
7676
if err != nil {
7777
return nil, err
7878
}

evmrpc/filter.go

+2-8
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ func (a *FilterAPI) GetFilterChanges(
133133
filterID uint64,
134134
) (interface{}, error) {
135135
a.filtersMu.Lock()
136+
defer a.filtersMu.Unlock()
136137
filter, ok := a.filters[filterID]
137-
a.filtersMu.Unlock()
138138
if !ok {
139139
return nil, errors.New("filter does not exist")
140140
}
@@ -152,22 +152,18 @@ func (a *FilterAPI) GetFilterChanges(
152152
if err != nil {
153153
return nil, err
154154
}
155-
a.filtersMu.Lock()
156155
updatedFilter := a.filters[filterID]
157156
updatedFilter.blockCursor = cursor
158157
a.filters[filterID] = updatedFilter
159-
a.filtersMu.Unlock()
160158
return hashes, nil
161159
case LogsSubscription:
162160
res, cursors, err := a.getLogsOverAddresses(ctx, filter.fc, filter.logsCursors)
163161
if err != nil {
164162
return nil, err
165163
}
166-
a.filtersMu.Lock()
167164
updatedFilter := a.filters[filterID]
168165
updatedFilter.logsCursors = cursors
169166
a.filters[filterID] = updatedFilter
170-
a.filtersMu.Unlock()
171167
return res, nil
172168
default:
173169
return nil, errors.New("unknown filter type")
@@ -179,8 +175,8 @@ func (a *FilterAPI) GetFilterLogs(
179175
filterID uint64,
180176
) ([]*ethtypes.Log, error) {
181177
a.filtersMu.Lock()
178+
defer a.filtersMu.Unlock()
182179
filter, ok := a.filters[filterID]
183-
a.filtersMu.Unlock()
184180
if !ok {
185181
return nil, errors.New("filter does not exist")
186182
}
@@ -197,11 +193,9 @@ func (a *FilterAPI) GetFilterLogs(
197193
if err != nil {
198194
return nil, err
199195
}
200-
a.filtersMu.Lock()
201196
updatedFilter := a.filters[filterID]
202197
updatedFilter.logsCursors = cursors
203198
a.filters[filterID] = updatedFilter
204-
a.filtersMu.Unlock()
205199
return res, nil
206200
}
207201

evmrpc/query_builder.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,17 @@ func GetTopicsRegex(topics [][]string) (string, error) {
7676

7777
topicRegex := func(topic []string) string {
7878
if len(topic) == 0 {
79-
return ""
79+
return "([^,]+)"
80+
}
81+
for _, t := range topic {
82+
if len(t) == 0 {
83+
return "([^,]+)"
84+
}
8085
}
8186
return fmt.Sprintf("(%s)", strings.Join(topic, "|"))
8287
}
8388

84-
return fmt.Sprintf("\\[%s.*\\]", strings.Join(utils.Map(topics, topicRegex), "[^\\,]*,")), nil
89+
return fmt.Sprintf("^%s.*", strings.Join(utils.Map(topics, topicRegex), ",")), nil
8590
}
8691

8792
func (q *QueryBuilder) FilterBlockNumber(blockNumber int64) *QueryBuilder {

evmrpc/query_builder_test.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -44,29 +44,29 @@ func TestGetTopicsRegex(t *testing.T) {
4444
name: "match first topic",
4545
topics: [][]string{{"a"}},
4646
wantErr: false,
47-
wantMatch: []string{"[a]", "[a,b]", "[a,a,a,a]"},
48-
wantNotMatch: []string{"b", "[b]", "[b,a]", "[a,b"},
47+
wantMatch: []string{"a", "a,b", "a,a,a,a"},
48+
wantNotMatch: []string{"b", "b", "b,a"},
4949
},
5050
{
5151
name: "match first topic with OR",
5252
topics: [][]string{{"a", "b"}}, // first topic can be a or b
5353
wantErr: false,
54-
wantMatch: []string{"[a]", "[a,b]", "[a,c,c,c]", "[b]", "[b,c]", "[b,c,c,c]"},
55-
wantNotMatch: []string{"b", "[c]", "[c,a]", "[c,b"},
54+
wantMatch: []string{"a", "a,b", "a,c,c,c", "b", "b,c", "b,c,c,c"},
55+
wantNotMatch: []string{"c", "c,a", "c,b"},
5656
},
5757
{
5858
name: "match second topic",
5959
topics: [][]string{{}, {"a"}},
6060
wantErr: false,
61-
wantMatch: []string{"[b,a]", "[c,a]", "[a,a,a]"},
62-
wantNotMatch: []string{"b,a]", "[a,b,a]"},
61+
wantMatch: []string{"b,a", "c,a", "a,a,a"},
62+
wantNotMatch: []string{"a,b,a"},
6363
},
6464
{
6565
name: "match second and fourth topic",
6666
topics: [][]string{{""}, {"a", "c"}, {""}, {"b", "d"}},
6767
wantErr: false,
68-
wantMatch: []string{"[d,a,c,b]", "[c,a,c,d,c]", "[a,c,b,d]"},
69-
wantNotMatch: []string{"[a,a,a,a]", "[a,b]", "[c,a,b,c]"},
68+
wantMatch: []string{"d,a,c,b", "c,a,c,d,c", "a,c,b,d"},
69+
wantNotMatch: []string{"a,a,a,a", "a,b", "c,a,b,c"},
7070
},
7171
}
7272

evmrpc/setup_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ func (c *MockClient) Subscribe(ctx context.Context, subscriber string, query str
246246
}()
247247
return resCh, nil
248248
// hardcoded test case for simplicity
249-
} else if strings.Contains(query, "tm.event = 'Tx' AND evm_log.contract_address = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' AND evm_log.topics MATCHES '\\[(0x0000000000000000000000000000000000000000000000000000000000000123).*\\]'") {
249+
} else if strings.Contains(query, "tm.event = 'Tx' AND evm_log.contract_address = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' AND evm_log.topics MATCHES '^(0x0000000000000000000000000000000000000000000000000000000000000123).*'") {
250250
resCh := make(chan coretypes.ResultEvent, 5)
251251
go func() {
252252
for i := uint64(0); i < 5; i++ {
@@ -265,7 +265,7 @@ func (c *MockClient) Subscribe(ctx context.Context, subscriber string, query str
265265
}
266266
}()
267267
return resCh, nil
268-
} else if strings.Contains(query, "tm.event = 'Tx' AND evm_log.contract_address = '0xc0ffee254729296a45a3885639AC7E10F9d54979' AND evm_log.topics MATCHES '\\[(0x0000000000000000000000000000000000000000000000000000000000000123).*\\]'") {
268+
} else if strings.Contains(query, "tm.event = 'Tx' AND evm_log.contract_address = '0xc0ffee254729296a45a3885639AC7E10F9d54979' AND evm_log.topics MATCHES '^(0x0000000000000000000000000000000000000000000000000000000000000123).*'") {
269269
resCh := make(chan coretypes.ResultEvent, 5)
270270
go func() {
271271
for i := uint64(0); i < 5; i++ {

evmrpc/tx.go

+5-12
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"sort"
99
"strconv"
1010
"strings"
11-
"time"
1211

1312
"github.com/cosmos/cosmos-sdk/client"
1413
sdk "github.com/cosmos/cosmos-sdk/types"
@@ -58,17 +57,11 @@ func (t *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common.
5857
// critical path, whereas this query endpoint is not on the chain critical path, so we are making the tradeoff to
5958
// sacrifice perf here.)
6059
height := int64(receipt.BlockNumber)
61-
blockRes, err := t.tmClient.BlockResults(ctx, &height)
60+
blockRes, err := blockResultsWithRetry(ctx, t.tmClient, &height)
6261
if err != nil {
63-
// retry once, since application DB and block DB are not committed atomically so it's possible for
64-
// receipt to exist while block results aren't committed yet
65-
time.Sleep(1 * time.Second)
66-
blockRes, err = t.tmClient.BlockResults(ctx, &height)
67-
if err != nil {
68-
return nil, err
69-
}
62+
return nil, err
7063
}
71-
block, err := t.tmClient.Block(ctx, &height)
64+
block, err := blockWithRetry(ctx, t.tmClient, &height)
7265
if err != nil {
7366
return nil, err
7467
}
@@ -88,15 +81,15 @@ func (t *TransactionAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context
8881
if err != nil {
8982
return nil
9083
}
91-
block, err := t.tmClient.Block(ctx, blockNumber)
84+
block, err := blockWithRetry(ctx, t.tmClient, blockNumber)
9285
if err != nil {
9386
return nil
9487
}
9588
return t.getTransactionWithBlock(block, index)
9689
}
9790

9891
func (t *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction {
99-
block, err := t.tmClient.BlockByHash(ctx, blockHash[:])
92+
block, err := blockByHashWithRetry(ctx, t.tmClient, blockHash[:])
10093
if err != nil {
10194
return nil
10295
}

evmrpc/utils.go

+45
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"crypto/ecdsa"
66
"encoding/hex"
77
"math/big"
8+
"time"
89

910
"github.com/cosmos/cosmos-sdk/client"
1011
"github.com/cosmos/cosmos-sdk/client/config"
@@ -21,7 +22,9 @@ import (
2122
"github.com/sei-protocol/sei-chain/x/evm/keeper"
2223
"github.com/sei-protocol/sei-chain/x/evm/state"
2324
"github.com/sei-protocol/sei-chain/x/evm/types"
25+
"github.com/tendermint/tendermint/libs/bytes"
2426
rpcclient "github.com/tendermint/tendermint/rpc/client"
27+
"github.com/tendermint/tendermint/rpc/coretypes"
2528
)
2629

2730
const LatestCtxHeight int64 = -1
@@ -186,3 +189,45 @@ func getAddressPrivKeyMap(kb keyring.Keyring) map[string]*ecdsa.PrivateKey {
186189
}
187190
return res
188191
}
192+
193+
func blockResultsWithRetry(ctx context.Context, client rpcclient.Client, height *int64) (*coretypes.ResultBlockResults, error) {
194+
blockRes, err := client.BlockResults(ctx, height)
195+
if err != nil {
196+
// retry once, since application DB and block DB are not committed atomically so it's possible for
197+
// receipt to exist while block results aren't committed yet
198+
time.Sleep(1 * time.Second)
199+
blockRes, err = client.BlockResults(ctx, height)
200+
if err != nil {
201+
return nil, err
202+
}
203+
}
204+
return blockRes, err
205+
}
206+
207+
func blockWithRetry(ctx context.Context, client rpcclient.Client, height *int64) (*coretypes.ResultBlock, error) {
208+
blockRes, err := client.Block(ctx, height)
209+
if err != nil {
210+
// retry once, since application DB and block DB are not committed atomically so it's possible for
211+
// receipt to exist while block results aren't committed yet
212+
time.Sleep(1 * time.Second)
213+
blockRes, err = client.Block(ctx, height)
214+
if err != nil {
215+
return nil, err
216+
}
217+
}
218+
return blockRes, err
219+
}
220+
221+
func blockByHashWithRetry(ctx context.Context, client rpcclient.Client, hash bytes.HexBytes) (*coretypes.ResultBlock, error) {
222+
blockRes, err := client.BlockByHash(ctx, hash)
223+
if err != nil {
224+
// retry once, since application DB and block DB are not committed atomically so it's possible for
225+
// receipt to exist while block results aren't committed yet
226+
time.Sleep(1 * time.Second)
227+
blockRes, err = client.BlockByHash(ctx, hash)
228+
if err != nil {
229+
return nil, err
230+
}
231+
}
232+
return blockRes, err
233+
}

0 commit comments

Comments
 (0)